From 718e3744195351130f4ce7dbe0613f4b3e23df93 Mon Sep 17 00:00:00 2001 From: paul Date: Fri, 13 Dec 2002 20:15:29 +0000 Subject: Initial revision --- .cvsignore | 10 + AUTHORS | 6 + COPYING | 339 + COPYING.LIB | 482 ++ ChangeLog | 674 ++ INSTALL | 181 + Makefile.am | 16 + Makefile.in | 548 ++ NEWS | 2338 +++++++ README | 12 + REPORTING-BUGS | 28 + SERVICES | 17 + TODO | 29 + acconfig.h | 161 + aclocal.m4 | 811 +++ bgpd/.cvsignore | 8 + bgpd/BGP4-MIB.txt | 929 +++ bgpd/ChangeLog | 2368 +++++++ bgpd/Makefile.am | 44 + bgpd/Makefile.in | 534 ++ bgpd/bgp_advertise.c | 405 ++ bgpd/bgp_advertise.h | 178 + bgpd/bgp_aspath.c | 1186 ++++ bgpd/bgp_aspath.h | 77 + bgpd/bgp_attr.c | 1838 +++++ bgpd/bgp_attr.h | 125 + bgpd/bgp_btoa.c | 291 + bgpd/bgp_clist.c | 905 +++ bgpd/bgp_clist.h | 143 + bgpd/bgp_community.c | 629 ++ bgpd/bgp_community.h | 68 + bgpd/bgp_damp.c | 648 ++ bgpd/bgp_damp.h | 141 + bgpd/bgp_debug.c | 732 ++ bgpd/bgp_debug.h | 113 + bgpd/bgp_dump.c | 741 ++ bgpd/bgp_dump.h | 34 + bgpd/bgp_ecommunity.c | 641 ++ bgpd/bgp_ecommunity.h | 72 + bgpd/bgp_filter.c | 658 ++ bgpd/bgp_filter.h | 31 + bgpd/bgp_fsm.c | 864 +++ bgpd/bgp_fsm.h | 42 + bgpd/bgp_main.c | 285 + bgpd/bgp_mplsvpn.c | 741 ++ bgpd/bgp_mplsvpn.h | 45 + bgpd/bgp_network.c | 381 ++ bgpd/bgp_network.h | 23 + bgpd/bgp_nexthop.c | 1405 ++++ bgpd/bgp_nexthop.h | 52 + bgpd/bgp_open.c | 793 +++ bgpd/bgp_open.h | 69 + bgpd/bgp_packet.c | 2240 ++++++ bgpd/bgp_packet.h | 49 + bgpd/bgp_regex.c | 93 + bgpd/bgp_regex.h | 31 + bgpd/bgp_route.c | 9053 +++++++++++++++++++++++++ bgpd/bgp_route.h | 159 + bgpd/bgp_routemap.c | 3207 +++++++++ bgpd/bgp_snmp.c | 875 +++ bgpd/bgp_snmp.h | 23 + bgpd/bgp_table.c | 489 ++ bgpd/bgp_table.h | 65 + bgpd/bgp_view.c | 258 + bgpd/bgp_vty.c | 9416 +++++++++++++++++++++++++ bgpd/bgp_vty.h | 21 + bgpd/bgp_zebra.c | 1001 +++ bgpd/bgp_zebra.h | 39 + bgpd/bgpd.c | 4601 +++++++++++++ bgpd/bgpd.conf.sample | 29 + bgpd/bgpd.conf.sample2 | 77 + bgpd/bgpd.h | 824 +++ config.guess | 1321 ++++ config.h.in | 367 + config.sub | 1332 ++++ configure | 8114 ++++++++++++++++++++++ configure.in | 873 +++ depcomp | 423 ++ doc/.cvsignore | 3 + doc/BGP-TypeCode | 24 + doc/ChangeLog | 90 + doc/Makefile.am | 14 + doc/Makefile.in | 482 ++ doc/appendix.texi | 238 + doc/basic.texi | 510 ++ doc/bgpd.8 | 169 + doc/bgpd.texi | 1288 ++++ doc/draft-zebra-00.ms | 209 + doc/filter.texi | 192 + doc/install.texi | 218 + doc/ipv6.texi | 32 + doc/kernel.texi | 48 + doc/main.texi | 186 + doc/ospf6d.8 | 127 + doc/ospf6d.texi | 102 + doc/ospfd.8 | 131 + doc/ospfd.texi | 345 + doc/overview.texi | 352 + doc/protocol.texi | 52 + doc/ripd.8 | 212 + doc/ripd.texi | 584 ++ doc/ripngd.8 | 143 + doc/ripngd.texi | 85 + doc/routemap.texi | 91 + doc/snmp.texi | 68 + doc/texinfo.tex | 5625 +++++++++++++++ doc/vtysh.1 | 68 + doc/vtysh.texi | 27 + doc/zebra.8 | 146 + doc/zebra.info | 170 + doc/zebra.texi | 150 + guile/.cvsignore | 3 + guile/ChangeLog | 26 + guile/Makefile.am | 9 + guile/Makefile.in | 299 + guile/README | 17 + guile/guile-bgp.c | 117 + guile/zebra-guile.c | 71 + guile/zebra-guile.h | 21 + guile/zebra-support.c | 19 + init/.cvsignore | 2 + init/ChangeLog | 39 + init/redhat/bgpd.init | 45 + init/redhat/ospf6d.init | 45 + init/redhat/ospfd.init | 45 + init/redhat/ripd.init | 45 + init/redhat/ripngd.init | 45 + init/redhat/zebra.init | 45 + init/redhat/zebra.logrotate | 47 + init/redhat/zebra.spec.in | 128 + install-sh | 251 + lib/.cvsignore | 4 + lib/ChangeLog | 1926 ++++++ lib/Makefile.am | 29 + lib/Makefile.in | 469 ++ lib/buffer.c | 568 ++ lib/buffer.h | 77 + lib/checksum.c | 47 + lib/command.c | 2981 ++++++++ lib/command.h | 308 + lib/daemon.c | 80 + lib/distribute.c | 709 ++ lib/distribute.h | 57 + lib/filter.c | 2058 ++++++ lib/filter.h | 67 + lib/getopt.c | 1054 +++ lib/getopt.h | 133 + lib/getopt1.c | 190 + lib/hash.c | 182 + lib/hash.h | 71 + lib/if.c | 713 ++ lib/if.h | 222 + lib/if_rmap.c | 305 + lib/if_rmap.h | 47 + lib/keychain.c | 1001 +++ lib/keychain.h | 56 + lib/linklist.c | 312 + lib/linklist.h | 101 + lib/log.c | 483 ++ lib/log.h | 128 + lib/md5-gnu.h | 156 + lib/md5.c | 447 ++ lib/memory.c | 493 ++ lib/memory.h | 245 + lib/network.c | 71 + lib/network.h | 29 + lib/pid_output.c | 77 + lib/plist.c | 2881 ++++++++ lib/plist.h | 78 + lib/prefix.c | 696 ++ lib/prefix.h | 161 + lib/print_version.c | 31 + lib/regex-gnu.h | 542 ++ lib/regex.c | 5891 ++++++++++++++++ lib/routemap.c | 1077 +++ lib/routemap.h | 194 + lib/smux.c | 1501 ++++ lib/smux.h | 159 + lib/sockopt.c | 199 + lib/sockopt.h | 41 + lib/sockunion.c | 756 +++ lib/sockunion.h | 128 + lib/str.c | 62 + lib/str.h | 24 + lib/stream.c | 479 ++ lib/stream.h | 113 + lib/table.c | 503 ++ lib/table.h | 74 + lib/tcpfilter.c | 69 + lib/tcpfilter.h | 21 + lib/thread.c | 668 ++ lib/thread.h | 139 + lib/vector.c | 189 + lib/vector.h | 58 + lib/version.h | 39 + lib/vty.c | 2792 ++++++++ lib/vty.h | 205 + lib/zclient.c | 901 +++ lib/zclient.h | 164 + lib/zebra.h | 312 + missing | 336 + mkinstalldirs | 101 + ospf6d/.cvsignore | 8 + ospf6d/ChangeLog | 809 +++ ospf6d/Makefile.am | 48 + ospf6d/Makefile.in | 549 ++ ospf6d/README | 85 + ospf6d/ospf6_abr.c | 655 ++ ospf6d/ospf6_abr.h | 56 + ospf6d/ospf6_area.c | 332 + ospf6d/ospf6_area.h | 90 + ospf6d/ospf6_asbr.c | 1040 +++ ospf6d/ospf6_asbr.h | 112 + ospf6d/ospf6_bintree.c | 436 ++ ospf6d/ospf6_bintree.h | 47 + ospf6d/ospf6_damp.c | 748 ++ ospf6d/ospf6_damp.h | 109 + ospf6d/ospf6_dbex.c | 704 ++ ospf6d/ospf6_dbex.h | 59 + ospf6d/ospf6_dump.c | 314 + ospf6d/ospf6_dump.h | 95 + ospf6d/ospf6_hook.c | 174 + ospf6d/ospf6_hook.h | 87 + ospf6d/ospf6_interface.c | 1028 +++ ospf6d/ospf6_interface.h | 153 + ospf6d/ospf6_intra.c | 896 +++ ospf6d/ospf6_intra.h | 31 + ospf6d/ospf6_ism.c | 519 ++ ospf6d/ospf6_ism.h | 53 + ospf6d/ospf6_linklist.c | 193 + ospf6d/ospf6_linklist.h | 35 + ospf6d/ospf6_lsa.c | 1926 ++++++ ospf6d/ospf6_lsa.h | 426 ++ ospf6d/ospf6_lsdb.c | 723 ++ ospf6d/ospf6_lsdb.h | 88 + ospf6d/ospf6_main.c | 326 + ospf6d/ospf6_message.c | 1972 ++++++ ospf6d/ospf6_message.h | 202 + ospf6d/ospf6_neighbor.c | 602 ++ ospf6d/ospf6_neighbor.h | 161 + ospf6d/ospf6_network.c | 501 ++ ospf6d/ospf6_network.h | 58 + ospf6d/ospf6_nsm.c | 391 ++ ospf6d/ospf6_nsm.h | 67 + ospf6d/ospf6_prefix.c | 213 + ospf6d/ospf6_prefix.h | 83 + ospf6d/ospf6_proto.c | 40 + ospf6d/ospf6_proto.h | 75 + ospf6d/ospf6_route.c | 1130 +++ ospf6d/ospf6_route.h | 209 + ospf6d/ospf6_routemap.c | 359 + ospf6d/ospf6_routemap.h | 27 + ospf6d/ospf6_spf.c | 1454 ++++ ospf6d/ospf6_spf.h | 105 + ospf6d/ospf6_top.c | 401 ++ ospf6d/ospf6_top.h | 96 + ospf6d/ospf6_types.h | 43 + ospf6d/ospf6_zebra.c | 727 ++ ospf6d/ospf6_zebra.h | 46 + ospf6d/ospf6d.c | 826 +++ ospf6d/ospf6d.conf.sample | 54 + ospf6d/ospf6d.h | 175 + ospfd/.cvsignore | 7 + ospfd/ChangeLog | 2970 ++++++++ ospfd/Makefile.am | 44 + ospfd/Makefile.in | 532 ++ ospfd/OSPF-MIB.txt | 2723 ++++++++ ospfd/OSPF-TRAP-MIB.txt | 443 ++ ospfd/ospf_abr.c | 1741 +++++ ospfd/ospf_abr.h | 84 + ospfd/ospf_asbr.c | 287 + ospfd/ospf_asbr.h | 75 + ospfd/ospf_ase.c | 838 +++ ospfd/ospf_ase.h | 42 + ospfd/ospf_dump.c | 1673 +++++ ospfd/ospf_dump.h | 139 + ospfd/ospf_flood.c | 1048 +++ ospfd/ospf_flood.h | 65 + ospfd/ospf_ia.c | 726 ++ ospfd/ospf_ia.h | 42 + ospfd/ospf_interface.c | 1045 +++ ospfd/ospf_interface.h | 245 + ospfd/ospf_ism.h | 88 + ospfd/ospf_lsa.c | 3315 +++++++++ ospfd/ospf_lsa.h | 326 + ospfd/ospf_lsdb.c | 299 + ospfd/ospf_lsdb.h | 83 + ospfd/ospf_main.c | 293 + ospfd/ospf_neighbor.h | 106 + ospfd/ospf_network.c | 192 + ospfd/ospf_network.h | 34 + ospfd/ospf_nsm.h | 91 + ospfd/ospf_opaque.c | 2392 +++++++ ospfd/ospf_opaque.h | 155 + ospfd/ospf_packet.c | 3243 +++++++++ ospfd/ospf_packet.h | 171 + ospfd/ospf_route.c | 1026 +++ ospfd/ospf_route.h | 165 + ospfd/ospf_routemap.c | 828 +++ ospfd/ospf_snmp.c | 2443 +++++++ ospfd/ospf_snmp.h | 33 + ospfd/ospf_spf.c | 1088 +++ ospfd/ospf_spf.h | 50 + ospfd/ospf_te.c | 1921 ++++++ ospfd/ospf_te.h | 193 + ospfd/ospf_vty.c | 7571 +++++++++++++++++++++ ospfd/ospf_vty.h | 85 + ospfd/ospf_zebra.c | 1180 ++++ ospfd/ospf_zebra.h | 78 + ospfd/ospfd.c | 1603 +++++ ospfd/ospfd.conf.sample | 13 + ospfd/ospfd.h | 559 ++ ports/Makefile | 58 + ports/README | 1 + ports/files/md5 | 1 + ports/pkg/COMMENT | 1 + ports/pkg/DESCR | 75 + ports/pkg/PLIST | 8 + ripd/.cvsignore | 7 + ripd/ChangeLog | 749 ++ ripd/Makefile.am | 37 + ripd/Makefile.in | 489 ++ ripd/RIPv2-MIB.txt | 530 ++ ripd/rip_debug.c | 290 + ripd/rip_debug.h | 54 + ripd/rip_interface.c | 2001 ++++++ ripd/rip_main.c | 270 + ripd/rip_offset.c | 414 ++ ripd/rip_peer.c | 211 + ripd/rip_routemap.c | 898 +++ ripd/rip_snmp.c | 577 ++ ripd/rip_zebra.c | 691 ++ ripd/ripd.c | 3536 ++++++++++ ripd/ripd.conf.sample | 24 + ripd/ripd.h | 408 ++ ripngd/.cvsignore | 7 + ripngd/ChangeLog | 216 + ripngd/Makefile.am | 37 + ripngd/Makefile.in | 487 ++ ripngd/ripng_debug.c | 292 + ripngd/ripng_debug.h | 52 + ripngd/ripng_interface.c | 835 +++ ripngd/ripng_main.c | 252 + ripngd/ripng_route.c | 157 + ripngd/ripng_route.h | 53 + ripngd/ripng_routemap.c | 342 + ripngd/ripng_zebra.c | 877 +++ ripngd/ripngd.c | 2526 +++++++ ripngd/ripngd.conf.sample | 22 + ripngd/ripngd.h | 318 + stamp-h.in | 1 + tools/mrlg.cgi | 395 ++ tools/rrcheck.pl | 135 + tools/rrlookup.pl | 123 + tools/zc.pl | 111 + tools/zebra.el | 108 + update-autotools | 14 + vtysh/.cvsignore | 6 + vtysh/ChangeLog | 173 + vtysh/Makefile.am | 22 + vtysh/Makefile.in | 453 ++ vtysh/extract.pl | 171 + vtysh/vtysh.c | 1803 +++++ vtysh/vtysh.conf.sample | 4 + vtysh/vtysh.h | 83 + vtysh/vtysh_cmd.c | 14710 ++++++++++++++++++++++++++++++++++++++++ vtysh/vtysh_config.c | 426 ++ vtysh/vtysh_main.c | 288 + vtysh/vtysh_user.c | 191 + vtysh/vtysh_user.h | 27 + zebra/.cvsignore | 8 + zebra/ChangeLog | 1221 ++++ zebra/GNOME-PRODUCT-ZEBRA-MIB | 78 + zebra/GNOME-SMI | 53 + zebra/Makefile.am | 57 + zebra/Makefile.in | 493 ++ zebra/client_main.c | 225 + zebra/connected.c | 394 ++ zebra/connected.h | 60 + zebra/debug.c | 272 + zebra/debug.h | 52 + zebra/if_ioctl.c | 438 ++ zebra/if_netlink.c | 33 + zebra/if_proc.c | 246 + zebra/if_sysctl.c | 148 + zebra/interface.c | 1387 ++++ zebra/interface.h | 180 + zebra/ioctl.c | 540 ++ zebra/ioctl.h | 46 + zebra/ipforward.h | 35 + zebra/ipforward_aix.c | 64 + zebra/ipforward_ews.c | 60 + zebra/ipforward_proc.c | 155 + zebra/ipforward_solaris.c | 77 + zebra/ipforward_sysctl.c | 146 + zebra/irdp.c | 569 ++ zebra/irdp.h | 148 + zebra/kernel_netlink.c | 20 + zebra/kernel_socket.c | 811 +++ zebra/main.c | 316 + zebra/mtu_kvm.c | 97 + zebra/redistribute.c | 410 ++ zebra/redistribute.h | 49 + zebra/rib.h | 251 + zebra/rt.h | 40 + zebra/rt_ioctl.c | 558 ++ zebra/rt_netlink.c | 1482 ++++ zebra/rt_socket.c | 441 ++ zebra/rtadv.c | 1112 +++ zebra/rtadv.h | 49 + zebra/rtread_getmsg.c | 229 + zebra/rtread_netlink.c | 31 + zebra/rtread_proc.c | 169 + zebra/rtread_sysctl.c | 75 + zebra/zebra.conf.sample | 25 + zebra/zebra_rib.c | 2199 ++++++ zebra/zebra_snmp.c | 550 ++ zebra/zebra_vty.c | 1554 +++++ zebra/zserv.c | 1806 +++++ zebra/zserv.h | 132 + 420 files changed, 243853 insertions(+) create mode 100644 .cvsignore create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 COPYING.LIB create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 Makefile.in create mode 100644 NEWS create mode 100644 README create mode 100644 REPORTING-BUGS create mode 100644 SERVICES create mode 100644 TODO create mode 100644 acconfig.h create mode 100644 aclocal.m4 create mode 100644 bgpd/.cvsignore create mode 100644 bgpd/BGP4-MIB.txt create mode 100644 bgpd/ChangeLog create mode 100644 bgpd/Makefile.am create mode 100644 bgpd/Makefile.in create mode 100644 bgpd/bgp_advertise.c create mode 100644 bgpd/bgp_advertise.h create mode 100644 bgpd/bgp_aspath.c create mode 100644 bgpd/bgp_aspath.h create mode 100644 bgpd/bgp_attr.c create mode 100644 bgpd/bgp_attr.h create mode 100644 bgpd/bgp_btoa.c create mode 100644 bgpd/bgp_clist.c create mode 100644 bgpd/bgp_clist.h create mode 100644 bgpd/bgp_community.c create mode 100644 bgpd/bgp_community.h create mode 100644 bgpd/bgp_damp.c create mode 100644 bgpd/bgp_damp.h create mode 100644 bgpd/bgp_debug.c create mode 100644 bgpd/bgp_debug.h create mode 100644 bgpd/bgp_dump.c create mode 100644 bgpd/bgp_dump.h create mode 100644 bgpd/bgp_ecommunity.c create mode 100644 bgpd/bgp_ecommunity.h create mode 100644 bgpd/bgp_filter.c create mode 100644 bgpd/bgp_filter.h create mode 100644 bgpd/bgp_fsm.c create mode 100644 bgpd/bgp_fsm.h create mode 100644 bgpd/bgp_main.c create mode 100644 bgpd/bgp_mplsvpn.c create mode 100644 bgpd/bgp_mplsvpn.h create mode 100644 bgpd/bgp_network.c create mode 100644 bgpd/bgp_network.h create mode 100644 bgpd/bgp_nexthop.c create mode 100644 bgpd/bgp_nexthop.h create mode 100644 bgpd/bgp_open.c create mode 100644 bgpd/bgp_open.h create mode 100644 bgpd/bgp_packet.c create mode 100644 bgpd/bgp_packet.h create mode 100644 bgpd/bgp_regex.c create mode 100644 bgpd/bgp_regex.h create mode 100644 bgpd/bgp_route.c create mode 100644 bgpd/bgp_route.h create mode 100644 bgpd/bgp_routemap.c create mode 100644 bgpd/bgp_snmp.c create mode 100644 bgpd/bgp_snmp.h create mode 100644 bgpd/bgp_table.c create mode 100644 bgpd/bgp_table.h create mode 100644 bgpd/bgp_view.c create mode 100644 bgpd/bgp_vty.c create mode 100644 bgpd/bgp_vty.h create mode 100644 bgpd/bgp_zebra.c create mode 100644 bgpd/bgp_zebra.h create mode 100644 bgpd/bgpd.c create mode 100644 bgpd/bgpd.conf.sample create mode 100644 bgpd/bgpd.conf.sample2 create mode 100644 bgpd/bgpd.h create mode 100755 config.guess create mode 100644 config.h.in create mode 100755 config.sub create mode 100755 configure create mode 100755 configure.in create mode 100755 depcomp create mode 100644 doc/.cvsignore create mode 100644 doc/BGP-TypeCode create mode 100644 doc/ChangeLog create mode 100644 doc/Makefile.am create mode 100644 doc/Makefile.in create mode 100644 doc/appendix.texi create mode 100644 doc/basic.texi create mode 100644 doc/bgpd.8 create mode 100644 doc/bgpd.texi create mode 100644 doc/draft-zebra-00.ms create mode 100644 doc/filter.texi create mode 100644 doc/install.texi create mode 100644 doc/ipv6.texi create mode 100644 doc/kernel.texi create mode 100644 doc/main.texi create mode 100644 doc/ospf6d.8 create mode 100644 doc/ospf6d.texi create mode 100644 doc/ospfd.8 create mode 100644 doc/ospfd.texi create mode 100644 doc/overview.texi create mode 100644 doc/protocol.texi create mode 100644 doc/ripd.8 create mode 100644 doc/ripd.texi create mode 100644 doc/ripngd.8 create mode 100644 doc/ripngd.texi create mode 100644 doc/routemap.texi create mode 100644 doc/snmp.texi create mode 100644 doc/texinfo.tex create mode 100644 doc/vtysh.1 create mode 100644 doc/vtysh.texi create mode 100644 doc/zebra.8 create mode 100644 doc/zebra.info create mode 100644 doc/zebra.texi create mode 100644 guile/.cvsignore create mode 100644 guile/ChangeLog create mode 100644 guile/Makefile.am create mode 100644 guile/Makefile.in create mode 100644 guile/README create mode 100644 guile/guile-bgp.c create mode 100644 guile/zebra-guile.c create mode 100644 guile/zebra-guile.h create mode 100644 guile/zebra-support.c create mode 100644 init/.cvsignore create mode 100644 init/ChangeLog create mode 100644 init/redhat/bgpd.init create mode 100644 init/redhat/ospf6d.init create mode 100644 init/redhat/ospfd.init create mode 100644 init/redhat/ripd.init create mode 100644 init/redhat/ripngd.init create mode 100644 init/redhat/zebra.init create mode 100644 init/redhat/zebra.logrotate create mode 100644 init/redhat/zebra.spec.in create mode 100755 install-sh create mode 100644 lib/.cvsignore create mode 100644 lib/ChangeLog create mode 100644 lib/Makefile.am create mode 100644 lib/Makefile.in create mode 100644 lib/buffer.c create mode 100644 lib/buffer.h create mode 100644 lib/checksum.c create mode 100644 lib/command.c create mode 100644 lib/command.h create mode 100644 lib/daemon.c create mode 100644 lib/distribute.c create mode 100644 lib/distribute.h create mode 100644 lib/filter.c create mode 100644 lib/filter.h create mode 100644 lib/getopt.c create mode 100644 lib/getopt.h create mode 100644 lib/getopt1.c create mode 100644 lib/hash.c create mode 100644 lib/hash.h create mode 100644 lib/if.c create mode 100644 lib/if.h create mode 100644 lib/if_rmap.c create mode 100644 lib/if_rmap.h create mode 100644 lib/keychain.c create mode 100644 lib/keychain.h create mode 100644 lib/linklist.c create mode 100644 lib/linklist.h create mode 100644 lib/log.c create mode 100644 lib/log.h create mode 100644 lib/md5-gnu.h create mode 100644 lib/md5.c create mode 100644 lib/memory.c create mode 100644 lib/memory.h create mode 100644 lib/network.c create mode 100644 lib/network.h create mode 100644 lib/pid_output.c create mode 100644 lib/plist.c create mode 100644 lib/plist.h create mode 100644 lib/prefix.c create mode 100644 lib/prefix.h create mode 100644 lib/print_version.c create mode 100644 lib/regex-gnu.h create mode 100644 lib/regex.c create mode 100644 lib/routemap.c create mode 100644 lib/routemap.h create mode 100644 lib/smux.c create mode 100644 lib/smux.h create mode 100644 lib/sockopt.c create mode 100644 lib/sockopt.h create mode 100644 lib/sockunion.c create mode 100644 lib/sockunion.h create mode 100644 lib/str.c create mode 100644 lib/str.h create mode 100644 lib/stream.c create mode 100644 lib/stream.h create mode 100644 lib/table.c create mode 100644 lib/table.h create mode 100644 lib/tcpfilter.c create mode 100644 lib/tcpfilter.h create mode 100644 lib/thread.c create mode 100644 lib/thread.h create mode 100644 lib/vector.c create mode 100644 lib/vector.h create mode 100644 lib/version.h create mode 100644 lib/vty.c create mode 100644 lib/vty.h create mode 100644 lib/zclient.c create mode 100644 lib/zclient.h create mode 100644 lib/zebra.h create mode 100755 missing create mode 100755 mkinstalldirs create mode 100644 ospf6d/.cvsignore create mode 100644 ospf6d/ChangeLog create mode 100644 ospf6d/Makefile.am create mode 100644 ospf6d/Makefile.in create mode 100644 ospf6d/README create mode 100644 ospf6d/ospf6_abr.c create mode 100644 ospf6d/ospf6_abr.h create mode 100644 ospf6d/ospf6_area.c create mode 100644 ospf6d/ospf6_area.h create mode 100644 ospf6d/ospf6_asbr.c create mode 100644 ospf6d/ospf6_asbr.h create mode 100644 ospf6d/ospf6_bintree.c create mode 100644 ospf6d/ospf6_bintree.h create mode 100644 ospf6d/ospf6_damp.c create mode 100644 ospf6d/ospf6_damp.h create mode 100644 ospf6d/ospf6_dbex.c create mode 100644 ospf6d/ospf6_dbex.h create mode 100644 ospf6d/ospf6_dump.c create mode 100644 ospf6d/ospf6_dump.h create mode 100644 ospf6d/ospf6_hook.c create mode 100644 ospf6d/ospf6_hook.h create mode 100644 ospf6d/ospf6_interface.c create mode 100644 ospf6d/ospf6_interface.h create mode 100644 ospf6d/ospf6_intra.c create mode 100644 ospf6d/ospf6_intra.h create mode 100644 ospf6d/ospf6_ism.c create mode 100644 ospf6d/ospf6_ism.h create mode 100644 ospf6d/ospf6_linklist.c create mode 100644 ospf6d/ospf6_linklist.h create mode 100644 ospf6d/ospf6_lsa.c create mode 100644 ospf6d/ospf6_lsa.h create mode 100644 ospf6d/ospf6_lsdb.c create mode 100644 ospf6d/ospf6_lsdb.h create mode 100644 ospf6d/ospf6_main.c create mode 100644 ospf6d/ospf6_message.c create mode 100644 ospf6d/ospf6_message.h create mode 100644 ospf6d/ospf6_neighbor.c create mode 100644 ospf6d/ospf6_neighbor.h create mode 100644 ospf6d/ospf6_network.c create mode 100644 ospf6d/ospf6_network.h create mode 100644 ospf6d/ospf6_nsm.c create mode 100644 ospf6d/ospf6_nsm.h create mode 100644 ospf6d/ospf6_prefix.c create mode 100644 ospf6d/ospf6_prefix.h create mode 100644 ospf6d/ospf6_proto.c create mode 100644 ospf6d/ospf6_proto.h create mode 100644 ospf6d/ospf6_route.c create mode 100644 ospf6d/ospf6_route.h create mode 100644 ospf6d/ospf6_routemap.c create mode 100644 ospf6d/ospf6_routemap.h create mode 100644 ospf6d/ospf6_spf.c create mode 100644 ospf6d/ospf6_spf.h create mode 100644 ospf6d/ospf6_top.c create mode 100644 ospf6d/ospf6_top.h create mode 100644 ospf6d/ospf6_types.h create mode 100644 ospf6d/ospf6_zebra.c create mode 100644 ospf6d/ospf6_zebra.h create mode 100644 ospf6d/ospf6d.c create mode 100644 ospf6d/ospf6d.conf.sample create mode 100644 ospf6d/ospf6d.h create mode 100644 ospfd/.cvsignore create mode 100644 ospfd/ChangeLog create mode 100644 ospfd/Makefile.am create mode 100644 ospfd/Makefile.in create mode 100644 ospfd/OSPF-MIB.txt create mode 100644 ospfd/OSPF-TRAP-MIB.txt create mode 100644 ospfd/ospf_abr.c create mode 100644 ospfd/ospf_abr.h create mode 100644 ospfd/ospf_asbr.c create mode 100644 ospfd/ospf_asbr.h create mode 100644 ospfd/ospf_ase.c create mode 100644 ospfd/ospf_ase.h create mode 100644 ospfd/ospf_dump.c create mode 100644 ospfd/ospf_dump.h create mode 100644 ospfd/ospf_flood.c create mode 100644 ospfd/ospf_flood.h create mode 100644 ospfd/ospf_ia.c create mode 100644 ospfd/ospf_ia.h create mode 100644 ospfd/ospf_interface.c create mode 100644 ospfd/ospf_interface.h create mode 100644 ospfd/ospf_ism.h create mode 100644 ospfd/ospf_lsa.c create mode 100644 ospfd/ospf_lsa.h create mode 100644 ospfd/ospf_lsdb.c create mode 100644 ospfd/ospf_lsdb.h create mode 100644 ospfd/ospf_main.c create mode 100644 ospfd/ospf_neighbor.h create mode 100644 ospfd/ospf_network.c create mode 100644 ospfd/ospf_network.h create mode 100644 ospfd/ospf_nsm.h create mode 100644 ospfd/ospf_opaque.c create mode 100644 ospfd/ospf_opaque.h create mode 100644 ospfd/ospf_packet.c create mode 100644 ospfd/ospf_packet.h create mode 100644 ospfd/ospf_route.c create mode 100644 ospfd/ospf_route.h create mode 100644 ospfd/ospf_routemap.c create mode 100644 ospfd/ospf_snmp.c create mode 100644 ospfd/ospf_snmp.h create mode 100644 ospfd/ospf_spf.c create mode 100644 ospfd/ospf_spf.h create mode 100644 ospfd/ospf_te.c create mode 100644 ospfd/ospf_te.h create mode 100644 ospfd/ospf_vty.c create mode 100644 ospfd/ospf_vty.h create mode 100644 ospfd/ospf_zebra.c create mode 100644 ospfd/ospf_zebra.h create mode 100644 ospfd/ospfd.c create mode 100644 ospfd/ospfd.conf.sample create mode 100644 ospfd/ospfd.h create mode 100644 ports/Makefile create mode 100644 ports/README create mode 100644 ports/files/md5 create mode 100644 ports/pkg/COMMENT create mode 100644 ports/pkg/DESCR create mode 100644 ports/pkg/PLIST create mode 100644 ripd/.cvsignore create mode 100644 ripd/ChangeLog create mode 100644 ripd/Makefile.am create mode 100644 ripd/Makefile.in create mode 100644 ripd/RIPv2-MIB.txt create mode 100644 ripd/rip_debug.c create mode 100644 ripd/rip_debug.h create mode 100644 ripd/rip_interface.c create mode 100644 ripd/rip_main.c create mode 100644 ripd/rip_offset.c create mode 100644 ripd/rip_peer.c create mode 100644 ripd/rip_routemap.c create mode 100644 ripd/rip_snmp.c create mode 100644 ripd/rip_zebra.c create mode 100644 ripd/ripd.c create mode 100644 ripd/ripd.conf.sample create mode 100644 ripd/ripd.h create mode 100644 ripngd/.cvsignore create mode 100644 ripngd/ChangeLog create mode 100644 ripngd/Makefile.am create mode 100644 ripngd/Makefile.in create mode 100644 ripngd/ripng_debug.c create mode 100644 ripngd/ripng_debug.h create mode 100644 ripngd/ripng_interface.c create mode 100644 ripngd/ripng_main.c create mode 100644 ripngd/ripng_route.c create mode 100644 ripngd/ripng_route.h create mode 100644 ripngd/ripng_routemap.c create mode 100644 ripngd/ripng_zebra.c create mode 100644 ripngd/ripngd.c create mode 100644 ripngd/ripngd.conf.sample create mode 100644 ripngd/ripngd.h create mode 100644 stamp-h.in create mode 100755 tools/mrlg.cgi create mode 100644 tools/rrcheck.pl create mode 100644 tools/rrlookup.pl create mode 100755 tools/zc.pl create mode 100644 tools/zebra.el create mode 100755 update-autotools create mode 100644 vtysh/.cvsignore create mode 100644 vtysh/ChangeLog create mode 100644 vtysh/Makefile.am create mode 100644 vtysh/Makefile.in create mode 100755 vtysh/extract.pl create mode 100644 vtysh/vtysh.c create mode 100644 vtysh/vtysh.conf.sample create mode 100644 vtysh/vtysh.h create mode 100644 vtysh/vtysh_cmd.c create mode 100644 vtysh/vtysh_config.c create mode 100644 vtysh/vtysh_main.c create mode 100644 vtysh/vtysh_user.c create mode 100644 vtysh/vtysh_user.h create mode 100644 zebra/.cvsignore create mode 100644 zebra/ChangeLog create mode 100644 zebra/GNOME-PRODUCT-ZEBRA-MIB create mode 100644 zebra/GNOME-SMI create mode 100644 zebra/Makefile.am create mode 100644 zebra/Makefile.in create mode 100644 zebra/client_main.c create mode 100644 zebra/connected.c create mode 100644 zebra/connected.h create mode 100644 zebra/debug.c create mode 100644 zebra/debug.h create mode 100644 zebra/if_ioctl.c create mode 100644 zebra/if_netlink.c create mode 100644 zebra/if_proc.c create mode 100644 zebra/if_sysctl.c create mode 100644 zebra/interface.c create mode 100644 zebra/interface.h create mode 100644 zebra/ioctl.c create mode 100644 zebra/ioctl.h create mode 100644 zebra/ipforward.h create mode 100644 zebra/ipforward_aix.c create mode 100644 zebra/ipforward_ews.c create mode 100644 zebra/ipforward_proc.c create mode 100644 zebra/ipforward_solaris.c create mode 100644 zebra/ipforward_sysctl.c create mode 100644 zebra/irdp.c create mode 100644 zebra/irdp.h create mode 100644 zebra/kernel_netlink.c create mode 100644 zebra/kernel_socket.c create mode 100644 zebra/main.c create mode 100644 zebra/mtu_kvm.c create mode 100644 zebra/redistribute.c create mode 100644 zebra/redistribute.h create mode 100644 zebra/rib.h create mode 100644 zebra/rt.h create mode 100644 zebra/rt_ioctl.c create mode 100644 zebra/rt_netlink.c create mode 100644 zebra/rt_socket.c create mode 100644 zebra/rtadv.c create mode 100644 zebra/rtadv.h create mode 100644 zebra/rtread_getmsg.c create mode 100644 zebra/rtread_netlink.c create mode 100644 zebra/rtread_proc.c create mode 100644 zebra/rtread_sysctl.c create mode 100644 zebra/zebra.conf.sample create mode 100644 zebra/zebra_rib.c create mode 100644 zebra/zebra_snmp.c create mode 100644 zebra/zebra_vty.c create mode 100644 zebra/zserv.c create mode 100644 zebra/zserv.h diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 00000000..0e2c5b64 --- /dev/null +++ b/.cvsignore @@ -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 index 00000000..61867a86 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,6 @@ +Kunihiro Ishiguro +Toshiaki Takada +Yasuhiro Ohara +Alex D. Zinin +Gleb Natapov +Akihiro Mizutani diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..a43ea212 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/COPYING.LIB b/COPYING.LIB new file mode 100644 index 00000000..161a3d1d --- /dev/null +++ b/COPYING.LIB @@ -0,0 +1,482 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 00000000..7448bfe1 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,674 @@ +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2002-06-28 Kunihiro Ishiguro + + * update-autotools: Change file name from update-auto-tools.sh. + +2002-06-21 Kunihiro Ishiguro + + * update-auto-tools.sh: Add a new script to clean up build + environment. + +2002-06-18 Kunihiro Ishiguro + + * Shift to the latest build environment autoconf-2.53 and + automake-1.6.2. + +2001-10-22 Kunihiro Ishiguro + + * Integrate Glen Turner 's pid option. + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-19 "Peter Galbavy" + + * configure.in: SNMP library check problem fix when the library is + installed under /usr/local/lib. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-04-22 Kunihiro Ishiguro + + * configure.in (LIBPAM): Use ZEBRA_AC_C_BIGENDIAN to avoid a + warning. + (IF_METHOD): Use test -r instead of AC_CHECK_FILE to avoid + warnings. + + * config.guess: Update to 2000-11-10 version. + +2001-04-11 Kunihiro Ishiguro + + * configure.in: Use AC_TRY_COMPILE instead of AC_EGREP_HEADER to + detect in_pktinfo structure. Suggested by: Vlad Lungu + . + +2001-03-07 Michael Rozhavsky + + * configure.in: Add check for structure in_pktinfo. + +2001-02-07 "Bjoern A. Zeeb" + + * configure.in (USE_PAM): Fix PAM library detection code. + +2001-02-01 Kunihiro Ishiguro + + * zebra-0.91 is released. + +2001-01-12 Kunihiro Ishiguro + + * configure.in: Remove guile related definition. + +2001-01-11 Kunihiro Ishiguro + + * configure.in (ac_cv_htonl_works): HAVE_REPAIRABLE_HTONL is + removed. htonl should work fine on any platform. + +2001-01-10 Kunihiro Ishiguro + + * configure.in: Remove --enable-oldrib option. + + * acconfig.h: OLD_RIB definition is removed. + + * zebra-0.90 is released. + + * configure.in (LIBS): Add check for sun_len field in struct + sun_len. + +2001-01-09 Kunihiro Ishiguro + + * Makefile.am: Include init/redhat files to distribution. + +2001-01-07 Yasuhiro Ohara + + * configure.in: check libm.a for BGPd compile error. + AC_CHECK_LIB(m, main) was added. + +2000-12-29 Kunihiro Ishiguro + + * configure.in: --enable-unixdomain becomes default. Add + --enable-tcp-zebra for TCP/IP communication between protocol + daemon and zebra. + + * COPYING.LIB: Added for lib/getopt.c, lib/getopt.h, + lib/getopt1.c, lib/md5-gnu.h, lib/md5.c, lib/regex-gnu.h, + lib/regex.c. + + * Makefile.am (dist-hook): Include tools/*.cgi to distribution. + +2000-12-26 Kunihiro Ishiguro + + * configure.in (MULTIPATH_NUM): --enable-multipath=ARG specify + multipath number. ARG must be digit. + +2000-12-11 Kunihiro Ishiguro + + * configure.in: Add --enable-newrib for test new RIB code. + +2000-11-25 Yasuhiro Ohara + + * configure.in, config.h.in: Add check for libutil.h and + setproctitle(). + +2000-10-26 Kunihiro Ishiguro + + * configure.in: Add --enable-nssa for OSPF NSSA option. + + * acconfig.h: Define HAVE_NSSA. + +2000-10-25 "Bjoern A. Zeeb" + + * configure.in: pam_misc is only linked when the platform is + GNU/Linux. + +2000-10-24 Arkadiusz Miskiewicz + + * configure.in (LIBS): Add check for crypto library. test x`ls + ${ac_snmp}` is replaced with sipmle test -f. + +2000-10-23 Kunihiro Ishiguro + + * configure.in: Add --enable-unixdomain option. This will be + default behavior in zebra-0.90. + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 is released. + +2000-09-27 Kunihiro Ishiguro + + * configure.in: Add check for Intel CPU for Solaris on x86 check. + +2000-09-21 Kunihiro Ishiguro + + * configure.in: Add check for getifaddrs(). + Set AM_INIT_AUTOMAKE version to 0.89. + +2000-09-14 Kunihiro Ishiguro + + * config.guess: Update to the latest version. + + * config.sub: Likewise + +2000-09-14 David Lipovkov + + * REPORTING-BUGS: New file is added. + +2000-08-27 itojun@iijlab.net + + * configure.in: Add ncurses library check when --enable-vtysh is + specified. + +2000-08-22 Kunihiro Ishiguro + + * configure.in: Add check for readline/history.h. + + * acconfig.h: Remove pthread related variables. + + * configure.in: Add --with-libpam option for vtysh PAM + authentication. Remove --disable-pthread because we don't support + pthread. + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 is released. + + * configure.in: Add Solaris -lcurses for vtysh. + +2000-08-02 Kunihiro Ishiguro + + * configure.in: Add check for ncurses for compiling on Solaris. + +2000-07-27 Kunihiro Ishiguro + + * configure.in: Add check for libreadline when --enable-vtysh is + specified. + +2000-07-23 Kunihiro Ishiguro + + * configure.in: Add AC_DEFINE(OPEN_BSD). When OS is OpenBSD + interface method is if_ioctl.o + +2000-07-09 Chris Dunlop + + * acconfig.h: Add HAVE_BROKEN_ALIASES. + + * configure.in: Add --enable-broken-aliases. + +2000-06-12 Kunihiro Ishiguro + + * Set version to zebra-0.87. + +2000-06-05 Kunihiro Ishiguro + + * configure.in: Remove --enable-mpls-vpn. Now MPLS-VPN support is + default. + + * Set version to zebra-0.87-pre + + * Makefile.am: Likewise. + +2000-04-27 Kunihiro Ishiguro + + * Set version to 0.86. + +2000-03-21 Kunihiro Ishiguro + + * Set version to 0.85b for ospfd test. + +2000-03-20 Kunihiro Ishiguro + + * Set version to 0.85a for ospfd test. + +2000-03-08 Kunihiro Ishiguro + + * Set version to 0.85. + +2000-01-26 Kunihiro Ishiguro + + * Makefile.in: Regenerated by patched automake for fixing "make + clean" problem on FreeBSD. + +1999-12-08 Kunihiro Ishiguro + + * Set version to 0.83a. This is for *BSD static route lookup + problem. + +1999-12-06 Kunihiro Ishiguro + + * Set version to 0.83. + +1999-11-29 Kunihiro Ishiguro + + * Set version to 0.82. + +1999-11-23 Kunihiro Ishiguro + + * aczebra.m4: New file added. + +1999-11-21 Michael Handler + + * configure.in (LIBS): Add sa_len check of sockaddr. + + * acconfig.h: Add HAVE_SA_LEN. + +1999-11-12 Kunihiro Ishiguro + + * version.h: Update version to zebra-0.81b for bgpd test. + +1999-11-09 Kunihiro Ishiguro + + * configure.in: Add --enable-mbgp. + +1999-11-05 Kunihiro Ishiguro + + * Makefile.am (EXTRA_DIST): Add TODO to the distribution. + +1999-11-04 Kunihiro Ishiguro + + * TODO: New file is added. + +1999-11-03 Kunihiro Ishiguro + + * version.h: Update version to zebra-0.81a for ospfd test. + +1999-10-28 Kunihiro Ishiguro + + * configure.in: New option --enable-snmp is added. + +1999-10-24 Kunihiro Ishiguro + + * version.h: Update version to zebra-0.80. + +1999-10-21 Kunihiro Ishiguro + + * version.h: Update version to zebra-0.80-pre3 + +1999-10-18 Kunihiro Ishiguro + + * configure.in (LIBS): SNMP check is done by ucd-snmp/asn1.h. + +1999-10-10 Peter Galbavy + + * configure.in: Add support of OpenBSD. + +1999-10-04 Kunihiro Ishiguro + + * version.h: Update version to zebra-0.80-pre2. + +1999-09-27 Kunihiro Ishiguro + + * version.h: Update version to zebra-0.80-pre. From this version, + access-list and prefix-list's name space is divided into IPv4 and + IPv6. + +1999-09-17 Kunihiro Ishiguro + + * version.h: For test recent fixes Set version to zebra-0.79a. + +1999-09-14 Kunihiro Ishiguro + + * version.h: zebra-0.79 is out. + +1999-09-08 Kunihiro Ishiguro + + * version.h: For ospfd's virtual link test. Set version to 0.78h. + +1999-09-07 Kunihiro Ishiguro + + * version.h: For ospfd test. Set version to 0.78g. + +1999-09-05 Kunihiro Ishiguro + + * version.h: For internal test of ospfd. Set version to 0.78f. + +1999-09-02 Kunihiro Ishiguro + + * version.h: To test ospfd's fix, set version to 0.78e. + +1999-09-01 Kunihiro Ishiguro + + * version.h: To test ospfd's area related bug fix, set version + to 0.78d. + +1999-09-01 Kunihiro Ishiguro + + * version.h: To test ospfd, set version to 0.78c. + +1999-08-31 Janos Farkas + + * Many misspelling correction. + +1999-08-31 Kunihiro Ishiguro + + * version.h: To test ospfd, set version to 0.78b. + +1999-08-31 Kunihiro Ishiguro + + * configure.in (LIBS): Add UCD-SNMP include path check. + +1999-08-31 Lars Fenneberg + + * configure.in: The logic which detects the UCD-SNMP library + should first check in the default system locations for the library + and then in /usr/local. + +1999-08-27 itojun@iijlab.net + + * configure.in (LIBS): Fix problem about libsnmp.a check. + +1999-08-26 kay + + * configure.in (CFLAGS): Add to check socklen_t. + +1999-08-24 VOP + + * filter.c: Include "sockunion.h". + plist.c: Likewise. + table.c: Likewise. + +1999-08-24 Kunihiro Ishiguro + + * configure.in: Add netinet6/in6.h check. + +1999-08-21 Masaki Minami + + * BSD/OS 4.0 porting. + +1999-08-15 Kunihiro Ishiguro + + * configure.in: Add --enable-netlink option to force to use Linux + netlink interface. + (CFLAGS): Add ucd-snmp library check. + + * acconfig.h: If socklen_t is not defined, typedef int to + socklen_t. + +1999-08-15 Arkadiusz Miskiewicz + + * configure.in: When --enable-ipv6 specified, then only kernel + version is checked. + +1999-08-14 Kunihiro Ishiguro + + * configure.in: Add GNU libc 2.1 check. + +1999-08-02 Kunihiro Ishiguro + + * configure.in: Fix privious Linux IPv6 check changes. + +1999-08-02 Arkadiusz Miskiewicz + + * configure.in: Improve Linux IPv6 feature check. + +1999-07-29 Rick Payne + + * Changed route-maps to behave in a more cisco-like fashion + +1999-07-27 Gerhard Poul + + * SERVICES: New file added. + +1999-07-12 itojun@iijlab.net + + * configure.in: Add check for getaddrinfo. Improve Kame related + library check. + +1999-07-07 Yasuhiro Ohara + + * configure.in, acconfig.h: Add check for FreeBSD 3.2. + +1999-07-07 Kunihiro Ishiguro + + * configure.in: Delete check for netinet/ip6.h. + +1999-06-30 Gerhard Poul + + * README: remixed the old files and added some new parts. + moved some INSTALL stuff into INSTALL file. + moved some other stuff to doc/zebra.texi + +1999-06-29 Kunihiro Ishiguro + + * configure.in (LIBS): Add libresolv check. + Change --enabe-all-in-one option to --enable-one-vty. + +1999-06-20 Kunihiro Ishiguro + + * configure.in: Add --enabe-all-in-one option. + +1999-06-16 Kunihiro Ishiguro + + * configure.in: Add socklen_t check. + +1999-06-16 Gerhard Poul + + * Many compile warnings fixed. + +1999-05-31 Kunihiro Ishiguro + + * configure.in: Change message from Linux 2.2.X IPv6 to Linux IPv6. + OpenBSD (NRL) check is enabled. + +1999-05-30 Kunihiro Ishiguro + + * configure.in (LIBS): Add crypt library check. + +1999-05-08 Kunihiro Ishiguro + + * configure.in: Add sin6_scope_id in struct sockaddr_in6 check. + +1999-04-30 Kunihiro Ishiguro + + * Set version to 0.63 for first beta package. + +1999-04-15 Kunihiro Ishiguro + + * guile.m4: Added from guile package. + +1999-04-14 Kunihiro Ishiguro + + * Set version to 0.60 for beta package preparation. + +1999-04-12 Kunihiro Ishiguro + + * Makefile.am: Add noninst_LIBRARIES each directory's Makefile.am. + This change is for linking these libraries to guile. + +1999-04-08 Kunihiro Ishiguro + + * configure.in (LIBS): Add struct rt_addrinfo check. + +1999-04-07 Kunihiro Ishiguro + + * configure.in: AC_STDC_HEADERS added. + +1999-03-29 Kunihiro Ishiguro + + * Add dependencies to each directory's Makefile.am. + +1999-03-02 Peter Galbavy + + * reworked include file structure, and configure so that all + source files get all system-dependent include files by including + which is really lib/zebra.h. This means that the + different programs include files are now available as #include + "zebra/zebra.h" - note the use of quotes, not <> as delimiters. + + In practical terms, if I haven't really screwed up, the main file + that maintainers for other OSes have to change is lib/zebra.h for + all the conditional includes etc. + + * added --disable-pthread for those systems that seem to have + POSIX threads, but do not work. OpenBSD 2.4+ is like that just + now. Changed all occurance of #ifdef PTHREAD to use HAVE_PTHREAD + instead. + +1999-02-24 + + * configure.in: update to AC_PREREQ(1.13). + Change message from Linux 2.1.x to Linux 2.2.x. + * Added ospf6d directory support. + +1999-02-22 Peter Galbavy + + * added a "log" element to the BGPd peer structure, enabling us to + start thinging about a log stream per peer. This is currently + ignored by the wrapper code, but developers should try to use the + "appropriate" ZLOG stream. Documentation will follow, when the + real routines start to exist. + + The current plan is to use a copy of the BSD syslog() routines and + replace the syslog library function with our own. I will need + feedback from users of other platforms as this work is done to see + if all is well elsewhere. + + * preliminary work on zlog() library. directly replaces syslog() + currently with zlog(ZLOG *, ...) where the new first argument + is a pointer to a ZLOG structure (defined in lib/log.h) and will + encapsulate all the information necessary to maintain multiple + logging streams. + +1999-02-19 Peter Galbavy + + * added vsnprintf() macro to lib/str.h if required and removed + #ifdef SUNOS_5 dependency on it + +1999-02-18 Peter Galbavy + + * syslog support added + +1999-02-18 Peter Galbavy + + * configure.in: Add daemon function check. + +1999-01-21 Kunihiro Ishiguro + + * configure.in: Add --disable-ipv6, --disable-zebra, + --disable-bgpd, --disable-ripd, --disable-ripngd, --disable-ospfd + options to configure. + +1998-12-07 Kunihiro Ishiguro + + * configure.in: Check /usr/inet6/lib/libinet6.a exists or not. + +1998-10-14 Kunihiro Ishiguro + + * configure.in: Comment out FreeBSD's libc_r detect section. At + this moment it doesn't work correctly with zebra. + + Netlink interface is only enabled when Linux kernel version is + upper than 2.1.0. + +1998-09-15 HEO SeonMeyong + + * Hydrangea is now called KAME, so change all defines. + +1998-08-16 Kunihiro Ishiguro + + * configure.in: ifaliasreq check added. + +1998-08-12 Katsuhiro Kondou + + * Patch is applied for compile under EWS4800 + +1998-06-09 Kunihiro Ishiguro + + * configure.in: delete old mtu_method check. + + * doc/zebra.texi (Kernel interface): chapter `Kernel interface' added + +1998-06-08 Kunihiro Ishiguro + + * configure.in: add new netlink check for GNU/Linux + +1998-06-07 Kunihiro Ishiguro + + * doc/zebra.texi: Update Linux netlink chapter. + +1998-05-18 Yamashita TAKAO + + * config.h.in: define PTHREAD if work on Solaris 2.6 + why delete the definition? I miss? + +1998-05-08 Kunihiro Ishiguro + + * configure.in: add net/if.h header check. + +1998-05-02 SeonMeyong HEO + + * zebra.tex,archfig.tex,zebra.sty: Manual file is added. + * zebra.texi: Modify Introduction text. + * RIPngd.c: Patch Hydrangea code. + +1998-05-01 Kunihiro Ishiguro + + * .cvsignore: added. + + * Makerule.in: is gone. + * Makefile.am: Now we use automake to generate Makefile.in + +1998-03-19 Yamashita TAKAO + + * lib/vty.c: modified the definition of *master + * lib/sockunion.c (inet_aton): add, but don't work. uum... + + +1998-03-15 Yamashita TAKAO + + * configure.in: define PTHREAD if work on Solaris 2.6 + * config.h.in: likewise + * lib/thread.c: likewise + * lib/vty.c: likewise + +1998-03-15 SeonMeyong HEO + + * config.h.in: define INET6 if defined HAVE_IPV6 & HYDRANGEA + * bgpd/: remove include line. + * lib/: remove include line. + * ripbgd/: remove include line. + * zebra/: remove include line. + * ripd/*.c: remove include line. + undefine IPV6 difinitions because RIPd is not worked for + IPv6 protocol. + + +1998-01-30 Kunihiro Ishiguro + + * configure.in: Change routing socket check method from + AC_TRY_COMPILE to AC_TRY_RUN because GNU libc version 2 has + AF_ROUTE but over linux it's meenigless. + +1998-01-06 Kunihiro Ishiguro + + * config.h.in: remove err_t define. + +1997-11-18 Kunihiro Ishiguro + + * configure.in (canonical): add check of IF_METHOD + +1997-09-27 Kunihiro Ishiguro + + * configure.in: add INRIA check + +1997-09-25 Kunihiro Ishiguro + + * configure.in (canonical): change ipforward_snmp.o to ipforward_proc.o + +1997-09-12 Kunihiro Ishiguro + + * configure.in: change IRDPD to NDPD + +1997-08-18 Kunihiro Ishiguro + + * INSTALL: new file + +1997-08-14 Kunihiro Ishiguro + + * config.h: add XCALLOC() + diff --git a/INSTALL b/INSTALL new file mode 100644 index 00000000..a2c8722c --- /dev/null +++ b/INSTALL @@ -0,0 +1,181 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..72a09dcf --- /dev/null +++ b/Makefile.am @@ -0,0 +1,16 @@ +## Process this file with automake to produce Makefile.in. + +SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @VTYSH@ doc + +EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS vtysh/Makefile.in \ + vtysh/Makefile.am update-autotools + +dist-hook: + mkdir $(distdir)/tools + cp -p $(srcdir)/tools/*.pl $(distdir)/tools + cp -p $(srcdir)/tools/*.el $(distdir)/tools + cp -p $(srcdir)/tools/*.cgi $(distdir)/tools + mkdir $(distdir)/init + mkdir $(distdir)/init/redhat + cp -p $(srcdir)/init/redhat/*.init $(distdir)/init/redhat + cp -p $(srcdir)/init/redhat/zebra.* $(distdir)/init/redhat diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 00000000..6654f41e --- /dev/null +++ b/Makefile.in @@ -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 index 00000000..24248c71 --- /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. + +* Changes in zebra-0.92a + +* Changes in bgpd + +** Fix "^$" community list bug. + +** Below command's Address Family specific configurations are added + + nexthop-self + route-reflector-client + route-server-client + soft-reconfiguration inbound + +* Changes in zebra + +** Treat kernel type routes as EGP routes. + +* Changes in zebra-0.92 + +** Overall security is improved. Default umask is 0077. + +* Changes in ripd + +** If output interface is in simple password authentication mode, +substruct one from rtemax. + +* Changes in bgpd + +** IPv4 multicast and IPv6 unicast configuration is changed to so +called new config. All of AFI and SAFI specific configuration is +moved to "address-family" node. When you have many IPv6 only +configuration, you will see many "no neighbor X:X::X:X activate" line +in your configuration to disable IPv4 unicast NLRI exchange. In that +case please use "no bgp default ipv4-unicast" command to suppress the +output. Until zebra-0.93, old config is still left for compatibility. + +Old config +========== +router bgp 7675 + bgp router-id 10.0.0.1 + redistribute connected + network 192.168.0.0/24 + neighbor 10.0.0.2 remote-as 7675 + ipv6 bgp network 3ffe:506::/33 + ipv6 bgp network 3ffe:1800:e800::/40 + ipv6 bgp aggregate-address 3ffe:506::/32 + ipv6 bgp redistribute connected + ipv6 bgp neighbor 3ffe:506:1000::2 remote-as 1 + +New config +========== +router bgp 7675 + bgp router-id 10.0.0.1 + network 192.168.0.0/24 + redistribute connected + neighbor 10.0.0.2 remote-as 7675 + neighbor 3ffe:506:1000::2 remote-as 1 + no neighbor 3ffe:506:1000::2 activate +! + address-family ipv6 + network 3ffe:506::/33 + network 3ffe:1800:e800::/40 + aggregate-address 3ffe:506::/32 + redistribute connected + neighbor 3ffe:506:1000::2 activate + exit-address-family + +* Changes in ospfd + +** Internal interface treatment is changed. Now ospfd can handle +multiple IP address for an interface. + +** Redistribution of loopback interface's address works fine. + +* Changes in zebra-0.91 + +** --enable-oldrib configure option is removed. + +** HAVE_IF_PSEUDO part is removed. Same feature is now supported by +default. + +* Changes in ripd + +** When redistributed route is withdrawn, perform poisoned reverse. + +* Changes in zebra + +** When interface's address is removed, kernel route pointing out to +the address is removed. + +** IPv6 RIB is now based upon new RIB code. + +** zebra can handle same connected route to one interface. + +** New command for interface address. Currently this commands are +only supported on GNU/Linux with netlink interface. + +"ip address A.B.C.D secondary" +"ip address A.B.C.D label LABEL" + +* Changes in bgpd + +** BGP flap dampening bugs are fixed. + +** BGP non-blocking TCP connection bug is fixed. + +** "show ip bgp summary" shows AS path and community entry number. + +** New commands have been added. + "show ip bgp cidr-only" + "show ip bgp ipv4 (unicast|multicast) cidr-only" + "show ip bgp A.B.C.D/M longer-prefixes" + "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes" + "show ipv6 bgp X:X::X:X/M longer-prefixes" + "show ipv6 mbgp X:X::X:X/M longer-prefixes" + +** IPv6 IBGP nexthop change is monitored. + +** Unknown transitive attribute is passed with partial flag bit on. + +* Changes in ospfd + +** Fix bug of LSA MaxAge flood. + +** Fix bug of NSSA codes. + +* Changes in zebra-0.90 + +** From this beta release, --enable-unixdomain and --enable-newrib +becomes default. So both options are removed from configure.in. To +revert old behavior please specify below option. + +--enable-tcp-zebra # TCP/IP socket is used for protocol daemon and zebra. +--enable-oldrib # Turn on old RIB implementation. + +Old RIB implementation will be removed in zebra-0.91. + +** From this beta release --enable-multipath is supported. This +option is only effective on GNU/Linux kernel with +CONFIG_IP_ADVANCED_ROUTER and CONFIG_IP_ROUTE_MULTIPATH is set. + +--enable-multipath=ARG # ARG must be digit. When ARG is 0 unlimit multipath number. + +** From this release we do not include guile files. + +* Changes in lib + +** newlist.[ch] is merged with linklist.[ch]. + +** Now Zebra works on MacOS X public beta. + +** Access-list can have remark. "access-list WORD remark LINE" define +remark for specified access-list. + +** Key of key-chain is sorted by it's idetifier value. + +** prefix-list rule is slightly changed. The rule of "len <= ge-value +<= le-value" is changed to "len < ge-value <= le-value". + +** According to above prefix-list rule change, add automatic +conversion function of an old rule. ex.) 10.0.0.0/8 ge 8 -> 10.0.0.0/8 +le 32 + +** SMUX can handle SNMP trap. + +** In our event library, event thread is executed before any other +thread like timer, read and write event. + +** Robust method for writing configuration file and recover from +backing up config file. + +** Display "end" at the end of configuration. + +** Fix memory leak in vtysh_read(). + +** Fix memroy leak about access-list and prefix-list name. + +* Changes in zebra + +** UNIX domain socket server of zebra protocol is added. + +** Fix PointoPoint interface network bug. The destination network +should be installed into routing table instead of local network. + +** Metric value is reflected to kernel routing table. + +** "show ip route" display uptime of RIP,OSPF,BGP routes. + +** New RIB implementation is added. + +Now we have enhanced RIB (routing information base) implementation in +zebra. New RIB has many new features and fixed some bugs which exist +in old RIB code. + +*** Static route with distance value + + Static route can be specified with administrative distance. The + distance value 255 means it is not installed into the kernel. + Default value of distance for static route is 1. + + ip route A.B.C.D/M A.B.C.D <1-255> + ip route A.B.C.D/M IFNAME <1-255> + + If the least distance value's route's nexthop are unreachable, + select the least distance value route which has reachable nexthop is + selected. + + ip route 0.0.0.0/0 10.0.0.1 + ip route 0.0.0.0/0 11.0.0.1 2 + + In this case, when 10.0.0.1 is unreachable and 11.0.0.1 is + reachable. The route with nexthop 11.0.0.1 will be installed into + forwarding table. + + zebra> show ip route + S>* 0.0.0.0/0 [2/0] via 11.0.0.1 + S 0.0.0.0/0 [1/0] via 10.0.0.1 inactive + + If the nexthop is unreachable "inactive" is displayed. You can + specify any string to IFNAME. There is no need of the interface is + there when you configure the route. + + ip route 1.1.1.1/32 ppp0 + + When ppp0 comes up, the route is installed properly. + +*** Multiple nexthop routes for one prefix + + Multiple nexthop routes can be specified for one prefix. Even the + kernel support only one nexthop for one prefix user can configure + multiple nexthop. + + When you configure routes like below, prefix 10.0.0.1 has three + nexthop. + + ip route 10.0.0.1/32 10.0.0.2 + ip route 10.0.0.1/32 10.0.0.3 + ip route 10.0.0.1/32 eth0 + + If there is no route to 10.0.0.2 and 10.0.0.3. And interface eth0 + is reachable, then the last route is installed into the kernel. + + zebra> show ip route + S> 10.0.0.1/32 [1/0] via 10.0.0.2 inactive + via 10.0.0.3 inactive + * is directly connected, eth0 + + '*' means this nexthop is installed into the kernel. + +*** Multipath (more than one nexthop for one prefix) can be installed into the kernel. + + When the kernel support multipath, zebra can install multipath + routes into the kernel. Before doing that please make it sure that + setting --enable-multipath=ARG to configure script. ARG must be digit + value. When specify 0 to ARG, there is no limitation of the number + of the multipath. Currently only GNU/Linux with netlink interface is + supported. + + ip route 10.0.0.1/32 10.0.0.2 + ip route 10.0.0.1/32 10.0.0.3 + ip route 10.0.0.1/32 eth0 + + zebra> show ip route + S>* 10.0.0.1/32 [1/0] via 10.0.0.2 + * via 10.0.0.3 + is directly connected, eth0 + +*** Kernel message delete installed route. + + After zebra install static or dynamic route into the kernel. + + R>* 0.0.0.0/0 [120/3] via 10.0.0.1 + + If you delete this route outside zebra, old zebra does not reinstall + route again. Now the route is re-processed and properly reinstall the + static or dynamic route into the kernel. + +** GNU/Linux netlink socket handling is improved to fix race condition +between kernel message and user command responce. + +* Changes in bgpd + +** Add show neighbor's routes command. + + "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes" + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes" + "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes" + "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes" + +** BGP passive peer support problem is fixed. + +** Redistributed IGP nexthop is passed to BGP nexthop. + +** On multiaccess media, if the nexthop is reachable nexthop is passed +as it is. + +** Remove zebra-0.88 compatibility commands. + + "match ip prefix-list WORD" + "match ipv6 prefix-list WORD" + + Instead of above please use below commands. + + "match ip address prefix-list WORD" + "match ipv6 address prefix-list WORD" + +** Fix bug of holdtimer is not reset when bgp cleared. + +** "show ip bgp summary" display peer establish/drop count. + +** Change "match ip next-hop" argument from IP address to access-list +name. + +** When "bgp enforce-first-as" is enabled, check EBGP peer's update +has it's AS number in the first AS number in AS sequence. + +** New route-map command "set community-delete COMMUNITY-LIST" is +added. Community matched the CoMMUNITY-LIST is removed from the +community. + +** BGP-MIB implementation is finished. + +** When BGP connection comes from unconfigured IP address, close +socket immediately. + +** Do not compare router ID when the routes comes from EBGP peer. +When originator ID is same, take shorter cluster-list route. If +cluster-list is same take smaller IP address neighbor's route. + +** Add "bgp bestpath as-path ignore" command. When this option is +set, do not concider AS path length when route selection. + +** Add "bgp bestpath compare-routerid". When this option is set, +compare router ID when the routes comes from EBGP peer. + +** Add "bgp deterministic-med" process. + +** BGP flap dampening feature is added. + +** When IBGP nexthop is changed, it is reflected to RIB. + +** Change "neighbor route-refresh" command to "neighbor capability +route-refresh". + +* Changes in ripd + +** Change "match ip next-hop" argument from IP address to access-list +name. + +** "no ip rip (send|receive)" command accept version number argument. + +** Memory leak related classfull network generation is fixed. + +** When a route is in garbage collection process (invalid with metric +16) and a router receives the same route with valid metric then route +was not installed into zebra rib, but only into ripd rib. Moreover , +it will never get into zebra rib, because ripd wrongly assumes it's +already there. + +* Change in ospfd + +** Fix bug of refreshing default route. + +** --enable-nssa turn on undergoing NSSA feature. + +** Fix bug of Hello packet's option is not properly set when interface +comes up. + +** Reduce unconditional logging. + +** Add nexthop to OSPF path only when it is not there. + +** When there is no DR on network (suppose you have only one router +with interface priority 0). It's router LSA does not contain the link +information about this network. + +** When you change a priority of interface from/to 0 +ISM_NeighborChange event should be scheduled in order to elect new +DR/BDR on the network. + +** When we add some LSA into retransmit list we need to check whether +the present old LSA in retransmit list is not more recent than the new +one. + +** In states Loading and Full the slave must resend its last Database +Description packet in response to duplicate Database Description +packets received from the master. For this reason the slave must wait +RouterDeadInterval seconds before freeing the last Database +Description packet. Reception of a Database Description packet from +the master after this interval will generate a SeqNumberMismatch +neighbor event. RFC2328 Section 10.8 + +** Virtual link can not configured in stub area. + +** Clear a ls_upd_queue queue of the interface when interface goes +down. + +** "no router ospf" unregister redistribution requests from zebra. + +** New command for virtual-link configuration is added. + + "area A.B.C.D virtual-link A.B.C.D" + "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535>" + "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535> authentication-key AUTH_KEY" + "area A.B.C.D virtual-link A.B.C.D authentication-key AUTH_KEY" + "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535> message-digest-key <1-255> md5 KEY" + "area A.B.C.D virtual-link A.B.C.D message-digest-key <1-255> md5 KEY" + +** Clear cryptographic sequence number when neighbor status is changed +to NSM down. + +** Make Summary LSA's origination and refreshment as same as other +type of LSA. + +** New OSPF pakcet read method. Now maximum packet length may be 65535 +bytes (maximum IP packet length). + +** Checking the age of the found LSA and if the LSA is MAXAGE we +should call refresh instead of originate. + +** Install multipath information to zebra. + +** Fix socket descriptor leak when system call failed. + +* Changes in ospf6d + +** Whole functionality has been rewritten as new code. new command +"show ipv6 ospf6 spf node", "show ipv6 ospf6 spf tree", "show ipv6 +ospf6 spf table" has been added. + +** Change to do not send garbage route whose nexthop is not linklocal +address. + +** "redistribute ospf6" was generated in "router ospf6" in config +file. It is fixed. + +** LSDB sync bug is fixed. + +** Fix bug of using unavailable route. + +* Changes in vtysh + +** route-map and access-list configuration is merged into one +configuration. + +** /usr/local/etc/Zebra.conf is integrated configuration file. "write +memory" in vtysh will write whole configuration to this file. + +** When -b option is specified to vtysh, vtysh read +/usr/local/etc/Zebra.conf file then pass the confuguration to proper +protocol daemon. So make all protocol daemon's configuration file +empty then invoke all daemon. After that vtysh -b will setup saved +configuration. + +zebrastart.sh +============= +/usr/local/sbin/zebra -d +/usr/local/sbin/ripd -d +/usr/local/sbin/ospfd -d +/usr/local/sbin/bgpd -d +/usr/local/bin/vtysh -b + +* Changes in zebra-0.89 + +* Changes in lib + +** distribute-list can set all interface's access-list and prefix-list +configuration. + +* Changes in ripd + +** "show ip protocols" display proper distribute-list settings and +distance settings. + +** When metric infinity route received withdraw the route from kernel +immediately it used to be wait garbage collection. + +** key-chain can be used for simple password authentication. + +** RIPv2 MIB getnext interface bug is fixed. + +* Changes in vtysh + +** --with-libpam enable PAM authentication for vtysh. + +** Now vtysh read vtysh.conf. This file should be +${SYSCONFDIR}/etc/vtysh.conf for security reason. Usually it is +/usr/local/etc/vtysh.conf. + +** "username WORD nopassword" command is added to vtysh. + +* Chagees in ospfd + +** NBMA interface support is added. + +** OSPF area is sorted by area ID. + +** New implementation of OSPF refreesh. + +** OSPF-MIB read function is partly added. + +* Changes in bgpd + +** When the peering is done by ebgp-multihop, nexthop is looked up +like IBGP routes. + +** "show ip mbgp" commands are changed to "show ip bgp ipv4 +multicast". + +** New terminal commands are added. + "show ip bgp ipv4 (unicast|multicast) filter-list WORD" + "show ip bgp ipv4 (unicast|multicast) community" + "show ip bgp ipv4 (unicast|multicast) community-list WORD" + "show ip bgp ipv4 (unicast|multicast) community-list WORD exact-match" + +** MBGP soft-reconfiguration command is added. + "clear ip bgp x.x.x.x ipv4 (unicast|multicast) in" + "clear ip bgp x.x.x.x ipv4 (unicast|multicast) out" + "clear ip bgp x.x.x.x ipv4 (unicast|multicast) soft" + "clear ip bgp <1-65535> ipv4 (unicast|multicast) in" + "clear ip bgp <1-65535> ipv4 (unicast|multicast) out" + "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft" + "clear ip bgp * ipv4 (unicast|multicast) in" + "clear ip bgp * ipv4 (unicast|multicast) out" + "clear ip bgp * ipv4 (unicast|multicast) soft" + +** MED related commands are added. + "bgp deterministic-med" + "bgp bestpath med confed" + "bgp bestpath med missing-as-worst" + +** "bgp default local-preference" command is added. + +** BGP confederation peer's routes are passed to zebra like IBGP route. + +** Community match command is added. + "show ip bgp community " + "show ip bgp community exact-match" + +** EBGP multihop route treatment bug is fixed. Now nexthop is +resolved by IGP routes. + +** Some commands are added to show routes by filter-list and community +value. + "show ip bgp ipv4 (unicast|multicast) filter-list WORD" + "show ip bgp ipv4 (unicast|multicast) community" + "show ip bgp ipv4 (unicast|multicast) community-list WORD" + "show ip bgp ipv4 (unicast|multicast) community-list WORD exact-match" + +* Changes in zebra + +** zebra read interface's address information using getifaddrs() when +it is available. + +** Reflect IPv6 interface's address change to protocol daemons. + +* Changes in zebra-0.88 + +* Changes in lib + +** "exact-match" option is added to "access-list" and "ipv6 +access-list" command. If this option is specified, the prefix and +prefix length is compared as exact match mode. + +* Changes in zebra + +** New Zebra message ZEBRA_REDISTRIBUTE_DEFAULT_ADD and +ZEBRA_REDISTRIBUTE_DEFAULT_DELTE are added. + +** Default administrative distance value is changed. + + Old New +------------------------------------------ +system 10 0 +kernel 20 0 +connected 30 0 +static 40 1 +rip 50 120 +ripng 50 120 +ospf 60 110 +ospf6 49 110 +bgp 70 200(iBGP) 20(eBGP) +------------------------------------------ + +** Distance value can be passed from protocol daemon to zebra. + +** "show ip route" shows [metric/distance] value pair. + +** Zebra Protocol is changed to support multi-path route and distance +value. + +* Changes in ospfd + +** "default-information originate [always]" command is added. + +** "default-metric <0-16777214>" command is added. + +** "show ip ospf database" command is integrated. LS-ID and AdvRouter can + be specifed. The commands are + + show ip ospf database TYPE LS-ID + show ip ospf database TYPE LS-ID ADV-ROUTER + show ip ospf database TYPE LS-ID self-originate + show ip ospf database TYPE self-originate + +** route-map support for `redistribute' command are added. + Supported `match' statements are + + match interface + match ip address + match next-hop + + Supported `set' statements are + + set metric + set metric-type + +** Pass OSPF metric value to zebra daemon. + +* Changes in ripd + +** When specified route-map does not exist, it means all deny. + +** "default-metric <1-16>" command is added. + +** "offset-list ACCESS-LIST-NAME <0-16>" and "offset-list +ACCESS-LIST-NAME <0-16> IFNAME" commands are added. + +** "redistribute ROUTE-TYPE metric <0-16>" command is added. + +** "default-information originate" command is added. + +** "ip split-horizon" and "no ip split-horizon" is added to interface +configuration. + +** "no router rip" command is added. + +** "ip rip authentication mode (md5|text)" is added to interface +configuration. + +** "ip rip authentication key-chain KEY-CHAIN" is added to interface +configuration. + +** Pass RIP metric value to zebra daemon. + +** Distance manipulation functions are added. + +* Changes in bgpd + +** Fix bug of next hop treatment for MPLS-VPN route exchange. + +** BGP peer MIB is updated. + +** Aggregated route has origin IGP, atomic-aggregate and proper +aggregator attribute. + +** Suppressed route now installed into BGP table. It is only +suppressed from announcement. + +** BGP router-id is properly set after "no router bgp ASN" and "router +bgp ASN". + +** Add check for nexthop is accessible or not for IBGP routes. + +** Add cehck for nexthop is on connected or not for EBGP routes. + +** "dump bgp route" command is changed to "dump bgp route-mrt" for +generating MRT compatible dump output. + +** Soft reconfiguration inbound and outbound is supported. + +** Route refresh feature is supported. + +* Changes in vtysh + +** VTY shell is now included into the distribution. + +* Changes in zebra-0.87 + +* Changes in lib + +** "show startup-config" command is added. + +** "show history" command is added. + +** Memory statistics command is changed. New command + + show memory all + show memory lib + show memory rip + show memory ospf + show memory bgp + +are added. + +** Filters can be removed only specify it's name. New command + + no access-list NAME + no ip community-list NAME + no ip as-path access-list NAME + no route-map NAME + +are added. + +** At any node, user can view/save user configuration. + + write terminal + write file + wirte memory + +are added to every node in default. + +** LCD completion is added. For example both "ip" and "ipv6" command +are exist, "i" then press TAB will be expanded to "ip". + +* Changes in bgpd + +** "show ip bgp" family shows total number of prefixes. + +** "no bgp default ipv4-unicast" command is added. + +** Extended Communities support is added. + +** "no neighbor PEER send-community extended" command is added. + +** MPLS-VPN PE-RR support is added. + + New address family vpnv4 unicast is introduced. + + ! + address-family vpnv4 unicast + neighobr PEER activate + network A.B.C.D rd RD tag TAG + exit-address-family + ! + + To make it route-reflector, please configure it under normal router +bgp ASN. + + ! + router bgp 7675 + no bgp default ipv4-unicast + bgp router-id 10.0.0.100 + bgp cluster-id 10.0.0.100 + neighbor 10.0.0.1 remote-as 65535 + neighbor 10.0.0.1 route-reflector-client + neighbor 10.0.0.2 remote-as 65535 + neighbor 10.0.0.2 route-reflector-client + neighbor 10.0.0.3 remote-as 65535 + neighbor 10.0.0.3 route-reflector-client + ! + address-family vpnv4 unicast + neighbor 10.0.0.1 activate + neighbor 10.0.0.2 activate + neighbor 10.0.0.3 activate + exit-address-family + ! + +* Changes in ospfd + +** Many many bugs are fixed. + +* Changes in ripd + +** Better interface up/down event handle. + +* Changes in zebra + +** Better interface up/down event handle. + +* Changes in zebra-0.86 + +* Changes in lib + +** Fix bug of exec-timeout command which may cause crush. + +** Multiple same policy for "access-list", "ip prefix-list, "as-path +access-list", "ip community-list" is not duplicated. + +** It used to be "ip prefix-list A.B.C.D/M" match routes which mask >= +M. Now default behavior is exact match so it only match routes which +mask == M. + +* Changes in bgpd + +** "match ip address prefix-list" is added to route-map. + +** A route without local preference is evaluated as 100 local preference. + +** Select smaller router-id route when other values are same. + +** Compare MED only both routes comes from same neighboring AS. + +** "bgp always-compare-med" command is added. + +** Now MED value is passed to IBGP peer. + +** When neighbor's filter is configured with non-existent access-list, +as-path access-list, ip prefix-list, route-map. The behavior is +changed from all permit to all deny. + +* Changes in ospfd + +** Fix bug of external route tag byte order. + +** OSPF Neighbor deletion bug which cause crush is fixed. + +** Some route calculation bug are fixed. + +** Add sanity check with router routing table. + +** Fix bug of memory leak about linklist. + +** Fix bug of 1-WayReceived in NSM. + +** Take care of BIGENDIAN architecture. + +** Fix bug of NSM state flapping between ExStart and Exchange. + +** Fix bug of Network-LSA originated in stub network. + +** Fix bug of MS flag unset. + +** Add to schedule router_lsa origination when the interface cost +changes. + +** Increment LS age by configured interface transmit_delay. + +** distribute-list is reimplemented. + +** Fix bug of refresh never occurs. + +** Fix bug of summary-LSAs reorigination. Correctly copy +OSPF_LSA_APPROVED flag to new LSA. when summary-LSA is reoriginatd. + +** Fix bug of re-origination when a neighbor disappears. + +** Fix bug of segmentation fault with DD retransmission. + +** Fix network-LSA re-origination problem. + +** Fix problem of remaining withdrawn routes on zebra. + +* Changes in ripd + +** Do not leave from multicast group when interface goes down bug is +fixed. + +* Changes in zebra + +** Remove client structure when client dies. + +** Take care static route when interface goes up/down. + +* Changes in zebra-0.85 + +* Changes in bgpd + +** "transparent-nexthop" and "transparenet-as" commands are added. + +** Route reflector's originator-id bug is fixed. + +* Changes in ospfd + +** Fix bug of OSPF LSA memory leak. + +** Fix bug of OSPF external route memory leak. + +** AS-external-LSA origination bug was fixed. + +** LS request treatment is completely rewritten. Now performance is +drastically improved. + +* Changes in ripd + +** RIPv1 update is done by class-full manner. + +* Changes in zebra-0.84b + +* Changes in lib + +** Fix bug of inet_pton return value handling + +* Changes in bgpd + +** Fix bug of BGP-4+ link-local address nexthop check for IBGP peer. + +** Don't allocate whole buffer for displaying "show ip bgp". Now it +consume only one screen size memory. + +* Changes in ripd + +** Fix debug output string. + +** Add RIP peer handling. RIP peer are shown by "show ip protocols". + +* Changes in zebra-0.84a + +* Changes in bgpd + +** Fix serious bug of BGP-4+ peering under IPv6 link-local address. + Due to the bug BGP-4+ peering may not be established. + +* Changes in zebra-0.84 + +* Changes in lib + +** IPv6 address and prefix parser is added to VTY by Toshiaki Takada + . DEFUN string is "X:X::X:X" for IPv6 address, + "X:X::X:X/M" for IPv6 prefix. You can use it like this. + + DEFUN (func, cmd, "neighbor (A.B.C.D|X:X::X:X) remote-as <1-65535>") + +** VTY configuration is locked during configuration. This is for + avoiding unconditional crush from two terminals modify the + configuration at the same time. "who" command shows which termnal + lock the configuration. VTY which has '*' character at the head of + line is locking the configuration. + +** Old logging functions are removed. Functions like + log_open,log_close,openlog are deleted. Instead of that please use + zlog_* functions. zvlog_* used in ospf6d are deleted also. + +** "terminal monitor" command is added. "no terminal monitor" is for + disabling. This command simply display logging information to the + VTY. + +** dropline.[ch] files are deleted. + +* Changes in bgpd + +** BGP neighbor configuration are sorted by it's IP address. + +** BGP peer configuration and actual peer is separated. This is + preparation for Route Server support. + +** "no neighbor PEER" command is added. You can delete neighbor + without specifying AS number. + +** "no neighbor ebgp-multihop" command is added. + +** "no neighbor port PORT" command is added. + +** To conform RFC1771, "neighbor PEER send-community" is default + behavior. If you want to disable sending community attribute, + please specify "no neighbor PEER send-community" to the peer. + +** "neighbor maximum-prefix NUMBER" command is added. + +** Multi-protocol extention NLRI is proceeded only when the peer is + configured proper Address Family and Subsequent Address Family. If + not, those NLRI are simply ignored. + +** Aggregate-address support is improved. Currently below commands + works. + + "aggregate-address" + "aggregate-address summary-only" + "no aggregate-address" + "no aggregate-address summary-only" + + "ipv6 bgp aggregate-address" + "ipv6 bgp aggregate-address summary-only" + "no ipv6 bgp aggregate-address" + "no ipv6 bgp aggregate-address summary-only" + +** redistribute route-map bug is fixed. + +** MBGP support becomes default. "configure" option --enable-mbgp is + removed. + +** New command "neighbor PEER timers connect <1-65535>" is added. + +** New command "neighbor PEER override-capability" is added. + +** New command "show ip bgp neighbor A.B.C.D advertised-route" is added. + +** New command "show ip bgp neighbor A.B.C.D routes" is added. To use + this command, you have to configure neighbor with + "neighbor A.B.C.D soft-reconfiguration inbound" beforehand. + + +* Changes in zebra-0.83 + +* bgpd + +** Serious bug fix about fetching global and link-local address at the +same time. Due to this bug, corrupted IPv6 prefix is generated. If +you uses bgpd for BGP-4+ please update to this version. The bug is +introduced in zebra-0.82. + +** When bgpd send Notify message, don't use thread manager. It is now +send to neighbor immediately. + +* Changes in zebra-0.82 + +** Solaris 2.6 support is added by Michael Handler +. + +** MBGP support is added by Robert Olsson . +Please specify --enable-mbgp to configure script. This option will be +removed in the future and MBGP support will be default. + +* Changes in zebra + +** When interface goes down, withdraw connected routes from routing +table. When interface goes up, restore the routes to the routing +table. + +** `show interface' show interface's statistics on Linux and BSD with +routing socket. + +** Now zebra can get MTU value on BSDI/OS. + +* Changes in bgpd + +** Add capability option support based upon +draft-ietf-idr-bgp4-cap-neg-04.txt. + +** Add `show ipv6 bgp prefix-list' command. + +** Check self AS appeared in received routes. + +** redistribute route-map support is added. + +** BGP packet dump feature compatible with MRT. + +* Changes in ripd + +** Fix bug of `timers basic' command's argument format. + +* Changes in ripngd + +** Calculate max RTE using interface's MTU value. + +* Changes in ospfd + +** Some correction to LSU processing. + +** Add check for lsa->refresh_list. + +* Changes in ospf6d + +** Many debug feature is added. + +* Changes in zebra-0.81 + +** SNMP support is disabled in default.--enable-snmp option is added +to configure script. + +* Changes in bgpd + +** Fix FSM bug which introduced in zebra-0.80. + +* Changes in zebra-0.80 + +* access-list + + New access-list name space `ipv6 access-list' is added. At the same + time, `access-list' statemant only accepts IPv4 prefix. Please be + careful if you use IPv6 filtering. You will need to change your + configuration. For IPv6 filtering please use `ipv6 access-list'. + + As of zebra-0.7x, user can use `access-list' for both IPv4 and IPv6 + filtering. + + ! zebra-0.7x + access-list DML-net permit 203.181.89.0/24 + access-list DML-net permit 3ffe:506::0/32 + access-list DML-net deny any + ! + + Above configuration is not valid for zebra-08x. Please add `ipv6' + before 'access-list' when you configure IPv6 filtering. + + ! zebra-0.8x + access-list DML-net permit 203.181.89.0/24 + access-list DML-net deny any + ! + ipv6 access-list DML-net permit 3ffe:506::0/32 + ipv6 access-list DML-net deny any + ! + +* prefix-list + + And also new prefix-list name space `ipv6 prefix-list' is added. It + is the same as the change of `access-list'. `ip prefix-list' now only + accept IPv4 prefix. It was source of confusion that `ip prefix-list' + can be used both IPv4 and IPv6 filtering. Now name space is separated + to clear the meaning of the filter. + + If you use `ip prefix-list' for IPv6 filtering, please change the + stetement. + + ! zebra-0.7x + ip prefix-list 6bone-filter seq 5 permit 3ffe::/17 le 24 ge 24 + ip prefix-list 6bone-filter seq 10 permit 3ffe:8000::/17 le 28 ge 28 + ip prefix-list 6bone-filter seq 12 deny 3ffe::/16 + ip prefix-list 6bone-filter seq 15 permit 2000::/3 le 16 ge 16 + ip prefix-list 6bone-filter seq 20 permit 2001::/16 le 35 ge 35 + ip prefix-list 6bone-filter seq 30 deny any + ! + + Now user can explicitly configure it as IPv6 prefix-list. + + ! zebra-0.8x + ipv6 prefix-list 6bone-filter seq 5 permit 3ffe::/17 le 24 ge 24 + ipv6 prefix-list 6bone-filter seq 10 permit 3ffe:8000::/17 le 28 ge 28 + ipv6 prefix-list 6bone-filter seq 12 deny 3ffe::/16 + ipv6 prefix-list 6bone-filter seq 15 permit 2000::/3 le 16 ge 16 + ipv6 prefix-list 6bone-filter seq 20 permit 2001::/16 le 35 ge 35 + ipv6 prefix-list 6bone-filter seq 30 deny any + ! + +* RIP configuration + + If you want to filter only default route (0.0.0.0/0) and permit other + routes, it was hard to do that. Now `ip prefix-list' can be used for + RIP route filtering. + + New statement: + + `distribute-list prefix PLIST_NAME (in|out) IFNAME' + + is added to ripd. So you can configure on eth0 interface accept all + routes other than default routes. + + ! + router rip + distribute-list prefix filter-default in eth0 + ! + ip prefix-list filter-default deny 0.0.0.0/0 le 0 + ip prefix-list filter-default permit any + ! + +* RIPng configuration + + Same change is done for ripngd. You can use `ipv6 prefix-list' for + filtering. + + ! + router ripng + distribute-list prefix filter-default in eth0 + ! + ipv6 prefix-list filter-default deny ::/0 le 0 + ipv6 prefix-list filter-default permit any + ! + +* BGP configuration + + So far, Multiprotocol Extensions for BGP-4 (RFC2283) configuration is + done with traditional IPv4 peering statement like blow. + + ! + router bgp 7675 + neighbor 3ffe:506::1 remote-as 2500 + neighbor 3ffe:506::1 prefix-list 6bone-filter out + ! + + For separating configuration IPv4 and IPv6, and for retaining Cisco + configuration compatibility, now IPv6 configuration is done by IPv6 + specific statement. IPv6 BGP configuration is done by statement which + start from `ipv6 bgp'. + + ! + router bgp 7675 + ! + ipv6 bgp neighbor 3ffe:506::1 remote-as 2500 + ipv6 bgp neighbor 3ffe:506::1 prefix-list 6bone-filter out + ! + + At the same time some IPv6 specific commands are deleted from IPv4 + configuration. + + o redistribute ripng + o redistribute ospf6 + o neighbor PEER version BGP_VERSION + o neighbor PEER interface IFNAME + + Those commands are only accepted as like below. + + o ipv6 bgp redistribute ripng + o ipv6 bgp redistribute ospf6 + o ipv6 bgp neighbor PEER version BGP_VERSION + o ipv6 bgp neighbor PEER interface IFNAME + + And below new commands are added. + + o ipv6 bgp network IPV6_PREFIX + o ipv6 bgp redistribute static + o ipv6 bgp redistribute connected + o ipv6 bgp neighbor PEER remote-as <1-65535> [passive] + o ipv6 bgp neighbor PEER ebgp-multihop [TTL] + o ipv6 bgp neighbor PEER description DESCRIPTION + o ipv6 bgp neighbor PEER shutdown + o ipv6 bgp neighbor PEER route-reflector-client + o ipv6 bgp neighbor PEER update-source IFNAME + o ipv6 bgp neighbor PEER next-hop-self + o ipv6 bgp neighbor PEER timers holdtime <0-65535> + o ipv6 bgp neighbor PEER timers keepalive <0-65535> + o ipv6 bgp neighbor PEER send-community + o ipv6 bgp neighbor PEER weight <0-65535> + o ipv6 bgp neighbor PEER default-originate + o ipv6 bgp neighbor PEER filter-list FILTER_LIST_NAME (in|out) + o ipv6 bgp neighbor PEER prefix-list PREFIX_LIST_NAME (in|out) + o ipv6 bgp neighbor PEER distribute-list AS_LIST_NAME (in|out) + o ipv6 bgp neighbor PEER route-map ROUTE_MAP_NAME (in|out) + + And some utility commands are introduced. + + o clear ipv6 bgp [PEER] + o show ipv6 bgp neighbors [PEER] + o show ipv6 bgp summary + + I hope these changes are easy to understand for current Zebra users... + +* To restrict connection to VTY interface. + + It used to be both IPv4 and IPv6 filter can be specified with one + access-list. Then the access-list can be appried to VTY interface + with `access-class' stetement in `line vty' node. Below is example in + zebra-0.7x. + + ! + access-list local-only permit 127.0.0.1/32 + access-list local-only permit ::1/128 + access-list local-only deny any + ! + line vty + access-class local-only + ! + + Now IPv4 and IPv6 filter have each name space. It is not possible to + specify IPv4 and IPv6 filter with one access-list. For setting IPv6 + access-list in `line vty', `ipv6 access-class' statement is + introduced. Let me show the configuration in zebra-0.8x. + + ! + access-list local-only permit 127.0.0.1/32 + access-list local-only deny any + ! + ipv6 access-list local-only permit ::1/128 + ipv6 access-list local-only dny any + ! + line vty + access-class local-only + ipv6 access-class local-only + ! + +* route-map + + New IPv6 related route-map match commands are added. + + o match ipv6 address + o match ipv6 next-hop + + Please change your configuration if you use IP match statement for + IPv6 route. + + zebra-0.7x config + ================= + ! + access-list all permit any + ! + route-map set-nexthop permit 10 + match ip address all + set ipv6 next-hop global 3ffe:506::1 + set ipv6 next-hop local fe80::cbb5:591a + ! + + zebra-0.8x config + ================= + ! + ipv6 access-list all permit any + ! + route-map set-nexthop permit 10 + match ipv6 address all + set ipv6 next-hop global 3ffe:506::1 + set ipv6 next-hop local fe80::cbb5:591a + ! + +* zebra connection + + Protocol daemon such as ripd, bgpd, ospfd will reconnect zebra daemon + when the connection fail. Those daemons try to connect zebra every 10 + seconds first three trial, then the interval changed to 60 seconds. + After all, if ten connections are fail, protocol daemon give up the + connection to the zebra daemon. + +* SNMP support (is not yet finished) + + Zebra uses SMUX protocol (RFC1227) for making communication with SNMP + agent. Currently lib/smux.c can be compiled only with ucd-snmp-4.0.1 + and http://ucd-snmp.ucdavis.edu/patches/012.patch. It can not be + compiled with ucd-snmp-3.6.2. + + After applying the patch to ucd-snmp-4.0.1, please configure it with + SMUX module. + + % configure --with-mib-modules=smux + + After compile & install ucd-snmp-4.0.1, you will need to configure + smuxpeer. I'm now using below configuration. + + /usr/local/share/snmp/snmpd.conf + ================================ + smuxpeer 1.3.6.1.6.3.1 test + + Above 1.3.6.1.6.3.1 and test is temporary configuration which is hard + coded in lib/smux.c. Yes, I know it is bad, I'll change it ASAP. + +* HUP signal treatment + + From zebra-0.80, ripd will reload it's configuration file when ripd + receives HUP signal. Other daemon such as bgpd, ospfd will support + HUP signal treatment soon. + +* Changes in zebra-0.79 + +* Changes in zebra + +** Broadcast address setting on Linux box bug is fixed. + +** Protocol daemon can install connected IPv6 route into the kernel. + +** Now zebra can handle blackhole route. + +* Changes in ripd + +** Add route-map feature for RIP protocol. + +** In case of RIP version 2 routing table entry has IPv4 address and +netmask pair which host part bit is on, ignore the entry. + +* Changes in ripngd + +** Change CMSG_DATA cast from (u_char *) to (int *). (u_char *) does +not work for NetBSD-currnet on SparcStation 10. + +* Changes in ospfd + +** MaxAge LSA treatment is added. + +** ABR/ASBR functionality is added. + +** Virtual Link funtionality is added. + +** ABR behaviors IBM/Cisco/Shortcut is added. + +* Changes in ospf6d + +** Enclosed KAME specific part with #ifdef #endif + +* Changes in zebra-0.78 + +* Changes in lib + +** SNMP support is started. + +** Now Zebra can work on BSD/OS 4.X. + +** Now Zebra can compiled on vanilla OpenBSD 2.5 but not yet working correcltly. + +* Changes in zebra + +** Interface index detection using ioctl() bug is fixed. + +** Interface information protocol is changed. Now interface +addition/deletion and interface's address addition/deletion is +separated. + +* Changes in bgpd + +** BGP hold timer bug is fixed. + +** BGP keepavlie timer becomes configurable. + +* Changes in ripd + +** When making reply to rip's REQUEST message, fill in +RIP_METRIC_INFINITY with network byte order using htonl (). + +** Pass host byte order address to IN_CLASSC and IN_CLASSB macro. + +* Changes in ospfd + +** LSA flooding works. + +** Fix bug of DD processing. + +** Fix bug of originating router-LSA bug is fixed. + +** LSA structure is changed to support LSA aging. + +* Changes in ospf6d + +** `ip6' statement in configuration is changed to `ipv6'. + +* Changes in zebra-0.77 + +* Changes in lib + +** SIGUSR1 reopen logging file. + +** route-map is extended to support multi-protocol routing +information. + +** When compiling under GNU libc 2.1 environment don't use inet6-apps. + +* Changes in zebra + +** Basic IPv6 router advertisement codes added. It is not yet usable. + +** Fix IPv6 route addition/deletion bug is fixed. + +** `show ip route A.B.C.D' works + +* Changes in bgpd + +** When invalid unfeasible routes length comes, bgpd send notify then +continue to process the packet. Now bgpd stop parsing invalid packet +then return to main loop. + +** BGP-4+ withdrawn routes parse bug is fixed. + +** When BGP-4+ information passed to non shared network's peer, trim +link-local next-hop information. + +** `no redistribute ROUTE_TYPE' withdraw installed routes from BGP +routing information. + +** `show ipv6 route IPV6ADDR' command added. + +** BGP start timer has jitter. + +** Holdtimer configuration bug is fixed. Now configuration does not +show unconfigured hold time value. + +* Changes in ripngd + +** Now update timer (default 30 seconds) has +/- 50% jitter value. + +** Add timers basic command. + +** `network' configuration is dynamically reflected. + +** `timers basic ' added. + +* Changes in ripd + +** Reconstruct almost codes. + +** `network' configuration is dynamically reflected. + +** RIP timers now conforms to RFC2453. So user can configure update, +timeout, garbage timer. + +** `timers basic ' works. + +* Changes in ospfd + +** Bug of originating network LSA is fixed. + +** `no router ospf' core dump bug is fixed. + +* Changes in ospf6d + +** Redistribute route works. + +* Changes in zebra-0.76 + +* Changes in lib + +** configure.in Linux IPv6 detection problem is fixed. + +** Include SERVICES file to the distribution + +** Update zebra.texi to zebra-0.76. + +* Changes in zebra-0.75 + +* Changes in lib + +** `termnal length 0' bug is fixed. + +* Changes in zebra + +** When zebra starts up, sweep all zebra installed routes. If -k or +--keep_kernel option is specified to zebra dameon. This function is +not performed. + +* Changes in ripngd + +** Aggreagte address command supported. In router ripngd, +`aggregate-address IPV6PREFIX' works. + +* Changes in bgpd + +** Input route-map's bug which cause segmentation violation is fixed. + +** route-map method improved. + +** BGP-4+ nexthop detection improved. + +** BGP-4+ route re-selection bug is fixed. + +** BGP-4+ iBGP route's nexthop calculation works. + +** After connection Established `show ip bgp neighbor' display BGP TCP +connection's source and destination address. + +** In case of BGP-4+ `show ip bgp neighbor' display BGP-4+ global and +local nexthop which used for originated route. This address will be +used when `next-hop-self'. + +* Changes in ospfd + +** Fix bug of DR election. + +** Set IP precedence field with IPTOS_PREC_INTERNET_CONTROL. + +** Schedule NeighborChange event if NSM status change. + +** Never include a neighbor in Hello packet, when the neighbor goes +down. + +* Changes in zebra-0.74 + +* Changes in lib + +** Now `terminal length 0' means no line output control. + +** `line LINES' command deleted. Instead of this please use `terminal +length <0-512>'. + +** `terminal length <0-512>' is each vty specific configuration so it +can not be configured in the configuration file. If you want to +configure system wide line control, please use `service +terminal-length <0-512>'. This configuration affects to the all vty +interface. + +* Changes in zebra + +** Installation of IPv6 route bug is fixed. + +* Changes in bgpd + +** Very serious bug of bgp_stop () is fixed. When multiple route to +the same destination exist, bgpd try to announce the information to +stopped peer. Then add orphan write thread is added. This cause +many strange behavior of bgpd. + +** Router-id parsing bug is fixed. + +** With BGP-4+ nexthop installation was done with global address but +it should be link-local address. This bug is fixed now. + +** When incoming route-map prepend AS, old AS path remained. Now bgpd +free old AS path. + +** `neighbor PEER weight <0-65535>' command added. + +* Changes in ripngd + +** Almost codes are rewritten to conform to RFC2080. + +* Changes in ospfd + +** SPF calculation timer is added. Currently it is set to 30 seconds. + +** SPF calculation works now. + +** OSPF routing table codes are added. + +** OSPF's internal routes installed into the kernel routing table. + +** Now `ospfd' works as non-area, non-external route support OSPF +router. + +** Call of log_rotate() is removed. + +* Changes in ospf6d + +** LSA data structure is changed. + +** Call of log_rotate() is removed. + +* Changes in zebra-0.73 + +* Changes in lib + +** `config terminal' is changed to `configure terminal'. + +** `terminal length <0-512>' command is added. + +** Variable length argument was specified by `...'. Now all strings +started with character `.' is variable length argument. + +* Changes in zebra + +** Internal route (such as iBGP, internal OSPF route) handling works +correctly. + +** In interface node, `ipv6 address' and `no ipv6 address' works. + +** Interface's address remain after `no ip address' bug is fixed. + +** Host route such as IPv4 with /32 mask and IPv6 with /128 mask +didn't set RTF_GATEWAY even it has gateway. This bug if fixed now. + +* Changes in bgpd + +** `match as-path' argument is used to be specify AS PATH value itself +directly (e.g. ^$). But it is changed to specify `ip as-apth +access-list' name. + +** iBGP route handle works without getting error from the kernel. + +** `set aggregator as AS A.B.C.D' command is added to route-map. + +** `set atomic-aggregate' command is added to bgpd's routemap. + +** Announcement of atomic aggregate attribute and aggregator attribute +works. + +** `update-source' bug is fixed. + +** When a route learned from eBGP is announced to iBGP, local +preference was set to zero. But now it set to +DEFAULT_LOCAL_PREF(100). + +* Changes in ripd + +** RIPv1 route filter bug is fixed. + +** Some memory leak is fixed. + +* Changes in ospfd + +** Fix bug of DR Election. + +** Fix bug of adjacency forming. + +* Changes in ospf6d + +** Clean up logging message. + +** Reflect routing information to zebra daemon. + +* Changes in zebra-0.72 + +* Changes in lib + +** When getsockname return IPv4 mapped IPv6 address. Convert it to +IPv4 address. + +* Changes in bgpd + +** Change route-map's next-hop related settings. + +set ip nexthop -> set ip next-hop +set ipv6 nexthop global -> set ipv6 next-hop global +set ipv6 nexthop local -> set ipv6 next-hop local + +** Add `next-hop-self' command. + +* Changes in ospfd + +** Fix bug of multiple `network area' directive crashes. + +* Changes in zebra-0.71 + +* Changes in lib + +** `log syslog' command is added. + +** Use getaddrinfo function to bind IPv4/IPv6 server socket. + +** `no banner motd' will suppress motd output when user connect to VTY. + +** Bind `quit' command to major nodes. + +* Changes in zebra + +** Point-to-point link address handling bug is fixed. + +* Changes in bgpd + +** AS path validity check is added. If malformed AS path is received +NOTIFY Malformed AS path is send to the peer. + +** Use getaddrinfo function to bind IPv4/IPv6 server socket. + +* Changes in ripd + +** Connected network announcement bug is fixed. + +** `broadcast' command is deleted. + +** `network' command is added. + +** `neighbor' command is added. + +** `redistribute' command is added. + +** `timers basic' command is added. + +** `route' command is added. + +* Changes in ripngd + +** Fix metric calculation bug. + +* Changes in ospfd + +** Check sum bug is fixed. + +* Chanegs in ospf6d + +** Routing table code is rewritten. + +* Changes in zebra-0.70 + +* Changes in zebra + +** Critical routing information base calculation bug check is fixed. + +** zebra ipv4 message is extended to support external/internal route +flavor. + +** Now if internal route doesn't has direct connected nexthop, then +nexthop is calculated by looking up IGP routing table. + +* Changes in bgpd + +** `neighbor PEER update-source IFNAME' command added as ALIAS to +`neighbor PEER interface IFNAME'. + +* Changes in ospfd + +** DD null pointer bug is fixed. + +* Changes in zebra-0.69 + +* Changes in zebra + +** zebra redistirbution supports dynamic notification of the route +change. If you add static route while running zebra, it will be +reflected to other protocol daemon which set `redistribute static'. + +** If static route installation is failed due to the error. The +static route is not added to the configuration and zebra routing +table. + +** zebra sets forwarding flag to on when it starts up. + +** `no ip forwarding' turn off IPv4 forwarding. + +** `no ipv6 forwarding' turn off IPv6 forwarding. + +** Change `show ipforward' command to `show ip forwarding'. + +** Change `show ipv6forward' command to `show ipv6 forwarding'. + +** `ip route A.B.C.D/M INTERFACE' works. So you can set `ip route +10.0.0.0/8 eth0'. + +* Changes in bgpd + +** `neighbor PEER send-community' command is added. If the option is +set, bgpd will send community attribute to the peer. + +** When a BGP route has no-export community attribute and +send-community is set to the peer, the route is not announced to the +peer. + +* Changes in ripngd + +** When ripngd terminates, delete all installed route. + +** `redistribute static', `redistribute connected' works. + +** Change `debug ripng event' to `debug ripng events'. + +** Change `show debug ripng' to `show debugging ripng'. + +** Bug of static route deletion is fixed. + +* Changes in ospfd + +** LS request and LS update can be send and received. + +* Changes in zebra-0.68 + +* Changes in lib + +** DEFUN() is extended to support (a|b|c) statement. + +** Input buffer overflow bug is fixed. + +* Changes in bgpd + +** `ip community-list' is added. + +** set community and match community is added to route-map statement. + +** aggregate-address A.B.C.D/M partly works. Now it works only +summary-only mode. + +* Changes in zebra + +** IPv6 network address delete bug is fixed. + +* Changes in ospfd + +** DR election bug fixed. + +** Now Database Description can be send or received. + +** Neighbor State Machine goes to Full state. + +* Changes in ospf6d + +** router zebra related bug is fixed. + +* Changes in zebra-0.67 + +* Changes in lib + +** `service password-encryption' is added for encrypted password. + +* Changes in bgpd + +** `set as-path prepend ASPATH' is added to route-map command. + +** `set weight WEIGHT' is added to route-map command. + +** `no set ipv6 nexthop global' and `no set ipv6 nexthop local' +command is added to route-map. + +** `neighbor IP_ADDR version BGP_VERSION' command's BGP_VERSION +argument changed. + +Old New +===================== +bgp4 4 +bgp4+ 4+ +bgp4+-draft-00 4- +===================== + +If you want to peer with old draft version of BGP-4+, please configure +like below: + +router bgp ASN + neighbor PEER version 4- + +** Some AS path isn't correctly compared during route selection. Now +it is fixed. + +* Changes in ospfd + +** `router zebra' is default behavior. + +* Changes in ospf6d + +** `router zebra' is default behavior. + +* Changes in zebra-0.66 + +* Changes in zebra + +** When other daemon such as gated install routes into the kernel then +zebra blocks. This is only occur with netlink socket. Now socket is +set as NONBLOCKING and problem is fixed. Reported and fixed by +Patrick Koppen + +* Changes in bgpd + +** Now `router zebra' is not needed to insert BGP routes into the +kernel. It is default behavior. If you don't want to install the BGP +routes to the kernel, please configure like below: + +! +router zebra + no redistribute bgp +! + +** redistribute connected works. + +** redistribute static now filter local loopback routes and link local +network. + +* Changes in ripd + +** Some network check is added. Patch is done by Carlos Alberto +Barcenilla + +* Changes in ripngd + +** Sometimes ripngd install wrong nexthop into the kernel. This bug +is fixed now. + +** Now `router zebra' is not needed to insert RIPng routes into the +kernel. It is default behavior. If you don't want to install the BGP +routes to the kernel, please configure like below: + +! +router zebra + no redistribute ripng +! + +* Changes in zebra-0.65 + +* Changes in lib + +** `C-c' changes current node to ENABLE_NODE. Previously it doesn't. + +** In ENABLE_NODE, `exit' command close vty connection. + +** `service advanced-vty' enable advanced vty function. If this +service is specified one can directly connect to ENABLE_NODE when +enable password is not set. + +** `lines LINES' command is added by Stephen R. van den Berg +. + +* Changes in zebra + +** Basic Linux policy based routing table support is added by Stephen +R. van den Berg . + +* Changes in bgpd + +** route-map command is improved: + `match ip next-hop': New command. + `match metric': New command. + `set metric': Doc fixed. + `set local-preference': DEFUN added. + +* Changes in ripd + +** Check of announced network is added. Now multicast address is +filtered. Reported by Carlos Alberto Barcenilla + + +** Check of network 127 is added. Reported by Carlos Alberto +Barcenilla + +* Changes in ripngd + +** Aging route bug is fixed. + +** `router zebra' semantics changed. ripngd automatically connect to +zebra. + +* Changes in ospfd + +** `no router ospf' works. + +* Changes in ospf6d + +** Bug fix about network vertex. + +* Changes in zebra-0.64.1. + +This is bug fix release. + +* Changes in lib + +** Add check of sin6_scope_id in struct sockaddr_in6. For compilation +on implementation which doesn't have sin6_scope_id. Reported by Wim +Biemolt . + +* Changes in zebra + +** Fix bug of display BGP routes as "O" instead of "B". Reported by +"William F. Maton" and Dave Hartzell +. + +* Changes in bgpd + +** `no network IPV6_NETWORK' statement and `no neighbor IP_ADDR timers +holdtime [TIMER]' statement doesn't work. Reported by Georg Hitsch +. Now both statement work. + +* Changes in ospfd + +** Last interface is not updated by ospf_if_update(). Reported by +Dave Hartzell . + +* Changes in ospf6d + +** Byte order of ifid is changed. Due to this change, this code will +not work with previous version, sorry. + +** Fix `show ip route' route type mismatch. + +** Fix bug of no network IPV6_NETWORK. + +** Important bug fix about intra-area-prefix-lsa. + +* Changes in zebra-0.64. + +* Changes in lib + +** prefix-list based filtering routine is added. Currently used in +bgpd but it will be in other daemons. + +* Changes in bgpd + +** `no router bgp' works. But network statement is not cleared. This +should be fixed in next beta. + +** Route reflector related statement is added. + + router bgp ASN + bgp cluster-id a.b.c.d + neighbor a.b.c.d route-reflector-client + + is added. + +** Prefix list based filtering is added. + + router bgp ASN + neighbor a.b.c.d prefix-list PREFIX_LIST_NAME + +** Prefix list based routing display works. + + show ip bgp prefix-list PREFIX_LIST_NAME + +* Changes in ripd + +** Fix route metric check bug. Reported from Mr. Carlos Alberto +Barcenilla. + +* Changes in ospf6d + +** There are many changes. If you have interested in ospf6d please +visit ospf6d/README file. + +* Changes in zebra-0.63 first beta package. + +* Changes in lib + +** `copy running-config stgartup-config' command is added. + +** prefix length check bug is fixed. Thanks Marlos Barcenilla +. + +* Changes in ospfd + +** DR and BDR election works. + +** OSPF Hello simple authentication works. + +* Changes in ospf6d + +** Now ospf6d can be compiled on both Linux and *BSD system. + +* Changes in zebra-19990420 snapshot + +** `make dist' at top directory works now. + +* Changes in lib + +** VTY has now access-class to restrict remote connection. +Implemented by Alex Bligh . + +! +line vty + access-class ACCESS-LIST-NAME +! + +** `show version' command added. Implemented by Carlos Alberto +Barcenilla + +* Changes in zebra + +** `ip address' command on *BSD bug is fixed. + +** `no ip address' works now for IPv4 address. + +** Now `write terminal' display `ip address' configuration. + +* Changes in bgpd + +** Redistribute static works now. Please run both zebra and bgpd. +bgpd.conf should be like this: + +! +router zebra +! +router bgp ASN + redisitribute static +! + +* Changes in guile + +** configure --enable-guile turns on zebra-guile build. + +** (router-bgp ASN) allocates real bgp structre. + +* Changes in zebra-19990416 snapshot + +** Set version to 0.60 for preparation of beta release. + +** New directory guile is added for linking with guile interpreter. + +* Changes in zebra + +** On GNU/Linux Kernel 2.2.x (with netlink support), zebra detects +asynchronous routing updates. *BSD support is not yet finished. + +* Changes in bgpd + +** `show ip bgp regexp ASPATH_REGEX' uses CISCO like regular expression +instead of RPSL like regular expression. I'm planing to provide RPSL +like regular expression with `show ip bgp rpsl' or something. + +* Changes in lib + +** Press '?' at variable mandatory argument, vty prints nothing. Now +vty outputs description about the argument. Fixed by Alex Bligh + + +** buffer.c has some ugly bugs. Due to the bug, vty interface hangs +when large output date exists. This bug is fixed. Reported by Alex +Bligh . + +* Changes in ospfd + +** DR and BDR information is shown by `show ip ospf interface' command. + +* Changes in zebra-19990408 snapshot + +* Changes in bgpd + +** Old BGP-4+ specification (described in old draft) treatment bug is +fixed. It seems that mrtd uses this format as default. So if you +have problem peering with mrtd and want to use old draft format please +use version statement like this. + +neighbor PEER_ADDRESS remote-as ASN +neighbor PEER_ADDRESS version bgp4+-draft-00 + +** When AS path is epmty (routes generated by bgpd), SEGV is occur +when announce the routes to eBGP peer. Reported by +kad@gibson.skif.net. + +** ip as-path access-list command is added. + +** neighbor PEER_ADDRESS filter-list AS_LIST [in|out] command is added. + +** neighbor PEER_ADDRESS timers holdtimer TIMER command is added. + +* Changes in all daemons + +** With KAME stack, terminal interface is now bind AF_INET socket +instead of AF_INET6 one. + +* Changes in zebra-19990403 snapshot + +* Changes in bgpd + +** When bgpd has 'router zebra', bgpd automatically select it's router +ID as most highest interface's IP Address. + +** When AS path is empty (in case of iBGP), it doesn't include any AS +segment. This change is for announcement to gated under iBGP. + +* Changes in ospfd + +** OSPF hello packet send/receive works. + +* Changes in ospf6d + +** Yasuhiro Ohara's ospf6d codes is imported. It is under development +and can't be compiled on any platform. + +* Changes in zebra-19990327 snapshot + +* Changes in bgpd + +** When BGP-4+ connection is done by IPv6 link-local address. One +have to specify interface index for the connection. So I've added +interface statement to the neighbor commmand. Please specify +interface name for getting interface index like below. This statement +only works on GNU/Linux. I'll support BSD ASAP. + +router bgp 7675 + neighbor fe80::200:f8ff:fe01:5fd3 remote-as 2500 + neighbor fe80::200:f8ff:fe01:5fd3 interface sit3 + +** For disable BGP peering `shutdown' command is added. + +router bgp 7675 + neighbor 10.0.0.1 shutdown + +** `description' command is added to neighbor statement. + +router bgp 7675 + neighbor 10.0.0.1 description peering with Norway. + +** `show ip bgp regexp AS-REGEXP' works again. + +show ip bgp regexp AS7675 + +will show routes which include AS7675. + +** When a route which is made from `network' statement is send to +neighbor. Set it's nexthop to self. So 10.0.0.0/8 is announced to +the peer A with source address 192.168.1.1. The routes nexthop is set +to 192.168.1.1. + +* Changes in zebra + +** In zebra/rtread_sysctl.c, function rtm_read() may overrun allocated +buffer when the address family is not supported and the length is big +(i.e link address). Reported Achim Patzner . + +* Changes in ospfd + +** Now ospfd receive OSPF packet. + +* Changes in zebra-19990319 snapshot + +* Changes in configuration and libraries + +** User can disable IPv6 feature and/or pthread feature by configure + option. + + To disable IPv6: configure --disable-ipv6 + To disable pthread: configure --disable-pthread + +** User can disable specified daemon by configure option. + + Don't make zebra: configure --disable-zebra + Don't make bgpd: configure --disable-bgpd + Don't make ripd: configure --disable-ripd + Don't make ripngd: configure --disable-ripngd + Don't make ospfd: configure --disable-ospfd + Don't make ospf6d: configure --disable-ospf6d + +** Sample configuration files are installed as 600 file flag. + Suggested by Jeroen Ruigrok/Asmodai . + +** syslog logging feature is added by Peter Galbavy + + +** Inclusion of standard header files is reworked by Peter Galbavy + + +** Change description from GNU/Linux 2.1.X to GNU/Linux 2.2.X + +** If daemon function exists in standard C library use it. + +** To generate configure script we upgrade autoconf to 2.13. To +generate Makefile.in we upgrade automake to 1.4. + +** doc/texinfo.tex is added to distribution. + +** Update ports/pkg/DESCR description. + +** Update doc/zebra.texi. + +** logfile FILENAME statement deleted. Instead of that please use log +file FILENAME. + +* Changes in zebra + +* Changes in bgpd + +** Communication between zebra and bgpd works now. So if there is + `router zebra' line in bgpd.conf, selected route is installed + into kernel routing table. + +** Delete all routes which inserted by bgpd when bgpd dies. If you +want to retain routes even bgpd dies please specify [-r|--retain] +option to bgpd. + +** BGP announcement code is reworked. Now bgpd announce selected + routes to other peer. + +** All output bgp packet is buffered. It's written to the socket when + it gets ready. + +** Output route-map works now. You can specify output route-map by: + + neighbor IP_ADDR route-map ROUTE_MAP_NAME out + +** New route-map command added. + + set ip nexthop IP_ADDR + set ipv6 nexthop global IP_ADDR + +** Fix bug about unlock of the route_node structure. + +** BGP-4+ support is added. bgpd can listen and speak BGP-4+ packet +specified in RFC2283. You can view IPv6 bgp table by: `show ipv6 bgp'. + +** Meny packet overflow check is added. + +* Changes in ripd + +* Changes in ripngd + +* Changes in ospfd + +** ospfd work is started by Toshiaki Takada . Now +several files are included in ospfd directory. + +** ospf6d codes are merged from Yasuhiro Ohara 's +ospfd work. Now codes are located in ospf6d directory. + + +Local variables: +mode: outline +paragraph-separate: "[ ]*$" +end: diff --git a/README b/README new file mode 100644 index 00000000..72bccfca --- /dev/null +++ b/README @@ -0,0 +1,12 @@ +GNU Zebra is free software that manages various IPv4 and IPv6 routing +protocols. + +Currently GNU Zebra supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, +RIPv2, and RIPng. + +See the file INSTALL for building and installation instructions. + +See the file REPORTING-BUGS to report bugs. + +GNU Zebra is free software. See the file COPYING for copying conditions. + diff --git a/REPORTING-BUGS b/REPORTING-BUGS new file mode 100644 index 00000000..d6b23dd9 --- /dev/null +++ b/REPORTING-BUGS @@ -0,0 +1,28 @@ +This file describes the procedure for reporting Zebra bugs. +You are not obliged to follow this format , but it would be +great help for Zebra developers if you report a bug as described +below. + +Send your report to bug-zebra@gnu.org mailing list. + +Please supply the following information: +1. Your zebra version or if it is CVS version then the date you did checkout. +Always try to report the bugs on the current CVS version. +2. Zebra daemons you run e.g. bgpd or ripd, your OS full name, +any specific options you compiled zebra with. +3. Problem description. Copy and paste relative zebra commands and their +output to describe your network setup e.g. "zebra>show ip route". +Please, also give your simple network layout and output of relative OS commands +(e.g. ifconfig). +4. All zebra configuration files you use. If you don't want to publish +your network numbers change 2 middle bytes in IPv4 address to be XXX e.g. +192.XXX.XXX.32/24. Similar could be done with IPv6. +5. If any zebra daemon core dumped, please, supply stack trace using +the following commands: host> gdb exec_file core_file , (gdb) bt . +6. Run all zebra daemons with full debugging on (see documentation on debugging) and +send _only_ part of logs which are relative to your problem. +7. If the problem is difficult to reproduce please send a shell script to +reproduce it. +8. Patches, workarounds, fixes are always welcome. + +Thank You. diff --git a/SERVICES b/SERVICES new file mode 100644 index 00000000..41d4b948 --- /dev/null +++ b/SERVICES @@ -0,0 +1,17 @@ +# As long as this software is in alpha testing it is not yet included +# in /etc/services files. This means that you may need to add the following +# lines into your /etc/services file on your hosts. +# +# --- Please add this to your /etc/services --- + +# +# GNU Zebra services +# + +zebrasrv 2600/tcp +zebra 2601/tcp +ripd 2602/tcp +ripng 2603/tcp +ospfd 2604/tcp +bgpd 2605/tcp +ospf6d 2606/tcp diff --git a/TODO b/TODO new file mode 100644 index 00000000..4c8b7b61 --- /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 diff --git a/acconfig.h b/acconfig.h new file mode 100644 index 00000000..de39bc82 --- /dev/null +++ b/acconfig.h @@ -0,0 +1,161 @@ +/* accconfig.h -- `autoheader' will generate config.h.in for zebra. + Copyright (C) 1998, 1999 Kunihiro Ishiguro */ + +/* 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 index 00000000..5401d285 --- /dev/null +++ b/aclocal.m4 @@ -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 index 00000000..8edffb6e --- /dev/null +++ b/bgpd/.cvsignore @@ -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 index 00000000..c911316c --- /dev/null +++ b/bgpd/BGP4-MIB.txt @@ -0,0 +1,929 @@ + BGP4-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE, + IpAddress, Integer32, Counter32, Gauge32, mib-2 + FROM SNMPv2-SMI + MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP + FROM SNMPv2-CONF; + + bgp MODULE-IDENTITY + LAST-UPDATED "9902100000Z" + ORGANIZATION "IETF IDR Working Group" + CONTACT-INFO "E-mail: idr@merit.net + + Susan Hares (Editor) + Merit Network + 4251 Plymouth Road + Suite C + Ann Arbor, MI 48105-2785 + Tel: +1 734 936 2095 + Fax: +1 734 647 3185 + E-mail: skh@merit.edu + + Jeff Johnson (Editor) + RedBack Networks, Inc. + 1389 Moffett Park Drive + Sunnyvale, CA 94089-1134 + Tel: +1 408 548 3516 + Fax: +1 408 548 3599 + E-mail: jeff@redback.com" + DESCRIPTION + "The MIB module for BGP-4." + REVISION "9902100000Z" + DESCRIPTION + "Corrected duplicate OBJECT IDENTIFIER + assignment in the conformance information." + REVISION "9601080000Z" + DESCRIPTION + "1) Fixed the definitions of the traps to + make them equivalent to their initial + definition in RFC 1269. + 2) Added compliance and conformance info." + ::= { mib-2 15 } + + bgpVersion OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (1..255)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Vector of supported BGP protocol version + numbers. Each peer negotiates the version + from this vector. Versions are identified + via the string of bits contained within this + object. The first octet contains bits 0 to + 7, the second octet contains bits 8 to 15, + and so on, with the most significant bit + referring to the lowest bit number in the + octet (e.g., the MSB of the first octet + refers to bit 0). If a bit, i, is present + and set, then the version (i+1) of the BGP + is supported." + ::= { bgp 1 } + + bgpLocalAs OBJECT-TYPE + SYNTAX INTEGER (0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The local autonomous system number." + ::= { bgp 2 } + + + + -- BGP Peer table. This table contains, one entry per BGP + -- peer, information about the BGP peer. + + bgpPeerTable OBJECT-TYPE + SYNTAX SEQUENCE OF BgpPeerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "BGP peer table. This table contains, + one entry per BGP peer, information about the + connections with BGP peers." + ::= { bgp 3 } + + bgpPeerEntry OBJECT-TYPE + SYNTAX BgpPeerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Entry containing information about the + connection with a BGP peer." + INDEX { bgpPeerRemoteAddr } + ::= { bgpPeerTable 1 } + + BgpPeerEntry ::= SEQUENCE { + bgpPeerIdentifier + IpAddress, + bgpPeerState + INTEGER, + bgpPeerAdminStatus + INTEGER, + bgpPeerNegotiatedVersion + Integer32, + bgpPeerLocalAddr + IpAddress, + bgpPeerLocalPort + INTEGER, + bgpPeerRemoteAddr + IpAddress, + bgpPeerRemotePort + INTEGER, + bgpPeerRemoteAs + INTEGER, + bgpPeerInUpdates + Counter32, + bgpPeerOutUpdates + Counter32, + bgpPeerInTotalMessages + Counter32, + bgpPeerOutTotalMessages + Counter32, + bgpPeerLastError + OCTET STRING, + bgpPeerFsmEstablishedTransitions + Counter32, + bgpPeerFsmEstablishedTime + Gauge32, + bgpPeerConnectRetryInterval + INTEGER, + bgpPeerHoldTime + INTEGER, + bgpPeerKeepAlive + INTEGER, + bgpPeerHoldTimeConfigured + INTEGER, + bgpPeerKeepAliveConfigured + INTEGER, + bgpPeerMinASOriginationInterval + INTEGER, + bgpPeerMinRouteAdvertisementInterval + INTEGER, + bgpPeerInUpdateElapsedTime + Gauge32 + } + + bgpPeerIdentifier OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The BGP Identifier of this entry's BGP peer." + ::= { bgpPeerEntry 1 } + + bgpPeerState OBJECT-TYPE + SYNTAX INTEGER { + idle(1), + connect(2), + active(3), + opensent(4), + openconfirm(5), + established(6) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The BGP peer connection state." + ::= { bgpPeerEntry 2 } + + bgpPeerAdminStatus OBJECT-TYPE + SYNTAX INTEGER { + stop(1), + start(2) + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The desired state of the BGP connection. A + transition from 'stop' to 'start' will cause + the BGP Start Event to be generated. A + transition from 'start' to 'stop' will cause + the BGP Stop Event to be generated. This + parameter can be used to restart BGP peer + connections. Care should be used in providing + write access to this object without adequate + authentication." + ::= { bgpPeerEntry 3 } + + bgpPeerNegotiatedVersion OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The negotiated version of BGP running between + the two peers." + ::= { bgpPeerEntry 4 } + + bgpPeerLocalAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The local IP address of this entry's BGP + connection." + ::= { bgpPeerEntry 5 } + + bgpPeerLocalPort OBJECT-TYPE + SYNTAX INTEGER (0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The local port for the TCP connection between + the BGP peers." + ::= { bgpPeerEntry 6 } + + bgpPeerRemoteAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The remote IP address of this entry's BGP + peer." + ::= { bgpPeerEntry 7 } + + bgpPeerRemotePort OBJECT-TYPE + SYNTAX INTEGER (0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The remote port for the TCP connection between + the BGP peers. Note that the objects + bgpPeerLocalAddr, bgpPeerLocalPort, + bgpPeerRemoteAddr and bgpPeerRemotePort + provide the appropriate reference to the + standard MIB TCP connection table." + ::= { bgpPeerEntry 8 } + + bgpPeerRemoteAs OBJECT-TYPE + SYNTAX INTEGER (0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The remote autonomous system number." + ::= { bgpPeerEntry 9 } + + bgpPeerInUpdates OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of BGP UPDATE messages received on + this connection. This object should be + initialized to zero (0) when the connection is + established." + ::= { bgpPeerEntry 10 } + + bgpPeerOutUpdates OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of BGP UPDATE messages transmitted + on this connection. This object should be + initialized to zero (0) when the connection is + established." + ::= { bgpPeerEntry 11 } + + bgpPeerInTotalMessages OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of messages received from the + remote peer on this connection. This object + should be initialized to zero when the + connection is established." + ::= { bgpPeerEntry 12 } + + bgpPeerOutTotalMessages OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of messages transmitted to + the remote peer on this connection. This object + should be initialized to zero when the + connection is established." + ::= { bgpPeerEntry 13 } + + bgpPeerLastError OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (2)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The last error code and subcode seen by this + peer on this connection. If no error has + occurred, this field is zero. Otherwise, the + first byte of this two byte OCTET STRING + contains the error code, and the second byte + contains the subcode." + ::= { bgpPeerEntry 14 } + + bgpPeerFsmEstablishedTransitions OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of times the BGP FSM + transitioned into the established state." + ::= { bgpPeerEntry 15 } + + bgpPeerFsmEstablishedTime OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This timer indicates how long (in seconds) this + peer has been in the Established state or how long + since this peer was last in the Established state. + It is set to zero when a new peer is configured or + the router is booted." + ::= { bgpPeerEntry 16 } + + bgpPeerConnectRetryInterval OBJECT-TYPE + SYNTAX INTEGER (1..65535) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Time interval in seconds for the ConnectRetry + timer. The suggested value for this timer is + 120 seconds." + ::= { bgpPeerEntry 17 } + + bgpPeerHoldTime OBJECT-TYPE + SYNTAX INTEGER ( 0 | 3..65535 ) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Time interval in seconds for the Hold Timer + established with the peer. The value of this + object is calculated by this BGP speaker by + using the smaller of the value in + bgpPeerHoldTimeConfigured and the Hold Time + received in the OPEN message. This value + must be at lease three seconds if it is not + zero (0) in which case the Hold Timer has + not been established with the peer, or, the + value of bgpPeerHoldTimeConfigured is zero (0)." + ::= { bgpPeerEntry 18 } + + bgpPeerKeepAlive OBJECT-TYPE + SYNTAX INTEGER ( 0 | 1..21845 ) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Time interval in seconds for the KeepAlive + timer established with the peer. The value of + this object is calculated by this BGP speaker + such that, when compared with bgpPeerHoldTime, + it has the same proportion as what + bgpPeerKeepAliveConfigured has when compared + with bgpPeerHoldTimeConfigured. If the value + of this object is zero (0), it indicates that + the KeepAlive timer has not been established + with the peer, or, the value of + bgpPeerKeepAliveConfigured is zero (0)." + ::= { bgpPeerEntry 19 } + + bgpPeerHoldTimeConfigured OBJECT-TYPE + SYNTAX INTEGER ( 0 | 3..65535 ) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Time interval in seconds for the Hold Time + configured for this BGP speaker with this peer. + This value is placed in an OPEN message sent to + this peer by this BGP speaker, and is compared + with the Hold Time field in an OPEN message + received from the peer when determining the Hold + Time (bgpPeerHoldTime) with the peer. This value + must not be less than three seconds if it is not + zero (0) in which case the Hold Time is NOT to be + established with the peer. The suggested value for + this timer is 90 seconds." + ::= { bgpPeerEntry 20 } + + bgpPeerKeepAliveConfigured OBJECT-TYPE + SYNTAX INTEGER ( 0 | 1..21845 ) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Time interval in seconds for the KeepAlive timer + configured for this BGP speaker with this peer. + The value of this object will only determine the + KEEPALIVE messages' frequency relative to the value + specified in bgpPeerHoldTimeConfigured; the actual + time interval for the KEEPALIVE messages is + indicated by bgpPeerKeepAlive. A reasonable + maximum value for this timer would be configured to + be one third of that of bgpPeerHoldTimeConfigured. + If the value of this object is zero (0), no + periodical KEEPALIVE messages are sent to the peer + after the BGP connection has been established. The + suggested value for this timer is 30 seconds." + ::= { bgpPeerEntry 21 } + + bgpPeerMinASOriginationInterval OBJECT-TYPE + SYNTAX INTEGER (1..65535) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Time interval in seconds for the + MinASOriginationInterval timer. + The suggested value for this timer is 15 seconds." + ::= { bgpPeerEntry 22 } + + bgpPeerMinRouteAdvertisementInterval OBJECT-TYPE + SYNTAX INTEGER (1..65535) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Time interval in seconds for the + MinRouteAdvertisementInterval timer. + The suggested value for this timer is 30 seconds." + ::= { bgpPeerEntry 23 } + + bgpPeerInUpdateElapsedTime OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Elapsed time in seconds since the last BGP + UPDATE message was received from the peer. + Each time bgpPeerInUpdates is incremented, + the value of this object is set to zero (0)." + ::= { bgpPeerEntry 24 } + + + + bgpIdentifier OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The BGP Identifier of local system." + ::= { bgp 4 } + + + + -- Received Path Attribute Table. This table contains, + -- one entry per path to a network, path attributes + -- received from all peers running BGP version 3 or less. + -- This table is obsolete, having been replaced in + -- functionality with the bgp4PathAttrTable. + + bgpRcvdPathAttrTable OBJECT-TYPE + SYNTAX SEQUENCE OF BgpPathAttrEntry + MAX-ACCESS not-accessible + STATUS obsolete + DESCRIPTION + "The BGP Received Path Attribute Table contains + information about paths to destination networks + received from all peers running BGP version 3 or + less." + ::= { bgp 5 } + + bgpPathAttrEntry OBJECT-TYPE + SYNTAX BgpPathAttrEntry + MAX-ACCESS not-accessible + STATUS obsolete + DESCRIPTION + "Information about a path to a network." + INDEX { bgpPathAttrDestNetwork, + bgpPathAttrPeer } + ::= { bgpRcvdPathAttrTable 1 } + + BgpPathAttrEntry ::= SEQUENCE { + bgpPathAttrPeer + IpAddress, + bgpPathAttrDestNetwork + IpAddress, + bgpPathAttrOrigin + INTEGER, + bgpPathAttrASPath + OCTET STRING, + bgpPathAttrNextHop + IpAddress, + bgpPathAttrInterASMetric + Integer32 + } + + bgpPathAttrPeer OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The IP address of the peer where the path + information was learned." + ::= { bgpPathAttrEntry 1 } + + bgpPathAttrDestNetwork OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The address of the destination network." + ::= { bgpPathAttrEntry 2 } + + bgpPathAttrOrigin OBJECT-TYPE + SYNTAX INTEGER { + igp(1),-- networks are interior + egp(2),-- networks learned via EGP + incomplete(3) -- undetermined + } + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The ultimate origin of the path information." + ::= { bgpPathAttrEntry 3 } + + bgpPathAttrASPath OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (2..255)) + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The set of ASs that must be traversed to reach + the network. This object is probably best + represented as SEQUENCE OF INTEGER. For SMI + compatibility, though, it is represented as + OCTET STRING. Each AS is represented as a pair + of octets according to the following algorithm: + + first-byte-of-pair = ASNumber / 256; + second-byte-of-pair = ASNumber & 255;" + ::= { bgpPathAttrEntry 4 } + + bgpPathAttrNextHop OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The address of the border router that should + be used for the destination network." + ::= { bgpPathAttrEntry 5 } + + bgpPathAttrInterASMetric OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The optional inter-AS metric. If this + attribute has not been provided for this route, + the value for this object is 0." + ::= { bgpPathAttrEntry 6 } + + + + -- BGP-4 Received Path Attribute Table. This table contains, + -- one entry per path to a network, path attributes + -- received from all peers running BGP-4. + + bgp4PathAttrTable OBJECT-TYPE + SYNTAX SEQUENCE OF Bgp4PathAttrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The BGP-4 Received Path Attribute Table contains + information about paths to destination networks + received from all BGP4 peers." + ::= { bgp 6 } + + bgp4PathAttrEntry OBJECT-TYPE + SYNTAX Bgp4PathAttrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information about a path to a network." + INDEX { bgp4PathAttrIpAddrPrefix, + bgp4PathAttrIpAddrPrefixLen, + bgp4PathAttrPeer } + ::= { bgp4PathAttrTable 1 } + + Bgp4PathAttrEntry ::= SEQUENCE { + bgp4PathAttrPeer + IpAddress, + bgp4PathAttrIpAddrPrefixLen + INTEGER, + bgp4PathAttrIpAddrPrefix + IpAddress, + bgp4PathAttrOrigin + INTEGER, + bgp4PathAttrASPathSegment + OCTET STRING, + bgp4PathAttrNextHop + IpAddress, + bgp4PathAttrMultiExitDisc + INTEGER, + bgp4PathAttrLocalPref + INTEGER, + bgp4PathAttrAtomicAggregate + INTEGER, + bgp4PathAttrAggregatorAS + INTEGER, + bgp4PathAttrAggregatorAddr + IpAddress, + bgp4PathAttrCalcLocalPref + INTEGER, + bgp4PathAttrBest + INTEGER, + bgp4PathAttrUnknown + OCTET STRING + } + + bgp4PathAttrPeer OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address of the peer where the path + information was learned." + ::= { bgp4PathAttrEntry 1 } + bgp4PathAttrIpAddrPrefixLen OBJECT-TYPE + SYNTAX INTEGER (0..32) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Length in bits of the IP address prefix in the + Network Layer Reachability Information field." + ::= { bgp4PathAttrEntry 2 } + + bgp4PathAttrIpAddrPrefix OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "An IP address prefix in the Network Layer + Reachability Information field. This object + is an IP address containing the prefix with + length specified by bgp4PathAttrIpAddrPrefixLen. + Any bits beyond the length specified by + bgp4PathAttrIpAddrPrefixLen are zeroed." + ::= { bgp4PathAttrEntry 3 } + + bgp4PathAttrOrigin OBJECT-TYPE + SYNTAX INTEGER { + igp(1),-- networks are interior + egp(2),-- networks learned via EGP + incomplete(3) -- undetermined + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The ultimate origin of the path information." + ::= { bgp4PathAttrEntry 4 } + + bgp4PathAttrASPathSegment OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (2..255)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The sequence of AS path segments. Each AS + path segment is represented by a triple + . + + The type is a 1-octet field which has two + possible values: + 1 AS_SET: unordered set of ASs a + route in the UPDATE message + has traversed + 2 AS_SEQUENCE: ordered set of ASs + a route in the UPDATE message + has traversed. + + The length is a 1-octet field containing the + number of ASs in the value field. + + The value field contains one or more AS + numbers, each AS is represented in the octet + string as a pair of octets according to the + following algorithm: + + first-byte-of-pair = ASNumber / 256; + second-byte-of-pair = ASNumber & 255;" + ::= { bgp4PathAttrEntry 5 } + + bgp4PathAttrNextHop OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The address of the border router that should + be used for the destination network." + ::= { bgp4PathAttrEntry 6 } + + bgp4PathAttrMultiExitDisc OBJECT-TYPE + SYNTAX INTEGER (-1..2147483647) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This metric is used to discriminate between + multiple exit points to an adjacent autonomous + system. A value of -1 indicates the absence of + this attribute." + ::= { bgp4PathAttrEntry 7 } + + bgp4PathAttrLocalPref OBJECT-TYPE + SYNTAX INTEGER (-1..2147483647) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The originating BGP4 speaker's degree of + preference for an advertised route. A value of + -1 indicates the absence of this attribute." + ::= { bgp4PathAttrEntry 8 } + + bgp4PathAttrAtomicAggregate OBJECT-TYPE + SYNTAX INTEGER { + lessSpecificRrouteNotSelected(1), + lessSpecificRouteSelected(2) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Whether or not a system has selected + a less specific route without selecting a + more specific route." + ::= { bgp4PathAttrEntry 9 } + + bgp4PathAttrAggregatorAS OBJECT-TYPE + SYNTAX INTEGER (0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The AS number of the last BGP4 speaker that + performed route aggregation. A value of zero (0) + indicates the absence of this attribute." + ::= { bgp4PathAttrEntry 10 } + + bgp4PathAttrAggregatorAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address of the last BGP4 speaker that + performed route aggregation. A value of + 0.0.0.0 indicates the absence of this attribute." + ::= { bgp4PathAttrEntry 11 } + + bgp4PathAttrCalcLocalPref OBJECT-TYPE + SYNTAX INTEGER (-1..2147483647) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The degree of preference calculated by the + receiving BGP4 speaker for an advertised route. + A value of -1 indicates the absence of this + attribute." + ::= { bgp4PathAttrEntry 12 } + + bgp4PathAttrBest OBJECT-TYPE + SYNTAX INTEGER { + false(1),-- not chosen as best route + true(2) -- chosen as best route + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "An indication of whether or not this route + was chosen as the best BGP4 route." + ::= { bgp4PathAttrEntry 13 } + + bgp4PathAttrUnknown OBJECT-TYPE + SYNTAX OCTET STRING (SIZE(0..255)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "One or more path attributes not understood + by this BGP4 speaker. Size zero (0) indicates + the absence of such attribute(s). Octets + beyond the maximum size, if any, are not + recorded by this object." + ::= { bgp4PathAttrEntry 14 } + + + -- Traps. + + -- note that in RFC 1657, bgpTraps was incorrectly + -- assigned a value of { bgp 7 }, and each of the + -- traps had the bgpPeerRemoteAddr object inappropriately + -- removed from their OBJECTS clause. The following + -- definitions restore the semantics of the traps as + -- they were initially defined in RFC 1269. + + -- { bgp 7 } is unused + + bgpTraps OBJECT IDENTIFIER ::= { bgp 0 } + + bgpEstablished NOTIFICATION-TYPE + OBJECTS { bgpPeerRemoteAddr, + bgpPeerLastError, + bgpPeerState } + STATUS current + DESCRIPTION + "The BGP Established event is generated when + the BGP FSM enters the ESTABLISHED state." + ::= { bgpTraps 1 } + + bgpBackwardTransition NOTIFICATION-TYPE + OBJECTS { bgpPeerRemoteAddr, + bgpPeerLastError, + bgpPeerState } + STATUS current + DESCRIPTION + "The BGPBackwardTransition Event is generated + when the BGP FSM moves from a higher numbered + state to a lower numbered state." + ::= { bgpTraps 2 } + + -- conformance information + + bgpMIBConformance OBJECT IDENTIFIER ::= { bgp 8 } + bgpMIBCompliances OBJECT IDENTIFIER ::= { bgpMIBConformance 1 } + bgpMIBGroups OBJECT IDENTIFIER ::= { bgpMIBConformance 2 } + + -- compliance statements + + bgpMIBCompliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for entities which + implement the BGP4 mib." + MODULE -- this module + MANDATORY-GROUPS { bgp4MIBGlobalsGroup, + bgp4MIBPeerGroup, + bgp4MIBPathAttrGroup, + bgp4MIBNotificationGroup } + ::= { bgpMIBCompliances 1 } + + -- units of conformance + + bgp4MIBGlobalsGroup OBJECT-GROUP + OBJECTS { bgpVersion, + bgpLocalAs, + bgpIdentifier } + STATUS current + DESCRIPTION + "A collection of objects providing information + on global BGP state." + ::= { bgpMIBGroups 1 } + + bgp4MIBPeerGroup OBJECT-GROUP + OBJECTS { bgpPeerIdentifier, + bgpPeerState, + bgpPeerAdminStatus, + bgpPeerNegotiatedVersion, + bgpPeerLocalAddr, + bgpPeerLocalPort, + bgpPeerRemoteAddr, + bgpPeerRemotePort, + bgpPeerRemoteAs, + bgpPeerInUpdates, + bgpPeerOutUpdates, + bgpPeerInTotalMessages, + bgpPeerOutTotalMessages, + bgpPeerLastError, + bgpPeerFsmEstablishedTransitions, + bgpPeerFsmEstablishedTime, + bgpPeerConnectRetryInterval, + bgpPeerHoldTime, + bgpPeerKeepAlive, + bgpPeerHoldTimeConfigured, + bgpPeerKeepAliveConfigured, + bgpPeerMinASOriginationInterval, + bgpPeerMinRouteAdvertisementInterval, + bgpPeerInUpdateElapsedTime } + STATUS current + DESCRIPTION + "A collection of objects for managing + BGP peers." + ::= { bgpMIBGroups 2 } + + bgp4MIBRcvdPathAttrGroup OBJECT-GROUP + OBJECTS { bgpPathAttrPeer, + bgpPathAttrDestNetwork, + bgpPathAttrOrigin, + bgpPathAttrASPath, + bgpPathAttrNextHop, + bgpPathAttrInterASMetric } + STATUS obsolete + DESCRIPTION + "A collection of objects for managing BGP + path entries. + + This conformance group is obsolete, + replaced by bgp4MIBPathAttrGroup." + ::= { bgpMIBGroups 3 } + + bgp4MIBPathAttrGroup OBJECT-GROUP + OBJECTS { bgp4PathAttrPeer, + bgp4PathAttrIpAddrPrefixLen, + bgp4PathAttrIpAddrPrefix, + bgp4PathAttrOrigin, + bgp4PathAttrASPathSegment, + bgp4PathAttrNextHop, + bgp4PathAttrMultiExitDisc, + bgp4PathAttrLocalPref, + bgp4PathAttrAtomicAggregate, + bgp4PathAttrAggregatorAS, + bgp4PathAttrAggregatorAddr, + bgp4PathAttrCalcLocalPref, + bgp4PathAttrBest, + bgp4PathAttrUnknown } + STATUS current + DESCRIPTION + "A collection of objects for managing + BGP path entries." + ::= { bgpMIBGroups 4 } + + bgp4MIBNotificationGroup NOTIFICATION-GROUP + NOTIFICATIONS { bgpEstablished, + bgpBackwardTransition } + STATUS current + DESCRIPTION + "A collection of notifications for signaling + changes in BGP peer relationships." + ::= { bgpMIBGroups 5 } + + END diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog new file mode 100644 index 00000000..4f7a20e9 --- /dev/null +++ b/bgpd/ChangeLog @@ -0,0 +1,2368 @@ +2002-10-23 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_init): Extend hash size from default to + 32767. + (aspath_key_make): Use unsigned shoft for making hash. Suggested + by: Marc Evans + +2002-08-19 Kunihiro Ishiguro + + * bgp_clist.c (community_entry_free): Fix memory leak of standard + extcommunity-list config string. + +2002-08-19 Akihiro Mizutani + + * bgp_route.c (route_vty_out_detail): Fix bug of router-id display + when multiple instance is used. + +2002-08-18 Akihiro Mizutani + + * bgpd.c: Make "default-originate" and "maximum-prefix" commands + available in peer-group configuration. + +2002-08-13 Akihiro Mizutani + + * bgp_packet.c (bgp_open_send): Put Opt Parm Len 0 when last + capability packet cause error or dont-capability-negotiate option + is specified. + +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2001-10-28 Kunihiro Ishiguro + + * bgpd.c (bgp_vty_init): Translate update commands are removed. + +2001-10-10 Kunihiro Ishiguro + + * bgp_route.c (bgp_static_set): Add workaround for BGP static + route announcement when there is no zebra running. + +2001-10-08 Kunihiro Ishiguro + + * bgpd.c (neighbor_remote_as_unicast): Remove "remote-as nlri + unicast multicast" commands. + +2001-09-14 Akihiro Mizutani + + * bgp_open.c: When we receive capability route-refresh, we should + check we send the capability not we receive the capability. + + * bgp_route.c (bgp_network_mask_natural_route_map): network + statement route-map is added. + +2001-08-31 Kunihiro Ishiguro + + * bgp_advertise.c (bgp_advertise_intern): attr must be interned + before looking up hash table. + +2001-08-30 Kunihiro Ishiguro + + * bgpd.h (struct peer): BGP filter is moved from peer_conf to + peer. + +2001-08-28 Kunihiro Ishiguro + + * bgp_nexthop.c (bnc_nexthop_free): Fix next pointer bug. + Suggested by: "Hong-Sung Kim" . + +2001-08-26 Kunihiro Ishiguro + + * bgp_table.c (bgp_node_create): Clearn memory before use it. + +2001-08-24 Kunihiro Ishiguro + + * Change to use bgp_table.[ch]. + +2001-08-23 Kunihiro Ishiguro + + * bgpd.c (bgp_init): Add "transparent-as" and + "transparent-nexthop" for old version compatibility. + +2001-08-23 Akihiro Mizutani + + * bgpd.h (struct peer): default-originate route-map is added. + + * bgp_route.c: When self originated route is advertised with + attrubute-unchanged, nexthop was not properly set. This bug is + fixed. + +2001-08-22 Akihiro Mizutani + + * bgpd.c (neighbor_attr_unchanged): transparent-as and + transparent-next-hop commands are restructured. Instead of + current transparent-* commands, attribute-unchanged command is + introduced. + + neighbor A.B.C.D attribute-unchanged [as-path|next-hop|med] + + (neighbor_default_originate): "default-originate" configuration + announce default route even 0.0.0.0/0 does not exists in BGP RIB. + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-19 Akihiro Mizutani + + * bgpd.c: AF specific soft-reconfiguration inbound commands are + added. + +2001-08-17 Kunihiro Ishiguro + + * bgp_route.c (bgp_show_callback): Do not do community NULL check. + + * bgp_community.c (community_cmp): Add check for commnunity NULL + check. + + * bgp_routemap.c (route_match_community): Do not check comunity is + NULL. It may match to community-list "^$". + + * bgp_community.c (community_match): Add check for community is + NULL case. + +2001-08-17 Akihiro Mizutani + + * bgpd.c: AF specific route-reflector-client and + route-server-client configuration are added. + +2001-08-17 Rick Payne + + * bgp_clist.c (community_match_regexp): Check special ^$ case. + +2001-08-17 Akihiro Mizutani + + * bgp_clist.c (community_list_match): Fix bug of community list + permit and deny check. + +2001-08-16 Akihiro Mizutani + + * bgp_mplsvpn.c (bgp_mplsvpn_init): Add AF specific "nexthop-self" + command. + +2001-08-15 Akihiro Mizutani + + * bgpd.h (PEER_FLAG_SEND_COMMUNITY): Per AF based configuration + flag is introduced. + + * bgp_mplsvpn.c (bgp_mplsvpn_init): VPNv4 filtering is added. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-08-13 Kunihiro Ishiguro + + * bgpd.c (bgp_delete): "no router bgp" free static, aggregate, rib + table properly. + +2001-08-12 Kunihiro Ishiguro + + * bgp_route.c (bgp_node_safi): Return SAFI of current node. + (bgp_config_write_network_vpnv4): VPNv4 static configuration + display. + +2001-08-11 Kunihiro Ishiguro + + * bgpd.c (no_bgp_ipv4_multicast_route_map): Add IPv4 multicast + node filter commands. + +2001-08-11 Kunihiro Ishiguro + + * bgpd.h (PEER_FLAG_IGNORE_LINK_LOCAL_NEXTHOP): Add + "ignore-link-local-nexthop" flag for ignore link-local nexthop for + IPv6. + +2001-08-07 Kunihiro Ishiguro + + * bgpd.c (address_family_ipv4_multicast): "address-family ipv4 + multicast" is added. + (address_family_ipv6_unicast): "address-family ipv6 unicast" is + added. + +2001-08-07 Akihiro Mizutani + + * bgp_route.c (bgp_process): Use flag instead of as_selected + memeber in struct bgp_info. + + * bgp_route.h (struct bgp_info): Remove as_selected memeber from + struct bgp_info. + +2001-07-31 Kunihiro Ishiguro + + * bgp_route.c (bgp_announce_check): Enclose sending time AS loop + check code with #ifdef BGP_SEND_ASPATH_CHECK. + +2001-07-29 Kunihiro Ishiguro + + * bgp_packet.c (bgp_withdraw_send): Simplify address family check. + + * bgpd.h (BGP_INFO_HOLDDOWN): Introduce new macro to check BGP + information is alive or not. + + * bgp_community.c: Use community_val_get() on all OS. + +2001-07-24 Kunihiro Ishiguro + + * bgp_route.c (bgp_announce_check): Simplify set next-hop self + check. + +2001-07-24 Akihiro Mizutani + + * bgp_route.c (bgp_announce_check): To route server clients, we + announce AS path, MED and nexthop transparently. + +2001-06-21 Kunihiro Ishiguro + + * bgp_routemap.c (route_set_atomic_aggregate_free): Do not call + XFREE. No memory is allocated in + route_set_atomic_aggregate_compile(). + +2001-06-21 Kunihiro Ishiguro + + * bgp_routemap.c (bgp_route_map_init): `match nlri` and `set nlri` + are replaced by `address-family ipv4` and `address-family vpnvr'. + +2001-06-19 Kunihiro Ishiguro + + * bgp_route.c (bgp_withdraw): Add check for BGP_PEER_CONFED. + Reported by Rick Payne . + +2001-06-17 Kunihiro Ishiguro + + * bgp_zebra.c (bgp_zebra_announce): When global IPv6 nexthop is + empty, use socket's remote address for the nexthop. + +2001-06-04 Kunihiro Ishiguro + + * bgpd.c (peer_delete): Fix memory leak. Reported by Yosi Yarchi + + +2001-06-01 Kunihiro Ishiguro + + * bgpd.c (bgp_delete): Fix memory leak. Reported by Yosi Yarchi + + +2001-05-27 Kunihiro Ishiguro + + * bgp_route.c (bgp_route_clear_with_afi_vpnv4): Use next instead + of ri->next. + + * bgp_packet.c (bgp_withdraw_send): MPLS/VPN withdraw takes effect + when HAVE_IPV6 is not defined. + +2001-03-07 "Akihiro Mizutani" + + * bgpd.c (peer_timers_set): Adjust keepalive timer to fit less + than holdtime / 3. + (bgp_confederation_peers_unset): Only set peer->local_as when + confederation is enabled. + (bgp_timers): Add "timers bgp <0-65535> <0-65535>" command. + + * bgp_route.c (bgp_announce_check): Set med of redistributed route + when it is announced to EBGP peer. + +2001-03-06 "Akihiro Mizutani" + + * bgp_nexthop.c (bgp_scan_ipv4): bgp_scan() call bgp_process() for + all prefixes. + +2001-03-06 Kunihiro Ishiguro + + * bgp_attr.c (bgp_attr_origin): When bgpd send NOTIFICATION with + erroneous attribute (type, length and value), it does include + attribute flags field. + +2001-02-21 "Akihiro Mizutani" + + * bgp_route.c (bgp_announce_check): The route reflector is not + allowed to modify the attributes of the reflected IBGP routes. + +2001-02-20 "Akihiro Mizutani" + + * bgp_route.c (bgp_info_cmp): During path seleciton, BGP + confederation peer is treated as same as IBGP peer. + +2001-02-19 Kunihiro Ishiguro + + * bgp_route.c (bgp_redistribute_add): Initialize attr_new with + attr. Call aspath_unintern when return from this function. + +2001-02-19 "Akihiro Mizutani" + + * bgpd.c (bgp_router_id_set): Reset BGP peer when router-id is + changed. + +2001-02-18 "Akihiro Mizutani" + + * bgp_packet.c (bgp_open_receive): When user configure holdtimer, + do not refrect the value to current session. + +2001-02-16 Kunihiro Ishiguro + + * bgp_route.c (bgp_aggregate_delete): Set BGP_INFO_ATTR_CHANGE to + suppress route withdraw. + + * bgp_damp.c (bgp_damp_init): Fix bug of flap dampening. + +2001-02-16 "Akihiro Mizutani" + + * bgp_aspath.c (aspath_make_str_count): Use ',' for separator for + AS_SET and AS_CONFED_SET. + +2001-02-15 Kunihiro Ishiguro + + * bgp_route.c (bgp_process): Do not consider suppress route. + + * bgp_aspath.c (aspath_aggregate_as_set_add): Reset asset when + aspath->data is realloced. + +2001-02-15 "Akihiro Mizutani" + + * bgp_attr.c (bgp_attr_aggregate_intern): Do not set atomic + aggregate when using as-set. + +2001-02-14 "Akihiro Mizutani" + + * bgpd.c (bgp_confederation_peers_unset): Set peer's local-as + correctly. + + * bgp_route.c (bgp_update): Just ignore AS path loop for + confederation peer. + +2001-02-10 Kunihiro Ishiguro + + * bgp_route.c (bgp_aggregate_set): Add as_set argument. + (bgp_aggregate_unset): Remove summary_only argument. + (aggregate_address_as_set): New commands. + "aggregate-address A.B.C.D/M as-set" + "no aggregate-address A.B.C.D/M as-set" + +2001-02-08 "Akihiro Mizutani" + + * bgp_route.c (bgp_announce_check): Do not modify nexthop when the + route is passed by route reflector. + +2001-02-08 Kunihiro Ishiguro + + * bgp_route.c: "no bgp dampening" with argument. + (bgp_announce_check): Do not modify nexthop when the route is + passed by route reflector. + +2001-02-07 "Akihiro Mizutani" + + * bgpd.c (neighbor_passive): Change "neighbor NEIGHBOR remote-as + ASN passive" to "neighbor NEIGHBOR passive". + (bgp_announce_check): Check well-known community attribute even + when "no neighbor send-community" is set. + +2001-02-03 Kunihiro Ishiguro + + * bgp_fsm.c (bgp_establish): Do not send keepalive at established + time when keepalive timer is configured as zero. + +2001-02-01 Kunihiro Ishiguro + + * bgp_attr.c (bgp_attr_check): When peer is IBGP peer, local + preference is well-known attribute. + +2001-01-30 Kunihiro Ishiguro + + * zebra-0.91 is released. + + * bgp_attr.h (struct attr): Comment out DPA value. + (struct attr): Change refcnt type from int to unsinged long. + + * bgp_attr.c (attrhash_key_make): Likewise. + (attrhash_cmp): Likewise. + (bgp_attr_dpa): Likewise. + +2001-01-30 "Akihiro Mizutani" + + * bgp_route.c (bgp_info_cmp): Make route selection completely same + as Cisco's. + +2001-01-30 Kunihiro Ishiguro + + * bgp_attr.h (BGP_ATTR_FLAG_OPTIONAL): Rename old ATTR_FLAG_* to + BGP_ATTR_FLAG_* to clarify meenings. + +2001-01-30 "Akihiro Mizutani" + + * bgp_route.c (route_vty_out): Display argument to suppress same + prefix information display. + (route_vty_out_route): Don't display mask information for + classfull network. + +2001-01-30 Kunihiro Ishiguro + + * bgp_attr.h (SET_BITMAP): Simple bitmapping macros. + + * bgp_attr.c (bgp_attr_parse): Use bitmap for attribute type + check. + +2001-01-29 Kunihiro Ishiguro + + * bgp_attr.c (bgp_mp_reach_parse): Enclose loggin with BGP_DEBUG. + (bgp_attr_parse): Comment out well-known attribute check. + +2001-01-28 Kunihiro Ishiguro + + * bgp_route.c (bgp_static_unset): Link-local IPv6 address can't be + used for network advertisement. + (nlri_parse): When link-local IPv6 address NLRI comes from + remote-peer, log the information then simply ignore it. + + * bgp_zebra.c (zebra_read_ipv6): Link-local IPv6 address is not + redistributed. + + * bgp_route.c (bgp_update): Check IPv6 global nexthop + reachability. + +2001-01-26 Kunihiro Ishiguro + + * bgp_route.c (bgp_update): Check nexthop points local address or + not. + (bgp_static_update_vpnv4): Set valid flag. + + * bgp_attr.c (bgp_attr_parse): Duplicate attribute check. + (bgp_attr_parse): Well-known attribute check. + + * bgp_open.c (bgp_auth_parse): Authentication is not yet supported. + + * bgp_packet.c (bgp_valid_marker): Check marker is synchronized. + + * bgpd.c (clear_bgp): Send NOTIFICATION Cease when SEND_CEASE is + defined. + + * bgp_snmp.c (bgp4PathAttrTable): Fix compile error. + +2001-01-24 Kunihiro Ishiguro + + * bgpd.c (bgp_network_import_check): New command for IGP network + check. + +2001-01-23 Kunihiro Ishiguro + + * bgp_nexthop.c (bgp_scan): Run bgp_process when IGP metric is + changed. Call bgp_process once for each node. + +2001-01-23 "Akihiro Mizutani" + + * bgp_route.c (bgp_info_cmp): Add IGP metric comparison. + +2001-01-23 Kunihiro Ishiguro + + * bgp_route.c (bgp_info_cmp): Add IGP metric comparison. + + * bgp_nexthop.c (bgp_nexthop_lookup): Set IGP metric for valid + IBGP route. + +2001-01-23 "Akihiro Mizutani" + + * bgp_route.c (show_ip_bgp_prefix_longer): Add new commands. + "show ip bgp A.B.C.D/M longer-prefixes" + "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes" + "show ipv6 bgp X:X::X:X/M longer-prefixes" + "show ipv6 mbgp X:X::X:X/M longer-prefixes" + +2001-01-20 "Akihiro Mizutani" + + * bgp_route.c (show_ip_bgp_cidr_only): Add new commands. + "show ip bgp cidr-only" + "show ip bgp ipv4 (unicast|multicast) cidr-only" + +2001-01-18 "Akihiro Mizutani" + + * bgp_route.c (bgp_update): AS path lookup check is done in + bgp_update() not in attr_parse(). + +2001-01-18 Kunihiro Ishiguro + + * bgp_route.c (bgp_update): Call bgp_aggregate_decrement() just + before bgp_attr_unintern(). + +2001-01-17 Kunihiro Ishiguro + + * bgp_route.c (bgp_update): Now intern is performed very last part + of the BGP packet update procedure. + +2001-01-17 "Akihiro Mizutani" + + * bgp_route.c (bgp_update): When implicit withdraw occur, reuse + existing bgp_info structure. + +2001-01-17 Kunihiro Ishiguro + + * bgp_route.c (bgp_aggregate_decrement): Fix bug of aggregate + address matching method. + (bgp_update): + + * bgp_nexthop.c (bgp_nexthop_onlink): Separate EBGP nexthop onlink + check and IBGP nexthop route check. + +2001-01-16 "Akihiro Mizutani" + + * bgp_route.h (BGP_INFO_ATRR_CHANGED): Added for track attribute + change. + +2001-01-16 Kunihiro Ishiguro + + * bgp_route.h (struct bgp_info): Remove selected flag. Use + BGP_INFO_SELECTED for flags instead. + (struct bgp_info): Remove valid flag. Use BGP_INFO_VALID for + flags instead. + (struct bgp_info): Add igpmetric for IBGP route nexthop IGP + metric. + (struct bgp_info_tab): Struct bgp_info_tag is integrated into + struct bgp_info. + (BGP_INFO_ATRR_CHANGED): Added for track attribute change. + + * bgp_community.c (community_val_get): gcc-2.95 on + sparc-sun-solaris cause crush. This function is for avoid the + crush. + +2001-01-15 Kunihiro Ishiguro + + * bgp_packet.c (bgp_open_receive): Translated peer's packet_size + clear bug is fixed. + +2001-01-14 "Akihiro Mizutani" + + * bgp_packet.c (bgp_open_receive): Return notification with + supported version number. + +2001-01-13 Kunihiro Ishiguro + + * bgpd.c (bgp_show_summary): Display AS path and community + entries. Suggested by: "Matt Ranney" . + + * bgp_packet.c (bgp_read_packet): Fix bug of unblocking BGP socket + read. When BGP packet read is partial, we must get size and type + from packet again. + +2001-01-12 "Akihiro Mizutani" + + * bgp_route.c (bgp_update): Do not unset BGP_INFO_HISTORY flag. + (bgp_update): When there is a history entry increment route count. + (bgp_damp_set): Check BGP_CONFIG_DAMPENING flag. + + * bgp_damp.c (bgp_damp_withdraw): Set status to + BGP_DAMP_DISCONTINUE. + +2001-01-11 Kunihiro Ishiguro + + * bgp_attr.c (bgp_mp_reach_parse): Fix warning code when second + IPv6 nexthop is not link-local addresss. + +2001-01-11 "Akihiro Mizutani" + + * bgp_damp.c (bgp_config_write_damp): Smart flap dampening + configuration display. + (bgp_damp_info_print): Display elapsed time from flap started. + + * bgp_damp.h (struct bgp_damp_info): Add flap start time. + + * bgpd.c (peer_create): Set last read time. + (bgp_show_peer): Display last read time. + (bgp_show_summary): Use BGP_CONFIG_DAMPENING flag to check + configuration. + + * bgpd.h (BGP_CONFIG_DAMPENING): Add new configuration option. + (struct peer): Add last read time member. + (BGP_VERSION_MP_4): Remove obsolete definition. + +2001-01-10 Kunihiro Ishiguro + + * bgp_nexthop.c: Remove OLD_RIB codes. + + * bgp_route.c (bgp_process): Likewise. + + * zebra-0.90 is released. + + * bgp_route.h (BGP_INFO_HISTORY): Remove damped member from struct + bgp_info. Instead of that use BGP_INFO_DAMPED flag. + (struct bgp_info): Remove invalid member from struct bgp_info. + Instead of that use BGP_INFO_HISTORY flag. + +2001-01-10 "Akihiro Mizutani" + + * bgp_damp.c (bgp_damp_info_print): New function to display + dampening status. + (DEFAULT_HARF_LIFE): Define default value. + (DEFAULT_REUSE): Likewise. + (DEFAULT_SUPPRESS): Likewise. + (bgp_config_write_damp): When config value is same as default + value, simply display "bgp dampening" to configuration. + + * bgp_damp.h (struct bgp_damp_info): Add flap member. + + * bgp_route.h (struct bgp_info): Added for BGP flap dampening + history status. + +2001-01-10 Kunihiro Ishiguro + + * bgp_nexthop.c (bgp_connected_add): Point-to-point connected + address is properly handled. + (bgp_connected_delete): Likewise. + + * bgp_route.c (bgp_route_init): Turn off BGP Flap dampening code + until it works fine. + +2001-01-09 Kunihiro Ishiguro + + * bgpd.c (bgp_show_summary): Add BGP_VERSION_MP_4 case. + + * bgp_route.c (bgp_update): When this is not damped route, clear + ri pointer. + +2001-01-09 Kunihiro Ishiguro + + * bgp_main.c: Add "-n" no_kernel option to not install route to + kernel. Suggested by: "Matt Ranney" + +2001-01-09 Kunihiro Ishiguro + + * bgp_nexthop.c (bgp_connected_add): Revert point-to-point + connected route patch. Reported by ruud@ruud.org (Ruud de Rooij) + + * bgp_damp.c (bgp_config_write_damp): Add configuration display + function. + + * bgp_route.c (bgp_info_free): Set NULL to BGP dampening + information when BGP info structure is freed. + (bgp_info_cmp): Check damped flag. + (bgp_announce_check): Damped route is not announced. + +2001-01-09 "Akihiro Mizutani" + + * bgpd.c (neighbor_capability_route_refresh): Change "neighbor + route-refresh" command to "neighbor capability route-refresh". + (clear_bgp_soft_in): Change soft-reconfig method. + + clear ip bgp soft in + -------------------------------------- + Try stored cache first then route-refresh + + clear ip bgp in + --------------------------------- + Try route-refresh first then try to use stored cache + +2001-01-09 Kunihiro Ishiguro + + * bgp_nexthop.c (bgp_connected_add): Check point-to-point + connected route. Reported by ruud@ruud.org (Ruud de Rooij) + +2001-01-08 Kunihiro Ishiguro + + * bgp_nexthop.c (bgp_nexthop_lookup): When IBGP nexthop is + changed, refresh it. + +2001-01-04 Kunihiro Ishiguro + + * bgp_route.h (struct bgp_info_tag): Add as_selected to + bgp_info_tag. + +2001-01-03 Kunihiro Ishiguro + + * bgp_route.h (struct bgp_info_tag): Add damped and bgp_damp_info + member for BGP flap dampening. + + * bgp_damp.c: New file is added. + + * bgp_damp.h: Likewise. + +2001-01-01 Kunihiro Ishiguro + + * bgpd.h (BGP_VTYSH_PATH): Change "/tmp/bgpd" to "/tmp/.bgpd". + +2000-12-29 Kunihiro Ishiguro + + * bgp_nexthop.c (zlookup_connect): Change to use UNIX domain + socket for zebra communication. + +2000-12-29 Akihiro Mizutani + + * bgp_route.c (bgp_process): Fix "bgp deterministic-med" process. + +2000-12-27 Akihiro Mizutani + + * bgp_route.c (bgp_process): Add "bgp deterministic-med" process. + +2000-12-25 Akihiro Mizutani + + * bgp_route.c (bgp_info_cmp): Use ntohl comparing router ID. + +2000-12-18 Akihiro Mizutani + + * bgp_route.c (bgp_info_cmp): When over three same prefix exit, + withdrawing best prefix perform router ID comparison. + +2000-12-15 Akihiro Mizutani + + * bgp_route.c (bgp_info_cmp): Do not compare router ID when the + routes comes from EBGP peer. When originator ID is same, take + shorter cluster-list route. If cluster-list is same take smaller + IP address neighbor's route. + + * bgpd.c (bgp_bestpath_aspath_ignore): Add "bgp bestpath as-path + ignore" command. When this option is set, do not concider AS path + length when route selection. + (bgp_bestpath_compare_router_id): Add "bgp bestpath + compare-routerid". When this option is set, compare router ID + when the routes comes from EBGP peer. + +2000-12-15 Akihiro Mizutani + + * bgp_route.c (bgp_info_cmp): Compare originator ID when it is + available. + +2000-12-14 Akihiro Mizutani + + * bgp_packet.c (bgp_notify_receive): Disply received Notify data + information. + +2000-12-14 Kunihiro Ishiguro + + * bgp_filter.c (as_filter_free): Use MTYPE_AS_FILTER_STR to make + it sure the memory is freed. + + * bgp_route.c (route_vty_out_detail): Do not use AF_INET6 outside + HAVE_IPV6. + +2000-12-08 Akihiro Mizutani + + * bgp_packet.c (bgp_notify_send_with_data): Store BGP notification + data part. + + * bgp_network.c (bgp_accept): When BGP connection comes from + unconfigured IP address, close socket immediately. + + * bgpd.c: Fix some display format. + +2000-11-29 Kunihiro Ishiguro + + * bgp_packet.c (bgp_keepalive_send): Delete duplicate + bgp_packet_set_size () call. + +2000-11-28 Kunihiro Ishiguro + + * bgp_packet.c (bgp_read_packet): Remove debug codes. + +2000-11-27 Kunihiro Ishiguro + + * bgp_snmp.c (write_bgpPeerTable): Add SNMP set method routine. + + * bgp_fsm.c (bgp_stop): Use fsm_change_status to change peer's + status. + (bgp_establish): Likewise. + +2000-11-26 Akihiro Mizutani + + * bgp_open.c: Fix error messages. + +2000-11-25 Kunihiro Ishiguro + + * bgp_fsm.c (bgp_establish): Call BGP trap when the peer is + established. + (bgp_stop): Call BGP trap when the peer is dropped. + +2000-11-24 Kunihiro Ishiguro + + * bgp_snmp.c (bgp4PathAttrTable): Return BGP path attribute table. + + * bgpd.h (struct peer): Add update_time for track last update + received time. + + * bgp_packet.c (bgp_notify_receive): Preserv notify code and sub + code in any case. + + * bgp_snmp.c (bgpPeerTable): Return remote router ID instead of + peering IP address. + (bgpPeerTable): Return actual BGP version number. + +2000-11-22 Akihiro Mizutani + + * bgp_debug.c (bgp_notify_print): Notify data length display bug + is fixed. + +2000-11-16 Kunihiro Ishiguro + + * bgp_nexthop.c (zlookup_connect): When UNIX domain connection to + zebra is enabled, use the method. + +2000-11-16 Akihiro Mizutani + + * bgpd.c: Revise debug message output. + +2000-11-15 Akihiro Mizutani + + * bgp_clist.c (ip_community_list): Fix bug of string comparison. + +2000-11-14 Akihiro Mizutani + + * bgp_community.c (community_match): Fix bug of memcmp return + value check. + +2000-11-07 Kunihiro Ishiguro + + * bgp_clist.c (community_list_match_exact): Add check for + entry->style is COMMUNITY_LIST. + (community_match_regexp): Apply new com_nthval macro. + +2000-11-07 Rick Payne + + * bgp_routemap.c (route_set_community_delete): "set + community-delete COMMUNITY-LIST" is added. + + * bgp_community.c (community_del_val): Delete one community. + (community_delete): Delete all community included in list. + (community_match): Fix bug of matching community value. + + * bgp_clist.c (community_entry_free): Free community regular + expression. + (community_entry_make): Default style is COMMUNITY_LIST. + (community_entry_lookup): Make it sure style is COMMUNITY_LIST. + (community_entry_regexp_lookup): New function for community + regular expression lookup. + (community_match_regexp): New function. + (community_delete_regexp): New function. + (community_list_delete_entries): New function. + (community_list_match): Add COMMUNITY_REGEXP treatment. + (community_list_match_exact): Likewise. + (config_write_community): Write community list according to + entry->style. + +2000-11-07 Rick Payne + + * bgp_attr.c (bgp_attr_aspath): AS path first AS check. + + * bgp_clist.c (struct community_entry): Add style, regexp, reg to + community_entry. + +2000-11-06 Rick Payne + + * bgp_aspath.c (aspath_firstas_check): AS path first AS check. + + * bgpd.c (bgp_enforce_first_as): New command "bgp + enforce-first-as". + + * bgpd.h (BGP_CONFIG_ENFORCE_FIRST_AS): Add new flag. + +2000-11-06 Kunihiro Ishiguro + + * bgp_community.c (community_compare): Copy byte stream data to + actual value instead of using type casting hack. + (community_add_val): Likewise. + (community_uniq_sort): Likewise. + (community_print): Likewise. + (community_print_vty): Likewise. + (community_include): Use memcmp to compare community value. + + * bgp_community.h (com_lastval): com_lastval and com_nthval macro + return pointer. + +2000-11-06 Akihiro Mizutani + + * bgpd.h (struct peer): Add established and dropped member for + count peering up/down statistics. + + * bgpd.c (bgp_show_peer): Display peering up/down statistics. + + * bgp_fsm.c (bgp_establish): Increment established count. + (bgp_stop): Increment dropped count. + + * bgp_packet.c (bgp_notify_receive): Increament notify count. + +2000-11-1 Akihiro Mizutani + + * bgp_fsm.c: Fix bug of holdtimer is not reset when bgp cleared. + +2000-10-31 Kunihiro Ishiguro + + * bgpd.h: Static bit flag is set by (1 << DIGIT). + +2000-10-24 Akihiro Mizutani + + * bgp_ecommunity.c (ecommunity_dup): Extended community display + format fix. + +2000-10-24 Arkadiusz Miskiewicz + + * bgp_network.c (bgp_serv_sock_addrinfo): Use gai_strerror. + (bgp_serv_sock_addrinfo): Check address family. + +2000-10-23 Jochen Friedrich + + * bgp_snmp.c: bgp_oid and bgpd_oid are used in smux_open after it + is registered. So those variables must be static. + +2000-10-23 Akihiro Mizutani + + * bgp_routemap.c (route_match_ip_next_hop): Change "match ip + next-hop" argument from IP address to access-list name. + Remove zebra-0.88 compatibility commands. + "match ip prefix-list WORD" + "match ipv6 prefix-list WORD" + +2000-10-23 Kunihiro Ishiguro + + * bgp_routemap.c (route_match_ipv6_next_hop_compile): Fix bug of + passing the pointer to the pointer of struct in6_addr instead of + the pointer of struct in6_addr in "match ipv6 next-hop" command. + + * bgp_route.c (bgp_announce_check): Enclose IPv6 part with + HAVE_IPV6. + +2000-10-20 Jasper Wallace + + * bgp_snmp.c (bgpPeerTable): ntohs missing bug is fixed. Change + to use linklist.c. Define COUNTER32 as ASN_COUNTER. + +2000-10-18 Kunihiro Ishiguro + + * bgp_route.c (bgp_announce_check): attr->nexthop empty check + should be done by attr->nexthop.s_addr instead of strcmp. + +2000-10-18 Akihiro Mizutani + + * bgp_zebra.c (zebra_read_ipv4): Pass nexthop value to + bgp_redistribute_add(). + + * bgp_nexthop.c (bgp_multiaccess_check_v4): New function for + checking IPv4 multiaccess nexthop. + + * bgp_route.c (bgp_announce_check): In case of the nexthop is + reachable on multiaccess media, do not change nexthop. + (bgp_redistribute_add): Set nexthop when the value is passed. + +2000-10-17 Kunihiro Ishiguro + + * bgp_fsm.c (bgp_timer_set): If peer is passive mode, do not set + connect timer. + (bgp_start): If the peer is passive mode, force to move to Active + mode. + +2000-10-17 Horms + + * bgp_debug.c (debug_bgp_fsm): Fix typo. + +2000-10-17 Akihiro Mizutani + + * bgp_route.c: "show ipv6 bgp" route display improvement. + +2000-10-03 Kunihiro Ishiguro + + * bgp_route.c (neighbor_routes): Allocate sockunion for callback + function. + (bgp_show_neighbor_route): Remove static declaration for union + sockunion. + + * bgpd.c (peer_update_source_set): Clean previously allocated + memory before allocate new one. + +2000-10-03 Akihiro Mizutani + + * bgp_route.c (neighbor_routes): Add show neighbor's routes + command. + "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes" + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes" + "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes" + "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes" + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 is released. + +2000-10-02 Akihiro Mizutani + + * bgpd.c: "bgp deterministic-med" command is added. + +2000-10-02 Kunihiro Ishiguro + + * bgp_nexthop.c (bgp_connected_add): Apply mask for connected + route addition and deletion. + +2000-09-29 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_cmp_left): Skip confederation AS segment + when comparing leftmost AS number. + +2000-09-29 Akihiro Mizutani + + * bgpd.c (peer_route_reflector): Route reflector can be set for + IBGP peer. + (bgp_distribute_set): Fix bug of string check for (in|out). + (bgp_show_summary): Display total neighbor count. + +2000-09-28 Akihiro Mizutani + + * bgp_attr.c (bgp_packet_attribute): Only add cluster_list and + originator for clinet to client routes. + (bgp_packet_attribute): Add new cluster_list to the beginning of + existing cluster_list. + (bgp_packet_attribute): Fix bug of originator is rewritten even + when originator is already set. + +2000-09-27 Kunihiro Ishiguro + + * bgpd.c (bgp_client_to_client_reflection): Add new command. + "no bgp client-to-client reflection" + "bgp client-to-client reflection" + + * bgpd.h (BGP_CONFIG_NO_CLIENT_TO_CLIENT): Add new definition. + +2000-09-26 Kunihiro Ishiguro + + * bgp_packet.c (bgp_read): Make BGP packet read to non-blocking + read. + (bgp_read_packet): Likewise. + (bgp_read_packet): When errono is EAGAIN, try to read it again. + + * bgp_fsm.c (bgp_stop): Clear packet size and read buffer. + +2000-09-26 Akihiro Mizutani + + * bgp_routemap.c: Configuration of prefix-list match is shown as + "match ip address prefix-list ". Old configuration "match + ip prefix-list " is left for compatibilitty. + +2000-09-25 Akihiro Mizutani + + * bgpd.h (BGP_CONFIG_MED_MISSING_AS_WORST): Changed from + BGP_CONFIG_MISSING_AS_WORST. + + * bgpd.c (bgp_bestpath_med): Change missing-as-worst syntax. + Old "bgp bestpath missing-as-worst" + New "bgp bestpath med missing-as-worst" + +2000-09-24 Akihiro Mizutani + + * bgp_route.c: Compare MED properly in case of CONFED-IBGP. + +2000-09-21 steve@Watt.COM (Steve Watt) + + * bgp_debug.h: Do not declare debug variables conf_bgp_debug_* and + term_bgp_debug_*. + + * bgp_debug.c: Declare variables here. + +2000-09-21 Akihiro Mizutani + + * bgpd.c: MBGP soft-reconfiguration command is added. + clear ip bgp x.x.x.x ipv4 (unicast|multicast) in + clear ip bgp x.x.x.x ipv4 (unicast|multicast) out + clear ip bgp x.x.x.x ipv4 (unicast|multicast) soft + clear ip bgp <1-65535> ipv4 (unicast|multicast) in + clear ip bgp <1-65535> ipv4 (unicast|multicast) out + clear ip bgp <1-65535> ipv4 (unicast|multicast) soft + clear ip bgp * ipv4 (unicast|multicast) in + clear ip bgp * ipv4 (unicast|multicast) out + clear ip bgp * ipv4 (unicast|multicast) soft + + Change "clear ip bgp vpnv4 x.x.x.x soft" command to + "clear ip bgp x.x.x.x vpnv4 unicast soft". + + "bgp bestpath med confed" command is added. + + * bgpd.h (BGP_CONFIG_MED_CONFED): Add New definition. + +2000-09-18 Rick Payne + + * bgpd.c (bgp_show_peer): Fix misplaced #endif. + +2000-09-12 Akihiro Mizutani + + * bgpd.c (bgp_default_local_preference): Add "bgp default + local-preference" command. + + * bgp_nexthop.c (no_bgp_scan_time): Add "no bgp scan-time" + command. + +2000-09-10 Kunihiro Ishiguro + + * bgp_zebra.c (bgp_zebra_announce): BGP confederation peer's routes + are passed to zebra like IBGP route. + +2000-09-10 Akihiro Mizutani + + * bgpd.c (bgp_config_write_peer): Make it consistent passive + configuration. + + * bgp_route.c: Community match command is added. + "show ip bgp community " + "show ip bgp community exact-match" + +2000-09-08 Kunihiro Ishiguro + + * bgp_nexthop.c (bgp_nexthop_lookup): ebgp-multihop routes are + treated as IBGP routes. + +2000-09-08 Akihiro Mizutani + + * bgp_route.c (bgp_show_route): When local-AS community route is + selected, display "not advertised outside local AS" to "show ip + route A.B.C.D" output. + (show_ip_bgp_ipv4_filter_list): Add below four commands. + "show ip bgp ipv4 (unicast|multicast) filter-list WORD" + "show ip bgp ipv4 (unicast|multicast) community" + "show ip bgp ipv4 (unicast|multicast) community-list WORD" + "show ip bgp ipv4 (unicast|multicast) community-list WORD exact-match" + + * bgp_clist.c (community_list_match_exact): Community exact match + function. + +2000-09-07 Kunihiro Ishiguro + + * bgp_route.c (bgp_update): Add peer's ttl check. + + * bgpd.h (struct peer): Structure member refresh is renamed to + refresh_adv. + + * bgpd.c (clear_bgp_soft_in): Check PEER_FLAG_ROUTE_REFRESH flag + when soft reconfiguration is performed. + + * bgp_zebra.c (bgp_zebra_announce): When the peer is EBGP and + ebgp-multiphop is set, set ZEBRA_FLAG_INTERNAL for nexthop lookup. + + * bgp_route.h (struct bgp_info_tag): Add valid flag. + +2000-08-25 Akihiro Mizutani + + * bgpd.c: Add AS base BGP soft reconfiguration. + + * bgp_route.c: When no-advertise or no-export route is selected, + "show ip bgp" display "not advertised to EBGP peer" or "not + advertised to any peer" message. + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 is released. + + * bgp_dump.c (dump_bgp_routes): Change "dump bgp routes" to "dump + bgp route-mrt" to support MRT specific dump format. + + * bgpd.c (bgp_init): "clear ip bgp vpnv4 soft {in,out}" command is + added. + + * bgp_route.c (bgp_update): Currently nexthop check is only works + for IPv4. + +2000-08-17 Akihiro Mizutani + + * bgpd. (clear_ip_bgp_all_soft): Add "clear ip bgp * soft" for + both inbound and outbound soft reconfiguration. + +2000-08-17 Kunihiro Ishiguro + + * bgpd.c (clear_ip_bgp_peer_soft_out): Add soft-reconfiguration + outbound. + (peer_new): Set route-refresh flag. + +2000-08-16 Akihiro Mizutani + + * bgpd.c: "no bgp router-id A.B.C.D" alias is added. "no bgp + cluster-id A.B.C.D" alias is added. " bgp cluster-id + <1-4294967295>" alias is added. "clear ip bgp * soft in" command + is added. "clear ip bgp A.B.C.D in" alias is added. "clear ip + bgp * in" alias is added. + +2000-08-16 Kunihiro Ishiguro + + * bgp_route.c (bgp_update): Add soft_reconfig flag. When the flag + is set do not install the route into Adj-RIBs-In. + (bgp_update): Perform implicit withdraw before filtering of the + route. + + * bgp_packet.c (bgp_read): draft-ietf-idr-bgp-route-refresh-01.txt + capability code and BGP message can be accepted. + + * bgp_open.c (bgp_capability_parse): Likewise. + + * bgp_route.c (bgp_refresh_table): New function for route refresh. + (bgp_refresh_rib): Likewise. + + * bgpd.c (bgp_show_peer): Display route refresh status. + + * bgp_route.c (bgp_aggregate_add): Add check for the route + validness. + (bgp_aggregate_delete): Likewise. + +2000-08-15 Kunihiro Ishiguro + + * bgp_nexthop.c (bgp_scan): Care for aggregate route when the + route become inaccessible. + +2000-08-15 Akihiro Mizutani + + * bgp_route.c (show_ip_bgp_prefix): "show ip bgp A.B.C.D/M" + command is added. + +2000-08-15 Kunihiro Ishiguro + + * bgp_zebra.c (bgp_interface_up): Register connected route. + (bgp_interface_down): Unregister connected route. + +2000-08-14 Kunihiro Ishiguro + + * bgp_route.h (struct bgp_info): Add distance to the structure. + + * bgp_route.c (bgp_aggregate_increment): Aggregate route only + match to smaller prefixlen route not match same prefixlen route. + (bgp_aggregate_decrement): Likewise. + (bgp_aggregate_add): Likewise. + (bgp_aggregate_delete): Likewise. + (bgp_network_backdoor): Add backdoor network configuration. + + * bgpd.h (struct bgp ): Add distance_{ebgp,ibgp,local} for store + configuration distance value. + + * bgp_route.c (bgp_update): Filter EBGP route which has non + connected nexthop. + + * bgp_attr.c (bgp_attr_aggregate_intern): New function for + aggregate route. Set origin to IGP. Set atomic aggregate flag. + Set aggregator AS and address. + (bgp_attr_aggregate_intern): Check BGP_CONFIG_CONFEDERATION when + filling aggregator_as. + + * bgp_route.c (bgp_process): Delete suppress check for install + suppressed route into local routing table. + (bgp_aggregate_increment): Use bgp_attr_aggregate_intern() instead + of bgp_attr_default_intern (). + (bgp_aggregate_add): Likewise. + + * bgpd.c (bgp_get): Call bgp_if_update_all() after BGP instance is + created. This is for avoid 0.0.0.0 router-id. + +2000-08-13 Akihiro Mizutani + + * bgp_route.c (route_vty_out_detail): Display "valid" when the + route is valied. Display "aggregated" when the route is + aggregated. "Advertisements suppressed by an aggregate" is + displayed when the route is suppressed. + (bgp_info_cmp): Prefer EBGP than Confed-EBGP. + +2000-08-10 Akihiro Mizutani + + * bgp_route.c (route_vty_out_detail): Display format change. + +2000-08-06 Kunihiro Ishiguro + + * bgp_route.c (bgp_update): Only AFI_IP nexthop check is enabled. + + * bgpd.c (bgp_delete): Delete static route before delete peer + configuration. + +2000-08-02 Kunihiro Ishiguro + + * bgpd.c: Include bgpd/bgp_nexthop.h. + +2000-07-31 Akihiro Mizutani + + * bgpd.c (bgp_show_summary): "show ip bgp summary" shows own BGP + identifier. And status is changed like below. + + State/Pref -> State/PfxRcd + Shutdown -> Idle (Admin) + PrefixOvflw -> Idle (PfxCt) + + * bgp_route.c (route_vty_out): Show internal route as "i". + +2000-07-13 Jim Bowen + + * bgp_snmp.c: Add BGP peer MIB implementation. + +2000-07-12 Akihiro Mizutani + + * bgpd.c (bgp_show_peer): Fix typo. + +2000-07-11 Akihiro Mizutani + + * bgp_routemap.c: Add commands for deleting set without argument. + +2000-07-03 Akihiro Mizutani + + * bgp_zebra.c: Fix redistribute help strings. + +2000-07-01 Kunihiro Ishiguro + + * bgp_route.c (bgp_show): When bgpd works as vtysh server send all + output to vty at once. + +2000-06-13 Kunihiro Ishiguro + + * bgp_mplsvpn.c (no_vpnv4_network): "no network A.B.C.D/M rd WORD + tag WORD" command is added. + + * bgp_ecommunity.c (ecommunity_vty_out): New function added. + +2000-06-12 Kunihiro Ishiguro + + * bgp_route.c (bgp_show): Fix total number of prefix count bug. + + * bgpd.c (bgp_show_peer): Display VPNv4 unicast configuration and + negotiation result in "show ip bgp neighbors". + +2000-06-12 Akihiro Mizutani + + * bgpd.c: Fix help strings. + + * bgpd.h: Likewise. + +2000-06-11 Kunihiro Ishiguro + + * bgp_route.c (bgp_aggregate_unset): Fix bug of checking rn->info + instead of rn. Reported by Akihiro Mizutani . + + * bgp_mplsvpn.c (vpnv4_network): For testing purpose, "network + A.B.C.D rd RD" is added to address-family vpnv4 unicast node. + + * bgp_route.c (bgp_static_set): Set safi to p.safi. + +2000-06-10 Kunihiro Ishiguro + + * bgp_route.c (bgp_show_prefix_list): Change to use bgp_show(). + (bgp_show_regexp): Change to use bgp_show(). + (show_adj_route): Change to display header. + + * bgpd.c (clear_bgp): Set peer->v_start to default value when peer + is cleared manually. + + * bgp_route.c (bgp_show_route): New function which display + specific BGP route. Divided from bgp_show(). + (bgp_static_delete): Delete all static route. + +2000-06-09 NOGUCHI Kay + + * bgp_route.c (show_ipv6_bgp): "show ipv6 bgp" is broken with + invalid privious fix. Now show_ipv6_bgp and show_ipv6_bgp_route + take care of "show ipv6 bgp [X:X::X:X]". Same change for "show ip + mbgp" and "show ipv6 mbgp". + +2000-06-07 Akihiro Mizutani + + * bgp_route.c: Fix help strings and command arguments. + +2000-06-06 Kunihiro Ishiguro + + * bgp_ecommunity.c: Include prefix.h + +2000-06-05 Kunihiro Ishiguro + + * bgp_route.h (struct bgp_info_tag): New structure to hold tag + value. + + * bgp_route.c (bgp_adj_set): table NULL check is added. + (bgp_adj_unset): Likewise. + (bgp_adj_lookup): Likewise. + (bgp_adj_clear): Likewise. + (route_vty_out): Add SAFI check for nexthop display. + (bgp_withdraw): Add SAFI check for withdraw route. + + * Remove all #ifdef MPLS_VPN then include it as default. + + * bgpd.c: Temporary disable peer-group command until the + implementation is completed. + + * bgp_routemap.c (bgp_route_map_init): Install + route_metric_match_cmd. + (route_match_metric_compile): MED value compile using strtoul. + +2000-06-05 Akihiro Mizutani + + * bgp_filter.c: Fix help strings. Change REGEXP to LINE. Change + NAME to WORD. + + * Change command argument to more comprehensive. + + METRIC -> <0-4294967295> + WEIGHT -> <0-4294967295> + LOCAL_PREF -> <0-4294967295> + IP_ADDR -> A.B.C.D + AS -> <1-65535> + AS-PATH-NAME -> WORD + ACCESS_LIST -> WORD + PREFIX_LIST -> WORD + COMMUNITY -> AA:NN + EXT_COMMUNITY -> ASN:nn_or_IP-address:nn + IPv6_ADDR -> X:X::X:X + + * bgp_clist.c: Fix help strings. + +2000-06-03 Kunihiro Ishiguro + + * bgpd.c (peer_active): Add new function for check the peer is + active or not. + (neighbor_activate): New command "neighbor PEER activate" and "no + neighbor PEER activate" are added. + + * bgp_packet.c: Include bgpd/bgp_mplsvpn.h. + +2000-06-02 Akihiro Mizutani + + * bgp_clist.c: Fix commuity-list help strings. + + * bgp_routemap.c: Fix "set community" help strings. Add #define + SET_STR. Use (unicast|multicast) argument for "set nlri" command. + +2000-06-01 Kunihiro Ishiguro + + * bgp_routemap.c (route_set_community_none_cmd): "set community + none" command is added to route-map. + +2000-06-01 Akihiro Mizutani + + * bgp_debug.c: Change "show debug" to "show debugging". Now "show + debugging" is not used in VIEW_NODE. + +2000-05-30 Kunihiro Ishiguro + + * bgp_fsm.c (bgp_timer_set): Add check for shutdown flag. This + fix unconditional BGP connection. + + * bgpd.c (peer_shutdown): Replace peer_shutdown() with + peer_change_flag_with_reset(). + +2000-05-26 Kunihiro Ishiguro + + * bgpd.c (no_bgp_default_ipv4_unicast): Add "no bgp default + ipv4-unicast" command. + + * bgpd.h (BGP_CONFIG_NO_DEFAULT_IPV4): Add new definition. + + * bgp_filter.c (as_list_delete): Free all AS filter. + + * bgp_clist.c (community_list_delete): Free all community entry. + + * bgp_filter.c (no_ip_as_path_all): New DEFUN for "no ip as-path + access-list NAME". + + * bgp_clist.c (no_ip_community_list_all): New DEFUN for "no ip + community-list NAME". + +2000-05-19 Kunihiro Ishiguro + + * bgp_route.c (ipv6_mbgp_neighbor_routes): Change "show ip bgp PEER + routes" to "show ip bgp PEER received-routes" + +2000-05-14 Kunihiro Ishiguro + + * bgp_ecommunity.c (ecommunity_parse): New file for Extended + Communities attribute. + * bgp_ecommunity.h: Likewise. + +2000-05-11 Kunihiro Ishiguro + + * bgp_mplsvpn.h: New file for MPLS-VPN. + * bgp_mplsvpn.c: Likewise. + + * bgpd.c (bgp_delete): Fix bug of "no router bgp" crush. + +2000-05-10 Kunihiro Ishiguro + + * bgpd.c (bgp_bestpath_missing_as_worst): Add "bgp bestpath + missing-as-worst". + +2000-05-08 Kunihiro Ishiguro + + * bgp_routemap.c (match_community): Clarify help of "match + community". + +2000-05-02 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_cmp_left): Remove debug code. + +2000-04-27 Kunihiro Ishiguro + + * bgp_route.c (bgp_info_cmp): Compare MED only both routes comes + from same neighboring AS. + + * bgp_aspath.c (aspath_cmp_left): Compare leftmost AS value. + + * bgp_route.c (bgp_info_cmp): Fix misused htonl() to ntohl(). + +2000-04-26 Kunihiro Ishiguro + + * bgp_route.c (bgp_output_filter): When distribute-list's + corresponding access-list does not exist, filter all routes. + (bgp_input_filter): Likewise. + +2000-04-19 Kunihiro Ishiguro + + * bgp_attr.c (bgp_packet_attribute): Propagate MED to IBGP peer. + + * bgp_route.c (bgp_info_cmp): Add evaluation of local preference. + +2000-04-18 Kunihiro Ishiguro + + * bgpd.c (bgp_distribute_update): Add struct access_list * + argument. + +2000-04-17 Kunihiro Ishiguro + + * bgp_clist.c (community_list_dup_check): Add duplicate insertion + check. + + * bgp_filter.c (as_list_dup_check): Add duplicate insertion check. + + * bgp_route.c (bgp_show): Fix undeclared write variable. + +2000-04-13 Kunihiro Ishiguro + + * bgp_routemap.c: Add "match ip address prefix-list". + +2000-03-29 Rick Payne + + * bgp_aspath.c (aspath_strip_confed): Fix realloc problem. + +2000-03-16 Kunihiro Ishiguro + + * bgp_fsm.c (bgp_reconnect): Connect retry timer is expired when + the peer status is Connect. + +2000-03-03 Kunihiro Ishiguro + + * Fix bug of rewritten originator-id. + +2000-01-27 Rick Payne + + * bgp_aspath.c (aspath_delimiter_char): New function. Instead of + directly referencing array, search proper AS path delimiter. + (aspath_strip_confed): Strip the confederation stuff from the + front of an AS path. + (aspath_add_left_confed): New function for adding specified AS to + the leftmost AS_CONFED_SEQUENCE. + + * bgp_aspath.h: Change AS_CONFED_SEQUENCE and AS_CONFED_SET value + to Cisco compatible. + + * bgpd.c (bgp_confederation_id_set): Confederation configuration. + (bgp_confederation_id_unset): Likewise. + (bgp_confederation_peers_check): Likewise. + (bgp_confederation_peers_add): Likewise. + (bgp_confederation_peers_remove): Likewise. + (bgp_confederation_peers_set): Likewise. + (bgp_confederation_peers_unset): Likewise. + (bgp_confederation_peers_print): Likewise. + +2000-01-16 Kunihiro Ishiguro + + * bgpd.c: Introduce peer_change_flag_with_reset() fucntion. + +2000-01-17 Kunihiro Ishiguro + + * bgp_open.c (bgp_open_option_parse): When there is no common + capability send Unsupported Capability error to the peer. + +2000-01-14 Kunihiro Ishiguro + + * bgp_open.c (bgp_capability_mp): Fix bug of mis-negotiation about + IPv6 unicast. + + * bgpd.c (bgp_init): Add "soft-reconfiguration inbound" command. + +2000-01-12 Kunihiro Ishiguro + + * bgpd.c (neighbor_strict_capability): Add + "strict-capability-match" command. + + * bgp_zebra.c (bgp_if_update): Ignore NET127 determining + router-id. + + * bgpd.c (peer_override_capability): Add "override-capability" + command. + +1999-12-16 Kunihiro Ishiguro + + * bgp_packet.c (bgp_write): Change status to Idle and set timer + after write failed. + +1999-12-14 Kunihiro Ishiguro + + * bgp_zebra.c (bgp_zebra_announce): Add info->selected check. + +1999-12-12 Kunihiro Ishiguro + + * bgp_route.c (nlri_unfeasible): nlri_unfeasible() is merged with + nlri_parse(). + +1999-12-10 Kunihiro Ishiguro + + * bgp_fsm.h (BGP_EVENT_DELETE): Macro added. + + * bgp_fsm.c (bgp_stop): Clear all event threads of the peer when + the peer is cleared. + + * bgp_zebra.c (bgp_nexthop_set): Clear interface index of + link-local address. This is KAME specific problem. + +1999-12-06 Kunihiro Ishiguro + + * bgp_attr.c (bgp_mp_reach_parse): Comment out previous code for a + while. We don't completely detect the link is shared or not at + this moment. + + * bgp_packet.c (bgp_notify_send): Make shortcut call of + bgp_write() and bgp_stop(). + + * bgp_attr.c (bgp_mp_reach_parse): Fix serious bug when getting + global and link-local address. + +1999-12-05 Kunihiro Ishiguro + + * bgpd.c (no_neighbor_port): New command added. + (peer_new): Set send_community. + +1999-12-04 Kunihiro Ishiguro + + * bgpd.c (show_ip_bgp_summary): Changed to use bgp_show_summary(). + (show_ip_mbgp_summary): Likewise. + (show_ipv6_bgp_summary): Likewise. + (show_ipv6_mbgp_summary): Add new command. + (peer_free): Free peer->host. + (peer_lookup_by_su): Delete function. + (ipv6_bgp_neighbor): Changed to use peer_remote_as(). + (sockunion_vty_out): Function deleted. + (vty_clear_bgp): Use afi instead of family. + Delete old list bgp_list. Use struct newlist *bgplist. + (peer_lookup_by_host): Function deleted. + +1999-12-03 Kunihiro Ishiguro + + * bgpd.h (struct peer_group): New structure added. + (struct peer_conf): New structure added. + (struct peer): Change all prefix_count to unsigned long. + + * bgpd.c: Reconstruct all of VTY commands reflect internal + structure change. + Use bgplist instead of bgp_list. + Use peerlist intstead of peer_list. + + * bgp_attr.c (bgp_mp_reach_parse): If nlri_parse return -1, stop + parsing then return immediately. + + * bgp_route.c (nlri_parse): When NLRI parse error occured, return + -1. + (nlri_process): Use pcount_v4_{unicast,multicast}. + (nlri_delete): Likewise. + +1999-11-25 Robert Olsson + + * bgp_routemap.c (route_match_nlri): `match nlri + unicast|multicast' and `set nlri unicast|multicast' command are + added. + +1999-11-22 Robert Olsson + + * bgpd.c: Add translate-update support. + + * bgpd.h (TRANSLATE_UPDATE_OFF): Add translate-update definition. + +1999-11-19 Robert.Olsson@data.slu.se + + * bgp_route.c (bgp_peer_delete): Add MBGP peer clear codes. + +1999-11-14 Kunihiro Ishiguro + + * bgp_open.c (bgp_capability_mp): Temporary comment out + SAFI_UNICAST_MULTICAST handling until we know the meanings. + +1999-11-13 Kunihiro Ishiguro + + * bgp_btoa.c: New file added. + +1999-11-12 Kunihiro Ishiguro + + * bgpd.h (struct peer): Add dont_capability flag. + (struct peer): Add override_capability flag. + + * bgpd.c (neighbor_dont_capability_negotiation): `neighbor PEER + dont-capability-negotiation' added. + +1999-11-12 Bill Sommerfeld + + * bgp_attr.c (bgp_mp_reach_parse): Ignore link-local addresses + attribute from non-shared-network peers. + +1999-11-10 Kunihiro Ishiguro + + * bgp_snmp.c: New file added. + + * BGP4-MIB.txt: Updated to the latest Internet-Draft + draft-ietf-idr-bgp4-mib-04.txt. + +1999-11-09 Kunihiro Ishiguro + + * bgp_route.c (bgp_route_init): Add `show ipv6 bgp prefix-list'. + + * bgp_attr.c (bgp_mp_unreach_parse): Enclose safi setup with + #ifdef HAVE_MBGPV4. + +1999-11-08 Kunihiro Ishiguro + + * bgp_dump.c (no_dump_bgp_all): Add [PATH] and [INTERVAL] to no + dump bgp commands. + (config_write_bgp_dump): Write interval value to the + configuration. + +1999-11-07 Kunihiro Ishiguro + + * bgp_zebra.c: Redistribute route-map support is added. + + * bgp_zebra.h: New file added. + +1999-11-04 Kunihiro Ishiguro + + * bgp_dump.c: BGP packet dump routine compatible with MRT. + * bgp_dump.h: BGP packet dump routine compatible with MRT. + + * bgp_debug.c: Renamed from bgp_dump.c + * bgp_debug.h: Renamed from bgp_dump.h + +1999-10-27 Kunihiro Ishiguro + + * BGP4-MIB.txt: New file added. Edited version of RFC1657. + +1999-10-25 Bill Sommerfeld + + * bgp_route.c (bgp_announce): If we're not on a shared network + with the peer and we don't have a link-local next hop, but the + inbound next-hop has a link-local address, don't readvertise it to + our peer. + +1999-10-25 Marc Boucher + + * bgp_zebra.c: Add redistribute kernel command. + +1999-10-25 Kunihiro Ishiguro + + * bgp_route.c (bgp_reset): New function added. + + * bgpd.conf.sample2: Add IPv6 configuration sample. + +1999-10-24 Bill Sommerfeld + + * bgp_route.c (ipv6_aggregate_address): Function added. + +1999-10-21 Kunihiro Ishiguro + + * bgp_packet.c (bgp_update): Unintern aspath, community, cluster + list after parsing BGP update packet. + + * bgp_attr.c (bgp_attr_aspath): Intern parsed aspath. + (bgp_attr_community): Intern parsed community. + (bgp_attr_cluster_list): Intern parsed cluster list. + + * bgp_routemap.c: Add `set community-additive' command. + +1999-10-21 Alexandr D. Kanevskiy + + * bgp_routemap.c (route_set_local_pref): Fix bug of setting + attribute flag. + +1999-10-21 Bill Sommerfeld + + * bgp_route.c (bgp_announce): Add check of IPv6 default route + announcement. + + * bgp_packet.c (bgp_update_send): Add BGP announcement logging. + +1999-10-15 Kunihiro Ishiguro + + * `show ip[v6] bgp PREFIX' show uptime of the route. + +1999-10-04 Kunihiro Ishiguro + + * bgpd.c (bgp_filter_set): Delete PEER_FAMILY_{IPV4,IPV6}. instead + of that use AF_INET and AF_INET6 directly. + (vty_clear_bgp): Add new function to support various clear ip bgp + method. + +1999-10-04 Lars Fenneberg + + * bgpd.c (clear_ip_bgp): Add `clear ip bgp ASN'. + +1999-10-03 Kunihiro Ishiguro + + * bgp_routemap.c: Add `match ip prefix-list' and `match ipv6 + prefix-list'. + +1999-09-28 Kunihiro Ishiguro + + * bgpd.c (bgp_collision_detect): Add BGP collision detection + function. + +1999-09-26 Blake Meike + + * bgpd.c (neighbor_port): New command `neighbor PEER port PORT' is + added. + +1999-08-24 Kunihiro Ishiguro + + * bgpd.c (no_neighbor_timers_keepalive): Change MIN to min. Add + min() macro. + +1999-08-19 Rick Payne + + * bgp_packet.c (bgp_open): BGP holdtimer bug is fixed. Make BGP + keepalive timer configurable. + +1999-08-15 Kunihiro Ishiguro + + * bgp_zebra.c (bgp_redistribute_set): Fix redistribute bug. + +1999-08-13 Kunihiro Ishiguro + + * bgpd.c (bgp_peer_display): show ip bgp neighbors PEER only list + the peer not all of them. + +1999-08-11 Rick Payne + + * bgp_route.c (bgp_announce): Remove MED if its an EBGP peer - + will get overwritten by route-maps. + +1999-08-08 Rick Payne + + * bgp_routemap.c: Multi protocol route-map modification. + +1999-08-01 Kunihiro Ishiguro + + * bgp_route.c: Set network statement route's origin attribute as + igp. + + * bgp_zebra.c: Set redistribute route's origin attribute as + incomplete. + + * bgp_route.c (bgp_info_cmp): Add attribute existance check, + origin attribute check, BGP peer type check. + +1999-07-30 Kunihiro Ishiguro + + * bgp_route.c (bgp_peer_delete): Reselect of IPv6 route. + +1999-07-29 Rick Payne + + * Changed route-maps to behave in a more cisco-like fashion + +1999-07-27 Kunihiro Ishiguro + + * bgp_fsm.c (bgp_stop): Very serious bug of bgp_stop () is fixed. + When multiple route to the same destination exist, bgpd try to + announce the information to stopped peer. Then add orphan write + thread is added. This cause many strange behavior of bgpd. + Reported by Georg Hitsch . + +1999-07-23 Kunihiro Ishiguro + + * bgpd.c: Change peer's A.B.C.D to PEER. + +1999-07-22 Kunihiro Ishiguro + + * bgp_route.c (bgp_announce): Add hack for link-local nexthop. + + * bgp_zebra.c (bgp_zebra_announce): Fill in nexthop address from + local address. + +1999-07-21 Kunihiro Ishiguro + + * bgp_packet.c (bgp_open): Holdtime fetch bug is fixed. Reported + by Yuji SEKIYA . + +1999-07-15 Kunihiro Ishiguro + + * bgp_fsm.c (fsm_holdtime): Don't close file descriptor in + fsm_holdtime (). + +1999-07-11 Kunihiro Ishiguro + + * bgp_routemap.c: Add `set atomic-aggregate' command. + +1999-07-06 Kunihiro Ishiguro + + * bgp_routemap.c (route_set_ip_nexthop_cmd): Change "ip nexthop" + to "ip next-hop". + +1999-07-02 Kunihiro Ishiguro + + * bgp_route.c (show_ipv6_bgp_regexp): `show ipv6 bgp regexp' + added. + +1999-07-01 Rick Payne + + * bgp_zebra.c (zebra_init): Install standard commands to + ZEBRA_NODE. + +1999-06-28 Rick Payne + + * bgpd.c (bgp_delete): bgp peer deletion bug is fixed. + +1999-06-25 Kunihiro Ishiguro + + * bgpd.c: Add neighbor update-source command as ALIAS to + neighbor_interface. + +1999-06-19 Kunihiro Ishiguro + + * bgp_attr.c (bgp_packet_attribute): Send community attribute when + send_community flag is set. + + * bgpd.h (struct peer): Add send_community flag. + +1999-06-12 Kunihiro Ishiguro + + * bgpd.c (router_bgp): router bgp's argument changed from AS_NO to + <1-65535>. + +1999-06-08 Kunihiro Ishiguro + + * bgp_route.h (struct bgp_info): Add subtype for BGP route type. + +1999-06-07 Kunihiro Ishiguro + + * bgp_community.c (community_merge): Function added. + +1999-06-04 Kunihiro Ishiguro + + * bgp_clist.c: New file. + * bgp_clist.h: New file. + + * bgp_community.h (COMMUNITY_LOCAL_AS): Added for Cisco + compatibility. + (COMMUNITY_NO_ADVERTISE): Fix typo. + +1999-05-30 Kunihiro Ishiguro + + * bgp_routemap.c: Add `set weight WEIGHT' command. + + * bgpd.c: Remove all_digit_check function. Instead of that use + all_digit function in lib/prefix.c. + + * bgp_routemap.c (bgp_route_map_init): Install + no_set_ipv6_nexthop_global_cmd and no_set_ipv6_nexthop_local_cmd + element to the RMAP_NODE. + +1999-05-28 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_make_str): Declare aspath_delimiter_char + inside aspath_make_str function. + (aspath_prepend): New function is added for AS path prepend. + (aspath_make_str_count): Renamed from aspath_make_str. AS path + count is set to the structure. + (aspath_merge): New function. + +1999-05-22 Kunihiro Ishiguro + + * bgp_zebra.c (redistribute_bgp): Add new DEFUN. + (no_redistribute_bgp): Likewise. + (router_zebra): Semantics changed. Now 'router zebra' is default + behavior of bgpd. + +1999-05-14 Kunihiro Ishiguro + + * bgp_routemap.c: Add some commands to bgp route-map. + match ip next-hop: New command. + match metric: New command. + set metric: Doc fix. + set local-preference: Add DEFUN. + +1999-05-14 Stephen R. van den Berg + + * bgp_main.c (signal_init): SIGTERM call sigint. + (sigint): Loggging more better message. + +1999-05-12 Kunihiro Ishiguro + + * bgp_attr.c (bgp_packet_attribute): AS path attribute extended + length bit check is added. + +1999-05-11 Kunihiro Ishiguro + + * bgp_routemap.c (bgp_route_map_init): Call route_map_install_set + function with route_set_local_pref_cmd argument. + (no_match_aspath): Function added. + (route_set_metric): Set attribute flag bit. + + * bgp_attr.c (bgp_packet_attribute): MULTI_EXIT_DISC is now in BGP + packet. + +1999-05-07 Kunihiro Ishiguro + + * bgpd.c (no_neighbor_timers_holdtime): `no neighbor PEER timers + holdtime' command is added. + + * bgpd.h (BGP_DEFAULT_HOLDTIME_BIG): Delete define. + + * bgpd.c (bgp_prefix_list_set): New function added. + (bgp_prefix_list_unset): Likewise. + (bgp_prefix_list_update): Likewise. + (show_ip_bgp_neighbors): prefix-list information display. + +1999-05-06 Kunihiro Ishiguro + + * bgpd.c (bgp_delete): Function added for `no router bgp'. + +1999-05-05 Kunihiro Ishiguro + + * bgp_dump.c (bgp_dump_attr): Add originator_id display. + + * bgpd.c (bgp_router_id): Even when address is malformed set the + value to configuration bug fixed. + (no_bgp_router_id): New function. + (no_bgp_cluster_id): New function. + +1999-05-04 Kunihiro Ishiguro + + * bgpd.h (BGP_ATTR_ORIGINATOR_ID): Changed from BGP_ATTR_ORIGINATOR. + +1999-05-02 Kunihiro Ishiguro + + * bgp_route.c (bgp_announce): Add route reflector check. + +1999-05-01 Kunihiro Ishiguro + + * bgpd.c (bgp_cluster_id): Add function for route reflector. + (neighbor_route_reflector_client): Likewise. + (no_neighbor_route_reflector_client): Likewise. + + * bgpd.h (struct bgp ): Add cluster for route reflector. + + * bgp_route.c (show_ip_bgp_prefix_list): New command is added. + +1999-04-24 Kunihiro Ishiguro + + * Makefile.am (noinst_HEADERS): Add bgp_filter.h + + * bgp_aspath.c (aspath_undup): Function deleted. aspath_free () + has same functionality. + + * bgp_filter.h: New file. + + * bgp_aspath.c (aspath_unintern): Rename aspath_free () to + aspath_unintern () + (aspath_free): New function. + +1999-04-23 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_aggregate): Function added. + + * bgp_aspath.h (aspath_aggregate): Prototype added. + + * bgp_aspath.c (aspath_empty_aspath): New argument + gated_dont_eat_flag is added. + +1999-04-18 Kunihiro Ishiguro + + * bgp_route.c: Add bgp_aggregate_ipv4 and bgp_aggregate_ipv6. + +1999-04-17 Kunihiro Ishiguro + + * bgp_route.c (aggregate_address): Function added. + + * bgp_zebra.c (zebra_read): Change log to zlog. + +1999-04-15 Kunihiro Ishiguro + + * Makefile.am (noninst_HEADERS): Added for make dist. + +1999-04-09 Kunihiro Ishiguro + + * aspath_regex.c: Removed from distribution. + +1999-04-07 Kunihiro Ishiguro + + * bgp_attr.c (bgp_packet_attribute): Old draft-00 packet treatment + bug fixed. + +1999-04-06 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_add_left): Fix empty aspath bug. Reported + by kad@gibson.skif.net. + + * bgp_regex.[ch]: New file added. + + +1999-04-05 Kunihiro Ishiguro + + * bgp_filter.c: New file added. + +1999-04-01 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_empty_aspath): Change for peering with + gated. + +1999-03-24 Kunihiro Ishiguro + + * bgp_main.c (main): Default loggin method changed from syslog to + stdout. + +1999-03-05 Kunihiro Ishiguro + + * bgp_route.c: Delete obsolete default attribute DEFUN. + +1999-03-04 Kunihiro Ishiguro + + * bgp_attr.c: Make attribute structure put into attribute hash. + +1999-03-02 Kunihiro Ishiguro + + * bgp_view.c : Delete file. + +1999-02-25 Kunihiro Ishiguro + + * bgp_routemap.c (bgp_apply_route_map): Add prefix argument. + + * bgp_route.h (struct bgp_info): Add bgp_info structre. I'll + replace bgp_route with this. + + * bgp_routemap.c (route_match_ip_address): Fix bug of passing non + prefix value to access_list_apply(). + + * bgpd.conf.sample: Add route-map sample. + Delete obsolete default-attr statements. + + * bgp_packet.c: Use stream_fifo for packet queueing. + +1999-02-24 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_add_left): add non empty aspath treatment. + + * bgp_main.c: include unistd.h for daemon(). + + * bgp_route.c (nlri_process): add IPv6 table lookup. + + * bgp_attr.c (route_parse_ipv6): call nlri_process(). + (attr_make): Obsolete function attr_make deleted. + +1999-02-22 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_add_left): change function name from + aspath_add_leftmost_as(). + +1999-02-21 Kunihiro Ishiguro + + * bgp_aspath.c: add aspath_add_leftmost_as (). + +1999-02-18 Peter Galbavy + + * syslog support added + +1999-01-26 Kunihiro Ishiguro + + * bgpd.c: DEFUN (neighbor_nexthop): deleted. + DEFUN (neighbor_distribute_list): added. + +1999-01-19 Kunihiro Ishiguro + + * bgpd.h (struct peer ): header_buf and read_buf is removed. + + * bgp_peer.[ch]: Deleted. Peer related functions are merged to + bgpd.c + + * bgp_network.c: New file. + * bgp_network.h: New file. + + * bgp_packet.h: New file. + +1999-01-11 Kunihiro Ishiguro + + * bgp_packet.c (bgp_keepalive_send): Now BGP keepalive packet is + buffered. + +1999-01-08 Kunihiro Ishiguro + + * bgp_packet.c: New file. + +1998-12-22 Kunihiro Ishiguro + + * bgp_zebra.c (zebra_client): Use zebra_connect() in lib/client.c. + + * `show ip bgp' bug fixed. + * aspath_log (): Remove argument logfp. + +1998-12-15 Kunihiro Ishiguro + + * bgp_fsm.h: New file. + +1998-12-15 Magnus Ahltorp + + * bgp_attr.c, bgp_community.h, bgp_dump.c, bgp_fsm.c, bgp_open.c + bgp_peer.c, bgp_peer.h, bgp_route.c, bgp_route.h, bgp_view.c + bgpd.c, bgpd.h, bgp_attr.c, bgp_community.h, bgp_dump.c, + bgp_fsm.c, bgp_open.c, bgp_peer.c, bgp_peer.h: Prototype fixes. + +1998-12-09 Kunihiro Ishiguro + + * bgpd.c (bgp_config_write): Delete vector v argument. + +1998-12-07 Kunihiro Ishiguro + + * bgpd.h: Delete annoying ld_[124]byte and st_[124]byte macros. + +1998-11-23 Kunihiro Ishiguro + + * bgp_radix.[ch]: removed. + +1998-09-15 HEO SeonMeyong + + * bgp_main.c: ifdef HYDRANGEA -> ifdef KAME + +1998-08-13 Kunihiro Ishiguro + + * bgp_dump.c: delete nroute(). + +1998-05-19 Yamshita TAKAO + + * bgp_aspath.c: HAVE_CONFIG_H typo :-) + * bgpd.h: Modify for compile on Solaris. + * bgp_aspath.h: likewize + * bgp_community.h: likewize + * bgp_routemap.c: likewize + +1998-05-18 Yamshita TAKAO + + * bgpd.h: Modify for compile on Solaris. + * bgp_aspath.h: likewize + +1998-05-08 Kunihiro Ishiguro + + * routemap.[ch]: move to ../lib directory. + +1998-05-07 Kunihiro Ishiguro + + * routemap.c (route_map_apply): add function. + +1998-05-06 Kunihiro Ishiguro + + * routemap.h: add file. + + * bgp_peer.h (enum ): change PEER_{IBGP,EBGP} to BGP_PEER_{IBGP,EBGP} + +1998-05-03 Kunihiro Ishiguro + + * Makefile.am: sysconfdir_DATA added. + +1998-05-02 Kunihiro Ishiguro + + * bgp_dump.c: add `debug bgp fsm' + add `no debug bgp fsm' + add `show debug bgp' + * bgp_open.c: File added. + +1998-05-01 Kunihiro Ishiguro + + * .cvsignore: File added. + +1998-04-30 Kunihiro Ishiguro + + * bgp_community.[ch]: File added. + +1998-03-04 Kunihiro Ishiguro + + * bgpd now use lib/thread.[ch]. + +1998-01-06 Kunihiro Ishiguro + + * bgpd.c (show_ip_bgp_neighbors): add 'show ip bgp neighbors' command. + + * bgpd.h (BGP_DEFAULT_START_TIMER): change from 1 to 30. + +1997-12-30 Kunihiro Ishiguro + + * bgp_vty.c: bgp_vty.c deleted. + + * bgpd.c (config_write_neighbor): add ebgp-multihop command. + +1997-12-29 Kunihiro Ishiguro + + * bgp_fsm.c: [-p bgp_port] and [-P vty_port] works + +1997-12-06 Kunihiro Ishiguro + + * bgp_vty.c: new file. + + * bgp_attr.c: add new logging system. + +1997-11-23 Kunihiro Ishiguro + + * Change all inet_addr call into inet_aton. + +1997-11-10 Kunihiro Ishiguro + + * bgp_radix.c: change radix_peer_delete + +1997-10-04 Kunihiro Ishiguro + + * bgp_aspath.c: move AS_TOKEN_??? definition from header to c source. + +1997-09-12 Kunihiro Ishiguro + + * bgp_dump.c (bgp_log_route): add dump_attr function + +1997-09-06 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_test): change AS_SET brace from '[' to '{' + * bgp_dump.c (bgp_log_route): change logfile format. + +1997-08-19 Kunihiro Ishiguro + + * bgp_open.c (bgp_open): move bgp_open function from bgpd.c + * bgp_attr.c (community_str2com): add community value generation + * bgp_attr.h: add SAFI definition for BGP-4+ + +1997-08-18 Kunihiro Ishiguro + + * bgpd.h: add BGP_OPEN_OPT_CAP for Capabilities Optional Parameter + * Makefile.in: add bgp_open.o, delete bgp_loop.o + * bgp_open.c: newfile which manages BGP Open message + * bgp_loop.c: this file is merged with bgp_fsm.c + * bgp_radix.c (radix_add): radix_add() now return route_t instead + of int + (bgp_sim): now we can read update & withdraw from file + * bgp_route.c: add route_free() call into route_parse etc. + +1997-08-17 Kunihiro Ishiguro + + * bgp_radix.c: Radix code is completely rewritten. It has better + memory treatment than old one. + +1997-08-14 Kunihiro Ishiguro + + * bgp_route.c: route_alloc for route struct allocation statistics. + * bgpd.c (bgp_make_update): now we cann announce MED attribute. + * bgp_aspath.c (aspath_print_all): change aspath_print_all output + format. + +1997-08-13 Kunihiro Ishiguro + + * bgp_term.c (term_parse): add command : show asstat, show ashash + * bgp_aspath.c: aspath_cmp bug fix + (aspath_print_all): add aspath_print_all (); + * bgp_peer.h: delete rlist element from struct peer. + +1997-08-12 Kunihiro Ishiguro + + * bgp_aspath.c: completely rewritten. + * bgp_aspath.h: completely rewritten. + add AsPath, AsSegment structure + add AS_SET treatment + change Hash codes + +1997-08-09 Kunihiro Ishiguro + + * bgp_attr.h: add Attribute flags defines + * bgp_route.c: delete rlist related functions + * bgp_aspath.c (as_origin): add as_origin function + (aspath_print): move from bgp_dump.c and add support of AS_SET + change Hash related function names. + +1997-08-08 Kunihiro Ishiguro + + * bgp_aspath.h: add next entry, delete rlist entry from struct aspath + +1997-08-04 Kunihiro Ishiguro + + * bgp_aspath.c (as_sort): add function as_sort + * bgp_aspath.h: add IBGP, EBGP + diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am new file mode 100644 index 00000000..7f739f6e --- /dev/null +++ b/bgpd/Makefile.am @@ -0,0 +1,44 @@ +## Process this file with automake to produce Makefile.in. + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 + +noinst_LIBRARIES = libbgp.a +sbin_PROGRAMS = bgpd + +libbgp_a_SOURCES = \ + bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \ + bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \ + bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \ + bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \ + bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c + +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 index 00000000..06c51892 --- /dev/null +++ b/bgpd/Makefile.in @@ -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 index 00000000..4778a977 --- /dev/null +++ b/bgpd/bgp_advertise.c @@ -0,0 +1,405 @@ +/* BGP advertisement and adjacency + Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "command.h" +#include "memory.h" +#include "prefix.h" +#include "hash.h" +#include "thread.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_advertise.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_packet.h" +#include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_mplsvpn.h" + +/* BGP advertise attribute is used for pack same attribute update into + one packet. To do that we maintain attribute hash in struct + peer. */ +static struct bgp_advertise_attr * +baa_new () +{ + return (struct bgp_advertise_attr *) + XCALLOC (MTYPE_BGP_ADVERTISE_ATTR, sizeof (struct bgp_advertise_attr)); +} + +static void +baa_free (struct bgp_advertise_attr *baa) +{ + XFREE (MTYPE_BGP_ADVERTISE_ATTR, baa); +} + +static void * +baa_hash_alloc (struct bgp_advertise_attr *ref) +{ + struct bgp_advertise_attr *baa; + + baa = baa_new (); + baa->attr = ref->attr; + return baa; +} + +static unsigned int +baa_hash_key (struct bgp_advertise_attr *baa) +{ + return attrhash_key_make (baa->attr); +} + +static int +baa_hash_cmp (struct bgp_advertise_attr *baa1, struct bgp_advertise_attr *baa2) +{ + return attrhash_cmp (baa1->attr, baa2->attr); +} + +/* BGP update and withdraw information is stored in BGP advertise + structure. This structure is referred from BGP adjacency + information. */ +static struct bgp_advertise * +bgp_advertise_new () +{ + return (struct bgp_advertise *) + XCALLOC (MTYPE_BGP_ADVERTISE, sizeof (struct bgp_advertise)); +} + +void +bgp_advertise_free (struct bgp_advertise *adv) +{ + XFREE (MTYPE_BGP_ADVERTISE, adv); +} + +void +bgp_advertise_add (struct bgp_advertise_attr *baa, + struct bgp_advertise *adv) +{ + adv->next = baa->adv; + if (baa->adv) + baa->adv->prev = adv; + baa->adv = adv; +} + +void +bgp_advertise_delete (struct bgp_advertise_attr *baa, + struct bgp_advertise *adv) +{ + if (adv->next) + adv->next->prev = adv->prev; + if (adv->prev) + adv->prev->next = adv->next; + else + baa->adv = adv->next; +} + +static struct bgp_advertise_attr * +bgp_advertise_intern (struct hash *hash, struct attr *attr) +{ + struct bgp_advertise_attr ref; + struct bgp_advertise_attr *baa; + + ref.attr = bgp_attr_intern (attr); + baa = (struct bgp_advertise_attr *) hash_get (hash, &ref, baa_hash_alloc); + baa->refcnt++; + + return baa; +} + +void +bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa) +{ + if (baa->refcnt) + baa->refcnt--; + + if (baa->refcnt && baa->attr) + bgp_attr_unintern (baa->attr); + else + { + if (baa->attr) + { + hash_release (hash, baa); + bgp_attr_unintern (baa->attr); + } + baa_free (baa); + } +} + +/* BGP adjacency keeps minimal advertisement information. */ +void +bgp_adj_out_free (struct bgp_adj_out *adj) +{ + XFREE (MTYPE_BGP_ADJ_OUT, adj); +} + +int +bgp_adj_out_lookup (struct peer *peer, struct prefix *p, + afi_t afi, safi_t safi, struct bgp_node *rn) +{ + struct bgp_adj_out *adj; + + for (adj = rn->adj_out; adj; adj = adj->next) + if (adj->peer == peer) + break; + + if (! adj) + return 0; + + return (adj->adv + ? (adj->adv->baa ? 1 : 0) + : (adj->attr ? 1 : 0)); +} + +struct bgp_advertise * +bgp_advertise_clean (struct peer *peer, struct bgp_adj_out *adj, + afi_t afi, safi_t safi) +{ + struct bgp_advertise *adv; + struct bgp_advertise_attr *baa; + struct bgp_advertise *next; + + adv = adj->adv; + baa = adv->baa; + next = NULL; + + if (baa) + { + /* Unlink myself from advertise attribute FIFO. */ + bgp_advertise_delete (baa, adv); + + /* Fetch next advertise candidate. */ + next = baa->adv; + + /* Unintern BGP advertise attribute. */ + bgp_advertise_unintern (peer->hash[afi][safi], baa); + adv->baa = NULL; + adv->rn = NULL; + } + + /* Unlink myself from advertisement FIFO. */ + FIFO_DEL (adv); + + /* Free memory. */ + bgp_advertise_free (adj->adv); + adj->adv = NULL; + + return next; +} + +void +bgp_adj_out_set (struct bgp_node *rn, struct peer *peer, struct prefix *p, + struct attr *attr, afi_t afi, safi_t safi, + struct bgp_info *binfo) +{ + struct bgp_adj_out *adj = NULL; + struct bgp_advertise *adv; + +#ifdef DISABLE_BGP_ANNOUNCE + return; +#endif /* DISABLE_BGP_ANNOUNCE */ + + /* Look for adjacency information. */ + if (rn) + { + for (adj = rn->adj_out; adj; adj = adj->next) + if (adj->peer == peer) + break; + } + + if (! adj) + { + adj = XCALLOC (MTYPE_BGP_ADJ_OUT, sizeof (struct bgp_adj_out)); + + if (rn) + { + BGP_ADJ_OUT_ADD (rn, adj); + bgp_lock_node (rn); + } + } + + if (adj->adv) + bgp_advertise_clean (peer, adj, afi, safi); + + adj->peer = peer; + adj->adv = bgp_advertise_new (); + + adv = adj->adv; + adv->rn = rn; + adv->binfo = binfo; + if (attr) + adv->baa = bgp_advertise_intern (peer->hash[afi][safi], attr); + else + adv->baa = baa_new (); + adv->adj = adj; + + /* Add new advertisement to advertisement attribute list. */ + bgp_advertise_add (adv->baa, adv); + + FIFO_ADD (&peer->sync[afi][safi]->update, &adv->fifo); +} + +void +bgp_adj_out_unset (struct bgp_node *rn, struct peer *peer, struct prefix *p, + afi_t afi, safi_t safi) +{ + struct bgp_adj_out *adj; + struct bgp_advertise *adv; + +#ifdef DISABLE_BGP_ANNOUNCE + return; +#endif /* DISABLE_BGP_ANNOUNCE */ + + /* Lookup existing adjacency, if it is not there return immediately. */ + for (adj = rn->adj_out; adj; adj = adj->next) + if (adj->peer == peer) + break; + + if (! adj) + return; + + /* Clearn up previous advertisement. */ + if (adj->adv) + bgp_advertise_clean (peer, adj, afi, safi); + + if (adj->attr) + { + /* We need advertisement structure. */ + adj->adv = bgp_advertise_new (); + adv = adj->adv; + adv->rn = rn; + adv->adj = adj; + + /* Add to synchronization entry for withdraw announcement. */ + FIFO_ADD (&peer->sync[afi][safi]->withdraw, &adv->fifo); + + /* Schedule packet write. */ + BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); + } + else + { + /* Remove myself from adjacency. */ + BGP_ADJ_OUT_DEL (rn, adj); + + /* Free allocated information. */ + bgp_adj_out_free (adj); + + bgp_unlock_node (rn); + } +} + +void +bgp_adj_out_remove (struct bgp_node *rn, struct bgp_adj_out *adj, + struct peer *peer, afi_t afi, safi_t safi) +{ + if (adj->attr) + bgp_attr_unintern (adj->attr); + + if (adj->adv) + bgp_advertise_clean (peer, adj, afi, safi); + + BGP_ADJ_OUT_DEL (rn, adj); + bgp_adj_out_free (adj); +} + +void +bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr) +{ + struct bgp_adj_in *adj; + + for (adj = rn->adj_in; adj; adj = adj->next) + { + if (adj->peer == peer) + { + if (adj->attr != attr) + { + bgp_attr_unintern (adj->attr); + adj->attr = bgp_attr_intern (attr); + } + return; + } + } + adj = XCALLOC (MTYPE_BGP_ADJ_IN, sizeof (struct bgp_adj_in)); + adj->peer = peer; + adj->attr = bgp_attr_intern (attr); + BGP_ADJ_IN_ADD (rn, adj); + bgp_lock_node (rn); +} + +void +bgp_adj_in_remove (struct bgp_node *rn, struct bgp_adj_in *bai) +{ + bgp_attr_unintern (bai->attr); + BGP_ADJ_IN_DEL (rn, bai); + XFREE (MTYPE_BGP_ADJ_IN, bai); +} + +void +bgp_adj_in_unset (struct bgp_node *rn, struct peer *peer) +{ + struct bgp_adj_in *adj; + + for (adj = rn->adj_in; adj; adj = adj->next) + if (adj->peer == peer) + break; + + if (! adj) + return; + + bgp_adj_in_remove (rn, adj); + bgp_unlock_node (rn); +} + +void +bgp_sync_init (struct peer *peer) +{ + afi_t afi; + safi_t safi; + struct bgp_synchronize *sync; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + sync = XCALLOC (MTYPE_TMP, sizeof (struct bgp_synchronize)); + FIFO_INIT (&sync->update); + FIFO_INIT (&sync->withdraw); + FIFO_INIT (&sync->withdraw_low); + peer->sync[afi][safi] = sync; + peer->hash[afi][safi] = hash_create (baa_hash_key, baa_hash_cmp); + } +} + +void +bgp_sync_delete (struct peer *peer) +{ + afi_t afi; + safi_t safi; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + if (peer->sync[afi][safi]) + XFREE (MTYPE_TMP, peer->sync[afi][safi]); + peer->sync[afi][safi] = NULL; + + hash_free (peer->hash[afi][safi]); + } +} diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h new file mode 100644 index 00000000..e2ae0104 --- /dev/null +++ b/bgpd/bgp_advertise.h @@ -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 index 00000000..fc5efb19 --- /dev/null +++ b/bgpd/bgp_aspath.c @@ -0,0 +1,1186 @@ +/* AS path management routines. + Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "hash.h" +#include "memory.h" +#include "vector.h" +#include "vty.h" +#include "str.h" +#include "log.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_aspath.h" + +/* Attr. Flags and Attr. Type Code. */ +#define AS_HEADER_SIZE 2 + +/* Two octet is used for AS value. */ +#define AS_VALUE_SIZE sizeof (as_t) + +/* AS segment octet length. */ +#define ASSEGMENT_LEN(X) ((X)->length * AS_VALUE_SIZE + AS_HEADER_SIZE) + +/* To fetch and store as segment value. */ +struct assegment +{ + u_char type; + u_char length; + as_t asval[1]; +}; + +/* Hash for aspath. This is the top level structure of AS path. */ +struct hash *ashash; + +static struct aspath * +aspath_new () +{ + struct aspath *aspath; + + aspath = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); + memset (aspath, 0, sizeof (struct aspath)); + return aspath; +} + +/* Free AS path structure. */ +void +aspath_free (struct aspath *aspath) +{ + if (!aspath) + return; + if (aspath->data) + XFREE (MTYPE_AS_SEG, aspath->data); + if (aspath->str) + XFREE (MTYPE_AS_STR, aspath->str); + XFREE (MTYPE_AS_PATH, aspath); +} + +/* Unintern aspath from AS path bucket. */ +void +aspath_unintern (struct aspath *aspath) +{ + struct aspath *ret; + + if (aspath->refcnt) + aspath->refcnt--; + + if (aspath->refcnt == 0) + { + /* This aspath must exist in aspath hash table. */ + ret = hash_release (ashash, aspath); + assert (ret != NULL); + aspath_free (aspath); + } +} + +/* Return the start or end delimiters for a particular Segment type */ +#define AS_SEG_START 0 +#define AS_SEG_END 1 +static char +aspath_delimiter_char (u_char type, u_char which) +{ + int i; + struct + { + int type; + char start; + char end; + } aspath_delim_char [] = + { + { AS_SET, '{', '}' }, + { AS_SEQUENCE, ' ', ' ' }, + { AS_CONFED_SET, '[', ']' }, + { AS_CONFED_SEQUENCE, '(', ')' }, + { 0 } + }; + + for (i = 0; aspath_delim_char[i].type != 0; i++) + { + if (aspath_delim_char[i].type == type) + { + if (which == AS_SEG_START) + return aspath_delim_char[i].start; + else if (which == AS_SEG_END) + return aspath_delim_char[i].end; + } + } + return ' '; +} + +/* Convert aspath structure to string expression. */ +char * +aspath_make_str_count (struct aspath *as) +{ + int space; + u_char type; + caddr_t pnt; + caddr_t end; + struct assegment *assegment; + int str_size = ASPATH_STR_DEFAULT_LEN; + int str_pnt; + u_char *str_buf; + int count = 0; + + /* Empty aspath. */ + if (as->length == 0) + { + str_buf = XMALLOC (MTYPE_AS_STR, 1); + str_buf[0] = '\0'; + as->count = count; + return str_buf; + } + + /* Set default value. */ + space = 0; + type = AS_SEQUENCE; + + /* Set initial pointer. */ + pnt = as->data; + end = pnt + as->length; + + str_buf = XMALLOC (MTYPE_AS_STR, str_size); + str_pnt = 0; + + assegment = (struct assegment *) pnt; + + while (pnt < end) + { + int i; + int estimate_len; + + /* For fetch value. */ + assegment = (struct assegment *) pnt; + + /* Check AS type validity. */ + if ((assegment->type != AS_SET) && + (assegment->type != AS_SEQUENCE) && + (assegment->type != AS_CONFED_SET) && + (assegment->type != AS_CONFED_SEQUENCE)) + { + XFREE (MTYPE_AS_STR, str_buf); + return NULL; + } + + /* Check AS length. */ + if ((pnt + (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE) > end) + { + XFREE (MTYPE_AS_STR, str_buf); + return NULL; + } + + /* Buffer length check. */ + estimate_len = ((assegment->length * 6) + 4); + + /* String length check. */ + while (str_pnt + estimate_len >= str_size) + { + str_size *= 2; + str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size); + } + + /* If assegment type is changed, print previous type's end + character. */ + if (type != AS_SEQUENCE) + str_buf[str_pnt++] = aspath_delimiter_char (type, AS_SEG_END); + if (space) + str_buf[str_pnt++] = ' '; + + if (assegment->type != AS_SEQUENCE) + str_buf[str_pnt++] = aspath_delimiter_char (assegment->type, AS_SEG_START); + + space = 0; + + /* Increment count - ignoring CONFED SETS/SEQUENCES */ + if (assegment->type != AS_CONFED_SEQUENCE + && assegment->type != AS_CONFED_SET) + { + if (assegment->type == AS_SEQUENCE) + count += assegment->length; + else if (assegment->type == AS_SET) + count++; + } + + for (i = 0; i < assegment->length; i++) + { + int len; + + if (space) + { + if (assegment->type == AS_SET + || assegment->type == AS_CONFED_SET) + str_buf[str_pnt++] = ','; + else + str_buf[str_pnt++] = ' '; + } + else + space = 1; + + len = sprintf (str_buf + str_pnt, "%d", ntohs (assegment->asval[i])); + str_pnt += len; + } + + type = assegment->type; + pnt += (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE; + } + + if (assegment->type != AS_SEQUENCE) + str_buf[str_pnt++] = aspath_delimiter_char (assegment->type, AS_SEG_END); + + str_buf[str_pnt] = '\0'; + + as->count = count; + + return str_buf; +} + +/* Intern allocated AS path. */ +struct aspath * +aspath_intern (struct aspath *aspath) +{ + struct aspath *find; + + /* Assert this AS path structure is not interned. */ + assert (aspath->refcnt == 0); + + /* Check AS path hash. */ + find = hash_get (ashash, aspath, hash_alloc_intern); + + if (find != aspath) + aspath_free (aspath); + + find->refcnt++; + + if (! find->str) + find->str = aspath_make_str_count (find); + + return find; +} + +/* Duplicate aspath structure. Created same aspath structure but + reference count and AS path string is cleared. */ +struct aspath * +aspath_dup (struct aspath *aspath) +{ + struct aspath *new; + + new = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); + memset (new, 0, sizeof (struct aspath)); + + new->length = aspath->length; + + if (new->length) + { + new->data = XMALLOC (MTYPE_AS_SEG, aspath->length); + memcpy (new->data, aspath->data, aspath->length); + } + else + new->data = NULL; + + /* new->str = aspath_make_str_count (aspath); */ + + return new; +} + +void * +aspath_hash_alloc (struct aspath *arg) +{ + struct aspath *aspath; + + /* New aspath strucutre is needed. */ + aspath = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); + memset ((void *) aspath, 0, sizeof (struct aspath)); + aspath->length = arg->length; + + /* In case of IBGP connection aspath's length can be zero. */ + if (arg->length) + { + aspath->data = XMALLOC (MTYPE_AS_SEG, arg->length); + memcpy (aspath->data, arg->data, arg->length); + } + else + aspath->data = NULL; + + /* Make AS path string. */ + aspath->str = aspath_make_str_count (aspath); + + /* Malformed AS path value. */ + if (! aspath->str) + { + aspath_free (aspath); + return NULL; + } + + return aspath; +} + +/* AS path parse function. pnt is a pointer to byte stream and length + is length of byte stream. If there is same AS path in the the AS + path hash then return it else make new AS path structure. */ +struct aspath * +aspath_parse (caddr_t pnt, int length) +{ + struct aspath as; + struct aspath *find; + + /* If length is odd it's malformed AS path. */ + if (length % 2) + return NULL; + + /* Looking up aspath hash entry. */ + as.data = pnt; + as.length = length; + + /* If already same aspath exist then return it. */ + find = hash_get (ashash, &as, aspath_hash_alloc); + if (! find) + return NULL; + find->refcnt++; + + return find; +} + +#define min(A,B) ((A) < (B) ? (A) : (B)) + +#define ASSEGMENT_SIZE(N) (AS_HEADER_SIZE + ((N) * AS_VALUE_SIZE)) + +struct aspath * +aspath_aggregate_segment_copy (struct aspath *aspath, struct assegment *seg, + int i) +{ + struct assegment *newseg; + + if (! aspath->data) + { + aspath->data = XMALLOC (MTYPE_AS_SEG, ASSEGMENT_SIZE (i)); + newseg = (struct assegment *) aspath->data; + aspath->length = ASSEGMENT_SIZE (i); + } + else + { + aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data, + aspath->length + ASSEGMENT_SIZE (i)); + newseg = (struct assegment *) (aspath->data + aspath->length); + aspath->length += ASSEGMENT_SIZE (i); + } + + newseg->type = seg->type; + newseg->length = i; + memcpy (newseg->asval, seg->asval, (i * AS_VALUE_SIZE)); + + return aspath; +} + +struct assegment * +aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset, + as_t as) +{ + int i; + + /* If this is first AS set member, create new as-set segment. */ + if (asset == NULL) + { + if (! aspath->data) + { + aspath->data = XMALLOC (MTYPE_AS_SEG, ASSEGMENT_SIZE (1)); + asset = (struct assegment *) aspath->data; + aspath->length = ASSEGMENT_SIZE (1); + } + else + { + aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data, + aspath->length + ASSEGMENT_SIZE (1)); + asset = (struct assegment *) (aspath->data + aspath->length); + aspath->length += ASSEGMENT_SIZE (1); + } + asset->type = AS_SET; + asset->length = 1; + asset->asval[0] = as; + } + else + { + size_t offset; + + /* Check this AS value already exists or not. */ + for (i = 0; i < asset->length; i++) + if (asset->asval[i] == as) + return asset; + + offset = (caddr_t) asset - (caddr_t) aspath->data; + aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data, + aspath->length + AS_VALUE_SIZE); + + asset = (struct assegment *) (aspath->data + offset); + aspath->length += AS_VALUE_SIZE; + asset->asval[asset->length] = as; + asset->length++; + } + + return asset; +} + +/* Modify as1 using as2 for aggregation. */ +struct aspath * +aspath_aggregate (struct aspath *as1, struct aspath *as2) +{ + int i; + int minlen; + int match; + int match1; + int match2; + caddr_t cp1; + caddr_t cp2; + caddr_t end1; + caddr_t end2; + struct assegment *seg1; + struct assegment *seg2; + struct aspath *aspath; + struct assegment *asset; + + match = 0; + minlen = 0; + aspath = NULL; + asset = NULL; + cp1 = as1->data; + end1 = as1->data + as1->length; + cp2 = as2->data; + end2 = as2->data + as2->length; + + seg1 = (struct assegment *) cp1; + seg2 = (struct assegment *) cp2; + + /* First of all check common leading sequence. */ + while ((cp1 < end1) && (cp2 < end2)) + { + /* Check segment type. */ + if (seg1->type != seg2->type) + break; + + /* Minimum segment length. */ + minlen = min (seg1->length, seg2->length); + + for (match = 0; match < minlen; match++) + if (seg1->asval[match] != seg2->asval[match]) + break; + + if (match) + { + if (! aspath) + aspath = aspath_new(); + aspath = aspath_aggregate_segment_copy (aspath, seg1, match); + } + + if (match != minlen || match != seg1->length + || seg1->length != seg2->length) + break; + + cp1 += ((seg1->length * AS_VALUE_SIZE) + AS_HEADER_SIZE); + cp2 += ((seg2->length * AS_VALUE_SIZE) + AS_HEADER_SIZE); + + seg1 = (struct assegment *) cp1; + seg2 = (struct assegment *) cp2; + } + + if (! aspath) + aspath = aspath_new(); + + /* Make as-set using rest of all information. */ + match1 = match; + while (cp1 < end1) + { + seg1 = (struct assegment *) cp1; + + for (i = match1; i < seg1->length; i++) + asset = aspath_aggregate_as_set_add (aspath, asset, seg1->asval[i]); + + match1 = 0; + cp1 += ((seg1->length * AS_VALUE_SIZE) + AS_HEADER_SIZE); + } + + match2 = match; + while (cp2 < end2) + { + seg2 = (struct assegment *) cp2; + + for (i = match2; i < seg2->length; i++) + asset = aspath_aggregate_as_set_add (aspath, asset, seg2->asval[i]); + + match2 = 0; + cp2 += ((seg2->length * AS_VALUE_SIZE) + AS_HEADER_SIZE); + } + + return aspath; +} + +/* When a BGP router receives an UPDATE with an MP_REACH_NLRI + attribute, check the leftmost AS number in the AS_PATH attribute is + or not the peer's AS number. */ +int +aspath_firstas_check (struct aspath *aspath, as_t asno) +{ + caddr_t pnt; + struct assegment *assegment; + + if (aspath == NULL) + return 0; + + pnt = aspath->data; + assegment = (struct assegment *) pnt; + + if (assegment + && assegment->type == AS_SEQUENCE + && assegment->asval[0] == htons (asno)) + return 1; + + return 0; +} + +/* AS path loop check. If aspath contains asno then return 1. */ +int +aspath_loop_check (struct aspath *aspath, as_t asno) +{ + caddr_t pnt; + caddr_t end; + struct assegment *assegment; + int count = 0; + + if (aspath == NULL) + return 0; + + pnt = aspath->data; + end = aspath->data + aspath->length; + + while (pnt < end) + { + int i; + assegment = (struct assegment *) pnt; + + for (i = 0; i < assegment->length; i++) + if (assegment->asval[i] == htons (asno)) + count++; + + pnt += (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE; + } + return count; +} + +/* When all of AS path is private AS return 1. */ +int +aspath_private_as_check (struct aspath *aspath) +{ + caddr_t pnt; + caddr_t end; + struct assegment *assegment; + + if (aspath == NULL) + return 0; + + if (aspath->length == 0) + return 0; + + pnt = aspath->data; + end = aspath->data + aspath->length; + + while (pnt < end) + { + int i; + assegment = (struct assegment *) pnt; + + for (i = 0; i < assegment->length; i++) + { + if (ntohs (assegment->asval[i]) < BGP_PRIVATE_AS_MIN + || ntohs (assegment->asval[i]) > BGP_PRIVATE_AS_MAX) + return 0; + } + pnt += (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE; + } + return 1; +} + +/* Merge as1 to as2. as2 should be uninterned aspath. */ +struct aspath * +aspath_merge (struct aspath *as1, struct aspath *as2) +{ + caddr_t data; + + if (! as1 || ! as2) + return NULL; + + data = XMALLOC (MTYPE_AS_SEG, as1->length + as2->length); + memcpy (data, as1->data, as1->length); + memcpy (data + as1->length, as2->data, as2->length); + + XFREE (MTYPE_AS_SEG, as2->data); + as2->data = data; + as2->length += as1->length; + as2->count += as1->count; + return as2; +} + +/* Prepend as1 to as2. as2 should be uninterned aspath. */ +struct aspath * +aspath_prepend (struct aspath *as1, struct aspath *as2) +{ + caddr_t pnt; + caddr_t end; + struct assegment *seg1 = NULL; + struct assegment *seg2 = NULL; + + if (! as1 || ! as2) + return NULL; + + seg2 = (struct assegment *) as2->data; + + /* In case of as2 is empty AS. */ + if (seg2 == NULL) + { + as2->length = as1->length; + as2->data = XMALLOC (MTYPE_AS_SEG, as1->length); + as2->count = as1->count; + memcpy (as2->data, as1->data, as1->length); + return as2; + } + + /* assegment points last segment of as1. */ + pnt = as1->data; + end = as1->data + as1->length; + while (pnt < end) + { + seg1 = (struct assegment *) pnt; + pnt += (seg1->length * AS_VALUE_SIZE) + AS_HEADER_SIZE; + } + + /* In case of as1 is empty AS. */ + if (seg1 == NULL) + return as2; + + /* Compare last segment type of as1 and first segment type of as2. */ + if (seg1->type != seg2->type) + return aspath_merge (as1, as2); + + if (seg1->type == AS_SEQUENCE) + { + caddr_t newdata; + struct assegment *seg = NULL; + + newdata = XMALLOC (MTYPE_AS_SEG, + as1->length + as2->length - AS_HEADER_SIZE); + memcpy (newdata, as1->data, as1->length); + seg = (struct assegment *) (newdata + ((caddr_t)seg1 - as1->data)); + seg->length += seg2->length; + memcpy (newdata + as1->length, as2->data + AS_HEADER_SIZE, + as2->length - AS_HEADER_SIZE); + + XFREE (MTYPE_AS_SEG, as2->data); + as2->data = newdata; + as2->length += (as1->length - AS_HEADER_SIZE); + as2->count += as1->count; + + return as2; + } + else + { + /* AS_SET merge code is needed at here. */ + return aspath_merge (as1, as2); + } + + /* Not reached */ +} + +/* Add specified AS to the leftmost of aspath. */ +static struct aspath * +aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type) +{ + struct assegment *assegment; + + assegment = (struct assegment *) aspath->data; + + /* In case of empty aspath. */ + if (assegment == NULL || assegment->length == 0) + { + aspath->length = AS_HEADER_SIZE + AS_VALUE_SIZE; + + if (assegment) + aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data, aspath->length); + else + aspath->data = XMALLOC (MTYPE_AS_SEG, aspath->length); + + assegment = (struct assegment *) aspath->data; + assegment->type = type; + assegment->length = 1; + assegment->asval[0] = htons (asno); + + return aspath; + } + + if (assegment->type == type) + { + caddr_t newdata; + struct assegment *newsegment; + + newdata = XMALLOC (MTYPE_AS_SEG, aspath->length + AS_VALUE_SIZE); + newsegment = (struct assegment *) newdata; + + newsegment->type = type; + newsegment->length = assegment->length + 1; + newsegment->asval[0] = htons (asno); + + memcpy (newdata + AS_HEADER_SIZE + AS_VALUE_SIZE, + aspath->data + AS_HEADER_SIZE, + aspath->length - AS_HEADER_SIZE); + + XFREE (MTYPE_AS_SEG, aspath->data); + + aspath->data = newdata; + aspath->length += AS_VALUE_SIZE; + } else { + caddr_t newdata; + struct assegment *newsegment; + + newdata = XMALLOC (MTYPE_AS_SEG, aspath->length + AS_VALUE_SIZE + AS_HEADER_SIZE); + newsegment = (struct assegment *) newdata; + + newsegment->type = type; + newsegment->length = 1; + newsegment->asval[0] = htons (asno); + + memcpy (newdata + AS_HEADER_SIZE + AS_VALUE_SIZE, + aspath->data, + aspath->length); + + XFREE (MTYPE_AS_SEG, aspath->data); + + aspath->data = newdata; + aspath->length += AS_HEADER_SIZE + AS_VALUE_SIZE; + } + + return aspath; +} + +/* Add specified AS to the leftmost of aspath. */ +struct aspath * +aspath_add_seq (struct aspath *aspath, as_t asno) +{ + return aspath_add_one_as (aspath, asno, AS_SEQUENCE); +} + +/* Compare leftmost AS value for MED check. If as1's leftmost AS and + as2's leftmost AS is same return 1. */ +int +aspath_cmp_left (struct aspath *aspath1, struct aspath *aspath2) +{ + struct assegment *seg1; + struct assegment *seg2; + as_t as1; + as_t as2; + + seg1 = (struct assegment *) aspath1->data; + seg2 = (struct assegment *) aspath2->data; + + while (seg1 && seg1->length + && (seg1->type == AS_CONFED_SEQUENCE || seg1->type == AS_CONFED_SET)) + seg1 = (struct assegment *) ((caddr_t) seg1 + ASSEGMENT_LEN (seg1)); + while (seg2 && seg2->length + && (seg2->type == AS_CONFED_SEQUENCE || seg2->type == AS_CONFED_SET)) + seg2 = (struct assegment *) ((caddr_t) seg2 + ASSEGMENT_LEN (seg2)); + + /* Check as1's */ + if (seg1 == NULL || seg1->length == 0 || seg1->type != AS_SEQUENCE) + return 0; + as1 = seg1->asval[0]; + + if (seg2 == NULL || seg2->length == 0 || seg2->type != AS_SEQUENCE) + return 0; + as2 = seg2->asval[0]; + + if (as1 == as2) + return 1; + + return 0; +} + +/* Compare leftmost AS value for MED check. If as1's leftmost AS and + as2's leftmost AS is same return 1. (confederation as-path + only). */ +int +aspath_cmp_left_confed (struct aspath *aspath1, struct aspath *aspath2) +{ + struct assegment *seg1; + struct assegment *seg2; + + as_t as1; + as_t as2; + + if (aspath1->count || aspath2->count) + return 0; + + seg1 = (struct assegment *) aspath1->data; + seg2 = (struct assegment *) aspath2->data; + + /* Check as1's */ + if (seg1 == NULL || seg1->length == 0 || seg1->type != AS_CONFED_SEQUENCE) + return 0; + as1 = seg1->asval[0]; + + /* Check as2's */ + if (seg2 == NULL || seg2->length == 0 || seg2->type != AS_CONFED_SEQUENCE) + return 0; + as2 = seg2->asval[0]; + + if (as1 == as2) + return 1; + + return 0; +} + +/* Delete first sequential AS_CONFED_SEQUENCE from aspath. */ +struct aspath * +aspath_delete_confed_seq (struct aspath *aspath) +{ + int seglen; + struct assegment *assegment; + + if (! aspath) + return aspath; + + assegment = (struct assegment *) aspath->data; + + while (assegment) + { + if (assegment->type != AS_CONFED_SEQUENCE) + return aspath; + + seglen = ASSEGMENT_LEN (assegment); + + if (seglen == aspath->length) + { + XFREE (MTYPE_AS_SEG, aspath->data); + aspath->data = NULL; + aspath->length = 0; + } + else + { + memcpy (aspath->data, aspath->data + seglen, + aspath->length - seglen); + aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data, + aspath->length - seglen); + aspath->length -= seglen; + } + + assegment = (struct assegment *) aspath->data; + } + return aspath; +} + +/* Add new AS number to the leftmost part of the aspath as + AS_CONFED_SEQUENCE. */ +struct aspath* +aspath_add_confed_seq (struct aspath *aspath, as_t asno) +{ + return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE); +} + +/* Add new as value to as path structure. */ +void +aspath_as_add (struct aspath *as, as_t asno) +{ + caddr_t pnt; + caddr_t end; + struct assegment *assegment; + + /* Increase as->data for new as value. */ + as->data = XREALLOC (MTYPE_AS_SEG, as->data, as->length + 2); + as->length += 2; + + pnt = as->data; + end = as->data + as->length; + assegment = (struct assegment *) pnt; + + /* Last segment search procedure. */ + while (pnt + 2 < end) + { + assegment = (struct assegment *) pnt; + + /* We add 2 for segment_type and segment_length and segment + value assegment->length * 2. */ + pnt += (AS_HEADER_SIZE + (assegment->length * AS_VALUE_SIZE)); + } + + assegment->asval[assegment->length] = htons (asno); + assegment->length++; +} + +/* Add new as segment to the as path. */ +void +aspath_segment_add (struct aspath *as, int type) +{ + struct assegment *assegment; + + if (as->data == NULL) + { + as->data = XMALLOC (MTYPE_AS_SEG, 2); + assegment = (struct assegment *) as->data; + as->length = 2; + } + else + { + as->data = XREALLOC (MTYPE_AS_SEG, as->data, as->length + 2); + assegment = (struct assegment *) (as->data + as->length); + as->length += 2; + } + + assegment->type = type; + assegment->length = 0; +} + +struct aspath * +aspath_empty () +{ + return aspath_parse (NULL, 0); +} + +struct aspath * +aspath_empty_get () +{ + struct aspath *aspath; + + aspath = aspath_new (); + aspath->str = aspath_make_str_count (aspath); + return aspath; +} + +unsigned long +aspath_count () +{ + return ashash->count; +} + +/* + Theoretically, one as path can have: + + One BGP packet size should be less than 4096. + One BGP attribute size should be less than 4096 - BGP header size. + One BGP aspath size should be less than 4096 - BGP header size - + BGP mandantry attribute size. +*/ + +/* AS path string lexical token enum. */ +enum as_token +{ + as_token_asval, + as_token_set_start, + as_token_set_end, + as_token_confed_start, + as_token_confed_end, + as_token_unknown +}; + +/* Return next token and point for string parse. */ +char * +aspath_gettoken (char *buf, enum as_token *token, u_short *asno) +{ + char *p = buf; + + /* Skip space. */ + while (isspace ((int) *p)) + p++; + + /* Check the end of the string and type specify characters + (e.g. {}()). */ + switch (*p) + { + case '\0': + return NULL; + break; + case '{': + *token = as_token_set_start; + p++; + return p; + break; + case '}': + *token = as_token_set_end; + p++; + return p; + break; + case '(': + *token = as_token_confed_start; + p++; + return p; + break; + case ')': + *token = as_token_confed_end; + p++; + return p; + break; + } + + /* Check actual AS value. */ + if (isdigit ((int) *p)) + { + u_short asval; + + *token = as_token_asval; + asval = (*p - '0'); + p++; + while (isdigit ((int) *p)) + { + asval *= 10; + asval += (*p - '0'); + p++; + } + *asno = asval; + return p; + } + + /* There is no match then return unknown token. */ + *token = as_token_unknown; + return p++; +} + +struct aspath * +aspath_str2aspath (char *str) +{ + enum as_token token; + u_short as_type; + u_short asno; + struct aspath *aspath; + int needtype; + + aspath = aspath_new (); + + /* We start default type as AS_SEQUENCE. */ + as_type = AS_SEQUENCE; + needtype = 1; + + while ((str = aspath_gettoken (str, &token, &asno)) != NULL) + { + switch (token) + { + case as_token_asval: + if (needtype) + { + aspath_segment_add (aspath, as_type); + needtype = 0; + } + aspath_as_add (aspath, asno); + break; + case as_token_set_start: + as_type = AS_SET; + aspath_segment_add (aspath, as_type); + needtype = 0; + break; + case as_token_set_end: + as_type = AS_SEQUENCE; + needtype = 1; + break; + case as_token_confed_start: + as_type = AS_CONFED_SEQUENCE; + aspath_segment_add (aspath, as_type); + needtype = 0; + break; + case as_token_confed_end: + as_type = AS_SEQUENCE; + needtype = 1; + break; + case as_token_unknown: + default: + return NULL; + break; + } + } + + aspath->str = aspath_make_str_count (aspath); + + return aspath; +} + +/* Make hash value by raw aspath data. */ +unsigned int +aspath_key_make (struct aspath *aspath) +{ + unsigned int key = 0; + int length; + unsigned short *pnt; + + length = aspath->length / 2; + pnt = (unsigned short *) aspath->data; + + while (length) + { + key += *pnt++; + length--; + } + + return key; +} + +/* If two aspath have same value then return 1 else return 0 */ +int +aspath_cmp (struct aspath *as1, struct aspath *as2) +{ + if (as1->length == as2->length + && !memcmp (as1->data, as2->data, as1->length)) + return 1; + else + return 0; +} + +/* AS path hash initialize. */ +void +aspath_init () +{ + ashash = hash_create_size (32767, aspath_key_make, aspath_cmp); +} + +/* return and as path value */ +const char * +aspath_print (struct aspath *as) +{ + return as->str; +} + +/* Printing functions */ +void +aspath_print_vty (struct vty *vty, struct aspath *as) +{ + vty_out (vty, "%s", as->str); +} + +void +aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty) +{ + struct aspath *as; + + as = (struct aspath *) backet->data; + + vty_out (vty, "[%p:%d] (%ld) ", backet, backet->key, as->refcnt); + vty_out (vty, "%s%s", as->str, VTY_NEWLINE); +} + +/* Print all aspath and hash information. This function is used from + `show ip bgp paths' command. */ +void +aspath_print_all_vty (struct vty *vty) +{ + hash_iterate (ashash, + (void (*) (struct hash_backet *, void *)) + aspath_show_all_iterator, + vty); +} diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h new file mode 100644 index 00000000..0295fafb --- /dev/null +++ b/bgpd/bgp_aspath.h @@ -0,0 +1,77 @@ +/* AS path related definitions. + Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* AS path segment type. */ +#define AS_SET 1 +#define AS_SEQUENCE 2 +#define AS_CONFED_SEQUENCE 3 +#define AS_CONFED_SET 4 + +/* Private AS range defined in RFC2270. */ +#define BGP_PRIVATE_AS_MIN 64512 +#define BGP_PRIVATE_AS_MAX 65535 + +/* AS path may be include some AsSegments. */ +struct aspath +{ + /* Reference count to this aspath. */ + unsigned long refcnt; + + /* Rawdata length. */ + int length; + + /* AS count. */ + int count; + + /* Rawdata. */ + caddr_t data; + + /* String expression of AS path. This string is used by vty output + and AS path regular expression match. */ + char *str; +}; + +#define ASPATH_STR_DEFAULT_LEN 32 + +/* Prototypes. */ +void aspath_init (); +struct aspath *aspath_parse (); +struct aspath *aspath_dup (struct aspath *); +struct aspath *aspath_aggregate (struct aspath *, struct aspath *); +struct aspath *aspath_prepend (struct aspath *, struct aspath *); +struct aspath *aspath_add_seq (struct aspath *, as_t); +struct aspath *aspath_add_confed_seq (struct aspath *, as_t); +int aspath_cmp_left (struct aspath *, struct aspath *); +int aspath_cmp_left_confed (struct aspath *, struct aspath *); +struct aspath *aspath_delete_confed_seq (struct aspath *); +struct aspath *aspath_empty (); +struct aspath *aspath_empty_get (); +struct aspath *aspath_str2aspath (char *); +void aspath_free (struct aspath *); +struct aspath *aspath_intern (struct aspath *); +void aspath_unintern (struct aspath *); +const char *aspath_print (struct aspath *); +void aspath_print_vty (struct vty *, struct aspath *); +void aspath_print_all_vty (struct vty *); +unsigned int aspath_key_make (struct aspath *); +int aspath_loop_check (struct aspath *, as_t); +int aspath_private_as_check (struct aspath *); +int aspath_firstas_check (struct aspath *, as_t); +unsigned long aspath_count (); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c new file mode 100644 index 00000000..480bb912 --- /dev/null +++ b/bgpd/bgp_attr.c @@ -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 + +#include "linklist.h" +#include "prefix.h" +#include "memory.h" +#include "vector.h" +#include "vty.h" +#include "stream.h" +#include "log.h" +#include "hash.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_packet.h" +#include "bgpd/bgp_ecommunity.h" + +/* Attribute strings for logging. */ +struct message attr_str [] = +{ + { BGP_ATTR_ORIGIN, "ORIGIN" }, + { BGP_ATTR_AS_PATH, "AS_PATH" }, + { BGP_ATTR_NEXT_HOP, "NEXT_HOP" }, + { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" }, + { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" }, + { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" }, + { BGP_ATTR_AGGREGATOR, "AGGREGATOR" }, + { BGP_ATTR_COMMUNITIES, "COMMUNITY" }, + { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" }, + { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" }, + { BGP_ATTR_DPA, "DPA" }, + { BGP_ATTR_ADVERTISER, "ADVERTISER"} , + { BGP_ATTR_RCID_PATH, "RCID_PATH" }, + { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" }, + { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" }, + { 0, NULL } +}; + +struct hash *cluster_hash; + +void * +cluster_hash_alloc (struct cluster_list *val) +{ + struct cluster_list *cluster; + + cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list)); + cluster->length = val->length; + + if (cluster->length) + { + cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length); + memcpy (cluster->list, val->list, val->length); + } + else + cluster->list = NULL; + + cluster->refcnt = 0; + + return cluster; +} + +/* Cluster list related functions. */ +struct cluster_list * +cluster_parse (caddr_t pnt, int length) +{ + struct cluster_list tmp; + struct cluster_list *cluster; + + tmp.length = length; + tmp.list = (struct in_addr *) pnt; + + cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc); + cluster->refcnt++; + return cluster; +} + +int +cluster_loop_check (struct cluster_list *cluster, struct in_addr originator) +{ + int i; + + for (i = 0; i < cluster->length / 4; i++) + if (cluster->list[i].s_addr == originator.s_addr) + return 1; + return 0; +} + +unsigned int +cluster_hash_key_make (struct cluster_list *cluster) +{ + unsigned int key = 0; + int length; + caddr_t pnt; + + length = cluster->length; + pnt = (caddr_t) cluster->list; + + while (length) + key += pnt[--length]; + + return key; +} + +int +cluster_hash_cmp (struct cluster_list *cluster1, struct cluster_list *cluster2) +{ + if (cluster1->length == cluster2->length && + memcmp (cluster1->list, cluster2->list, cluster1->length) == 0) + return 1; + return 0; +} + +void +cluster_free (struct cluster_list *cluster) +{ + if (cluster->list) + XFREE (MTYPE_CLUSTER_VAL, cluster->list); + XFREE (MTYPE_CLUSTER, cluster); +} + +struct cluster_list * +cluster_dup (struct cluster_list *cluster) +{ + struct cluster_list *new; + + new = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list)); + memset (new, 0, sizeof (struct cluster_list)); + new->length = cluster->length; + + if (cluster->length) + { + new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length); + memcpy (new->list, cluster->list, cluster->length); + } + else + new->list = NULL; + + return new; +} + +struct cluster_list * +cluster_intern (struct cluster_list *cluster) +{ + struct cluster_list *find; + + find = hash_get (cluster_hash, cluster, cluster_hash_alloc); + find->refcnt++; + + return find; +} + +void +cluster_unintern (struct cluster_list *cluster) +{ + struct cluster_list *ret; + + if (cluster->refcnt) + cluster->refcnt--; + + if (cluster->refcnt == 0) + { + ret = hash_release (cluster_hash, cluster); + cluster_free (cluster); + } +} + +void +cluster_init () +{ + cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp); +} + +/* Unknown transit attribute. */ +struct hash *transit_hash; + +void +transit_free (struct transit *transit) +{ + if (transit->val) + XFREE (MTYPE_TRANSIT_VAL, transit->val); + XFREE (MTYPE_TRANSIT, transit); +} + +void * +transit_hash_alloc (struct transit *transit) +{ + /* Transit structure is already allocated. */ + return transit; +} + +struct transit * +transit_intern (struct transit *transit) +{ + struct transit *find; + + find = hash_get (transit_hash, transit, transit_hash_alloc); + if (find != transit) + transit_free (transit); + find->refcnt++; + + return find; +} + +void +transit_unintern (struct transit *transit) +{ + struct transit *ret; + + if (transit->refcnt) + transit->refcnt--; + + if (transit->refcnt == 0) + { + ret = hash_release (transit_hash, transit); + transit_free (transit); + } +} + +unsigned int +transit_hash_key_make (struct transit *transit) +{ + unsigned int key = 0; + int length; + caddr_t pnt; + + length = transit->length; + pnt = (caddr_t) transit->val; + + while (length) + key += pnt[--length]; + + return key; +} + +int +transit_hash_cmp (struct transit *transit1, struct transit *transit2) +{ + if (transit1->length == transit2->length && + memcmp (transit1->val, transit2->val, transit1->length) == 0) + return 1; + return 0; +} + +void +transit_init () +{ + transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp); +} + +/* Attribute hash routines. */ + +struct hash *attrhash; + +unsigned int +attrhash_key_make (struct attr *attr) +{ + unsigned int key = 0; + + key += attr->origin; + key += attr->nexthop.s_addr; + key += attr->med; + key += attr->local_pref; + key += attr->aggregator_as; + key += attr->aggregator_addr.s_addr; + key += attr->weight; + + key += attr->mp_nexthop_global_in.s_addr; + if (attr->aspath) + key += aspath_key_make (attr->aspath); + if (attr->community) + key += community_hash_make (attr->community); + if (attr->ecommunity) + key += ecommunity_hash_make (attr->ecommunity); + if (attr->cluster) + key += cluster_hash_key_make (attr->cluster); + if (attr->transit) + key += transit_hash_key_make (attr->transit); + +#ifdef HAVE_IPV6 + { + int i; + + key += attr->mp_nexthop_len; + for (i = 0; i < 16; i++) + key += attr->mp_nexthop_global.s6_addr[i]; + for (i = 0; i < 16; i++) + key += attr->mp_nexthop_local.s6_addr[i]; + } +#endif /* HAVE_IPV6 */ + + return key; +} + +int +attrhash_cmp (struct attr *attr1, struct attr *attr2) +{ + if (attr1->flag == attr2->flag + && attr1->origin == attr2->origin + && attr1->nexthop.s_addr == attr2->nexthop.s_addr + && attr1->med == attr2->med + && attr1->local_pref == attr2->local_pref + && attr1->aggregator_as == attr2->aggregator_as + && attr1->aggregator_addr.s_addr == attr2->aggregator_addr.s_addr + && attr1->weight == attr2->weight +#ifdef HAVE_IPV6 + && attr1->mp_nexthop_len == attr2->mp_nexthop_len + && IPV6_ADDR_SAME (&attr1->mp_nexthop_global, &attr2->mp_nexthop_global) + && IPV6_ADDR_SAME (&attr1->mp_nexthop_local, &attr2->mp_nexthop_local) +#endif /* HAVE_IPV6 */ + && IPV4_ADDR_SAME (&attr1->mp_nexthop_global_in, &attr2->mp_nexthop_global_in) + && attr1->aspath == attr2->aspath + && attr1->community == attr2->community + && attr1->ecommunity == attr2->ecommunity + && attr1->cluster == attr2->cluster + && attr1->transit == attr2->transit) + return 1; + else + return 0; +} + +void +attrhash_init () +{ + attrhash = hash_create (attrhash_key_make, attrhash_cmp); +} + +void +attr_show_all_iterator (struct hash_backet *backet, struct vty *vty) +{ + struct attr *attr = backet->data; + + vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt, + inet_ntoa (attr->nexthop), VTY_NEWLINE); +} + +void +attr_show_all (struct vty *vty) +{ + hash_iterate (attrhash, + (void (*)(struct hash_backet *, void *)) + attr_show_all_iterator, + vty); +} + +void * +bgp_attr_hash_alloc (struct attr *val) +{ + struct attr *attr; + + attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr)); + *attr = *val; + attr->refcnt = 0; + return attr; +} + +/* Internet argument attribute. */ +struct attr * +bgp_attr_intern (struct attr *attr) +{ + struct attr *find; + + /* Intern referenced strucutre. */ + if (attr->aspath) + { + if (! attr->aspath->refcnt) + attr->aspath = aspath_intern (attr->aspath); + else + attr->aspath->refcnt++; + } + if (attr->community) + { + if (! attr->community->refcnt) + attr->community = community_intern (attr->community); + else + attr->community->refcnt++; + } + if (attr->ecommunity) + { + if (! attr->ecommunity->refcnt) + attr->ecommunity = ecommunity_intern (attr->ecommunity); + else + attr->ecommunity->refcnt++; + } + if (attr->cluster) + { + if (! attr->cluster->refcnt) + attr->cluster = cluster_intern (attr->cluster); + else + attr->cluster->refcnt++; + } + if (attr->transit) + { + if (! attr->transit->refcnt) + attr->transit = transit_intern (attr->transit); + else + attr->transit->refcnt++; + } + + find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc); + find->refcnt++; + + return find; +} + +/* Make network statement's attribute. */ +struct attr * +bgp_attr_default_set (struct attr *attr, u_char origin) +{ + memset (attr, 0, sizeof (struct attr)); + + attr->origin = origin; + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); + attr->aspath = aspath_empty (); + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); + attr->weight = 32768; + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); +#ifdef HAVE_IPV6 + attr->mp_nexthop_len = 16; +#endif + return attr; +} + +/* Make network statement's attribute. */ +struct attr * +bgp_attr_default_intern (u_char origin) +{ + struct attr attr; + struct attr *new; + + memset (&attr, 0, sizeof (struct attr)); + + attr.origin = origin; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); + attr.aspath = aspath_empty (); + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); + attr.weight = 32768; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); +#ifdef HAVE_IPV6 + attr.mp_nexthop_len = 16; +#endif + + new = bgp_attr_intern (&attr); + aspath_unintern (new->aspath); + return new; +} + +struct attr * +bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, + struct aspath *aspath, + struct community *community, int as_set) +{ + struct attr attr; + struct attr *new; + + memset (&attr, 0, sizeof (struct attr)); + + /* Origin attribute. */ + attr.origin = origin; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); + + /* AS path attribute. */ + if (aspath) + attr.aspath = aspath_intern (aspath); + else + attr.aspath = aspath_empty (); + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); + + /* Next hop attribute. */ + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); + + if (community) + { + attr.community = community; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); + } + + attr.weight = 32768; +#ifdef HAVE_IPV6 + attr.mp_nexthop_len = 16; +#endif + if (! as_set) + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); + if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION)) + attr.aggregator_as = bgp->confed_id; + else + attr.aggregator_as = bgp->as; + attr.aggregator_addr = bgp->router_id; + + new = bgp_attr_intern (&attr); + aspath_unintern (new->aspath); + return new; +} + +/* Free bgp attribute and aspath. */ +void +bgp_attr_unintern (struct attr *attr) +{ + struct attr *ret; + struct aspath *aspath; + struct community *community; + struct ecommunity *ecommunity; + struct cluster_list *cluster; + struct transit *transit; + + /* Decrement attribute reference. */ + attr->refcnt--; + aspath = attr->aspath; + community = attr->community; + ecommunity = attr->ecommunity; + cluster = attr->cluster; + transit = attr->transit; + + /* If reference becomes zero then free attribute object. */ + if (attr->refcnt == 0) + { + ret = hash_release (attrhash, attr); + assert (ret != NULL); + XFREE (MTYPE_ATTR, attr); + } + + /* aspath refcount shoud be decrement. */ + if (aspath) + aspath_unintern (aspath); + if (community) + community_unintern (community); + if (ecommunity) + ecommunity_unintern (ecommunity); + if (cluster) + cluster_unintern (cluster); + if (transit) + transit_unintern (transit); +} + +void +bgp_attr_flush (struct attr *attr) +{ + if (attr->aspath && ! attr->aspath->refcnt) + aspath_free (attr->aspath); + if (attr->community && ! attr->community->refcnt) + community_free (attr->community); + if (attr->ecommunity && ! attr->ecommunity->refcnt) + ecommunity_free (attr->ecommunity); + if (attr->cluster && ! attr->cluster->refcnt) + cluster_free (attr->cluster); + if (attr->transit && ! attr->transit->refcnt) + transit_free (attr->transit); +} + +/* Get origin attribute of the update message. */ +int +bgp_attr_origin (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag, u_char *startp) +{ + bgp_size_t total; + + /* total is entire attribute length include Attribute Flags (1), + Attribute Type code (1) and Attribute length (1 or 2). */ + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + + /* If any recognized attribute has Attribute Flags that conflict + with the Attribute Type Code, then the Error Subcode is set to + Attribute Flags Error. The Data field contains the erroneous + attribute (type, length and value). */ + if (flag != BGP_ATTR_FLAG_TRANS) + { + zlog (peer->log, LOG_ERR, + "Origin attribute flag isn't transitive %d", flag); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + return -1; + } + + /* If any recognized attribute has Attribute Length that conflicts + with the expected length (based on the attribute type code), then + the Error Subcode is set to Attribute Length Error. The Data + field contains the erroneous attribute (type, length and + value). */ + if (length != 1) + { + zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d", + length); + bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + startp, total); + return -1; + } + + /* Fetch origin attribute. */ + attr->origin = stream_getc (BGP_INPUT (peer)); + + /* If the ORIGIN attribute has an undefined value, then the Error + Subcode is set to Invalid Origin Attribute. The Data field + contains the unrecognized attribute (type, length and value). */ + if ((attr->origin != BGP_ORIGIN_IGP) + && (attr->origin != BGP_ORIGIN_EGP) + && (attr->origin != BGP_ORIGIN_INCOMPLETE)) + { + zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d", + attr->origin); + + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_ORIGIN, + startp, total); + return -1; + } + + /* Set oring attribute flag. */ + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); + + return 0; +} + +/* Parse AS path information. This function is wrapper of + aspath_parse. */ +int +bgp_attr_aspath (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag, u_char *startp) +{ + struct bgp *bgp; + struct aspath *aspath; + bgp_size_t total; + + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + + /* Flag check. */ + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) + || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) + { + zlog (peer->log, LOG_ERR, + "Origin attribute flag isn't transitive %d", flag); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + return -1; + } + + /* In case of IBGP, length will be zero. */ + attr->aspath = aspath_parse (stream_pnt (peer->ibuf), length); + if (! attr->aspath) + { + zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length); + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_AS_PATH); + return -1; + } + + bgp = peer->bgp; + + /* First AS check for EBGP. */ + if (bgp != 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; +} + +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 index 00000000..9c5bf879 --- /dev/null +++ b/bgpd/bgp_attr.h @@ -0,0 +1,125 @@ +/* BGP attributes. + Copyright (C) 1996, 97, 98 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* Simple bit mapping. */ +#define BITMAP_NBBY 8 + +#define SET_BITMAP(MAP, NUM) \ + SET_FLAG (MAP[(NUM) / BITMAP_NBBY], 1 << ((NUM) % BITMAP_NBBY)) + +#define CHECK_BITMAP(MAP, NUM) \ + CHECK_FLAG (MAP[(NUM) / BITMAP_NBBY], 1 << ((NUM) % BITMAP_NBBY)) + +/* BGP Attribute type range. */ +#define BGP_ATTR_TYPE_RANGE 256 +#define BGP_ATTR_BITMAP_SIZE (BGP_ATTR_TYPE_RANGE / BITMAP_NBBY) + +/* BGP Attribute flags. */ +#define BGP_ATTR_FLAG_OPTIONAL 0x80 /* Attribute is optional. */ +#define BGP_ATTR_FLAG_TRANS 0x40 /* Attribute is transitive. */ +#define BGP_ATTR_FLAG_PARTIAL 0x20 /* Attribute is partial. */ +#define BGP_ATTR_FLAG_EXTLEN 0x10 /* Extended length flag. */ + +/* BGP attribute header must bigger than 2. */ +#define BGP_ATTR_MIN_LEN 2 /* Attribute flag and type. */ + +/* BGP attribute structure. */ +struct attr +{ + /* Reference count of this attribute. */ + unsigned long refcnt; + + /* Flag of attribute is set or not. */ + u_int32_t flag; + + /* Attributes. */ + u_char origin; + struct in_addr nexthop; + u_int32_t med; + u_int32_t local_pref; + as_t aggregator_as; + struct in_addr aggregator_addr; + u_int32_t weight; + struct in_addr originator_id; + struct cluster_list *cluster; + + u_char mp_nexthop_len; +#ifdef HAVE_IPV6 + struct in6_addr mp_nexthop_global; + struct in6_addr mp_nexthop_local; +#endif /* HAVE_IPV6 */ + struct in_addr mp_nexthop_global_in; + struct in_addr mp_nexthop_local_in; + + /* AS Path structure */ + struct aspath *aspath; + + /* Community structure */ + struct community *community; + + /* Extended Communities attribute. */ + struct ecommunity *ecommunity; + + /* Unknown transitive attribute. */ + struct transit *transit; +}; + +/* Router Reflector related structure. */ +struct cluster_list +{ + unsigned long refcnt; + int length; + struct in_addr *list; +}; + +/* Unknown transit attribute. */ +struct transit +{ + unsigned long refcnt; + int length; + u_char *val; +}; + +#define ATTR_FLAG_BIT(X) (1 << ((X) - 1)) + +/* Prototypes. */ +void bgp_attr_init (); +int bgp_attr_parse (struct peer *, struct attr *, bgp_size_t, + struct bgp_nlri *, struct bgp_nlri *); +int bgp_attr_check (struct peer *, struct attr *); +struct attr *bgp_attr_intern (struct attr *attr); +void bgp_attr_unintern (struct attr *); +void bgp_attr_flush (struct attr *); +struct attr *bgp_attr_default_set (struct attr *attr, u_char); +struct attr *bgp_attr_default_intern (u_char); +struct attr *bgp_attr_aggregate_intern (struct bgp *, u_char, struct aspath *, struct community *, int as_set); +bgp_size_t bgp_packet_attribute (struct bgp *bgp, struct peer *, struct stream *, struct attr *, struct prefix *, afi_t, safi_t, struct peer *, struct prefix_rd *, u_char *); +bgp_size_t bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p, afi_t, safi_t, struct prefix_rd *, u_char *); +void bgp_dump_routes_attr (struct stream *, struct attr *); +unsigned int attrhash_key_make (struct attr *); +int attrhash_cmp (struct attr *, struct attr *); +void attr_show_all (struct vty *); + +/* Cluster list prototypes. */ +int cluster_loop_check (struct cluster_list *, struct in_addr); +void cluster_unintern (struct cluster_list *); + +/* Transit attribute prototypes. */ +void transit_unintern (struct transit *); diff --git a/bgpd/bgp_btoa.c b/bgpd/bgp_btoa.c new file mode 100644 index 00000000..7c708814 --- /dev/null +++ b/bgpd/bgp_btoa.c @@ -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 + +#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 index 00000000..0b6a2e8c --- /dev/null +++ b/bgpd/bgp_clist.c @@ -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 + +#include "command.h" +#include "prefix.h" +#include "memory.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_regex.h" +#include "bgpd/bgp_clist.h" + +/* Lookup master structure for community-list or + extcommunity-list. */ +struct community_list_master * +community_list_master_lookup (struct community_list_handler *ch, int 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; +} + +/* Add community-list entry to the list. */ +static void +community_list_entry_add (struct community_list *list, + struct community_entry *entry) +{ + entry->next = NULL; + entry->prev = list->tail; + + if (list->tail) + list->tail->next = entry; + else + list->head = entry; + list->tail = entry; +} + +/* Delete community-list entry from the list. */ +static void +community_list_entry_delete (struct community_list *list, + struct community_entry *entry, int style) +{ + if (entry->next) + entry->next->prev = entry->prev; + else + list->tail = entry->prev; + + if (entry->prev) + entry->prev->next = entry->next; + else + list->head = entry->next; + + community_entry_free (entry); + + if (community_list_empty_p (list)) + community_list_delete (list); +} + +/* Lookup community-list entry from the list. */ +static struct community_entry * +community_list_entry_lookup (struct community_list *list, void *arg, + int direct) +{ + struct community_entry *entry; + + for (entry = list->head; entry; entry = entry->next) + { + switch (entry->style) + { + case COMMUNITY_LIST_STANDARD: + if (community_cmp (entry->u.com, arg)) + return entry; + break; + case EXTCOMMUNITY_LIST_STANDARD: + if (ecommunity_cmp (entry->u.ecom, arg)) + return entry; + break; + case COMMUNITY_LIST_EXPANDED: + case EXTCOMMUNITY_LIST_EXPANDED: + if (strcmp (entry->config, arg) == 0) + return entry; + break; + default: + break; + } + } + return NULL; +} + +/* Internal function to perform regular expression match for community + attribute. */ +static int +community_regexp_match (struct community *com, regex_t *reg) +{ + char *str; + + /* When there is no communities attribute it is treated as empty + string. */ + if (com == NULL || com->size == 0) + str = ""; + else + str = community_str (com); + + /* Regular expression match. */ + if (regexec (reg, str, 0, NULL, 0) == 0) + return 1; + + /* No match. */ + return 0; +} + +/* 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; +} + +/* 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 index 00000000..ffc707c2 --- /dev/null +++ b/bgpd/bgp_clist.h @@ -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 index 00000000..83b1cc5e --- /dev/null +++ b/bgpd/bgp_community.c @@ -0,0 +1,629 @@ +/* Community attribute related functions. + Copyright (C) 1998, 2001 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "hash.h" +#include "memory.h" + +#include "bgpd/bgp_community.h" + +/* Hash of community attribute. */ +struct hash *comhash; + +/* Allocate a new communities value. */ +struct community * +community_new () +{ + return (struct community *) XCALLOC (MTYPE_COMMUNITY, + sizeof (struct community)); +} + +/* Free communities value. */ +void +community_free (struct community *com) +{ + if (com->val) + XFREE (MTYPE_COMMUNITY_VAL, com->val); + if (com->str) + XFREE (MTYPE_COMMUNITY_STR, com->str); + XFREE (MTYPE_COMMUNITY, com); +} + +/* Add one community value to the community. */ +void +community_add_val (struct community *com, u_int32_t val) +{ + com->size++; + if (com->val) + com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val, com_length (com)); + else + com->val = XMALLOC (MTYPE_COMMUNITY_VAL, com_length (com)); + + val = htonl (val); + memcpy (com_lastval (com), &val, sizeof (u_int32_t)); +} + +/* Delete one community. */ +void +community_del_val (struct community *com, u_int32_t *val) +{ + int i = 0; + int c = 0; + + if (! com->val) + return; + + while (i < com->size) + { + if (memcmp (com->val + i, val, sizeof (u_int32_t)) == 0) + { + c = com->size -i -1; + + if (c > 0) + memcpy (com->val + i, com->val + (i + 1), c * sizeof (val)); + + com->size--; + + if (com->size > 0) + com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val, + com_length (com)); + else + { + XFREE (MTYPE_COMMUNITY_VAL, com->val); + com->val = NULL; + } + return; + } + i++; + } +} + +/* Delete all communities listed in com2 from com1 */ +struct community * +community_delete (struct community *com1, struct community *com2) +{ + int i = 0; + + while(i < com2->size) + { + community_del_val (com1, com2->val + i); + i++; + } + + return com1; +} + +/* Callback function from qsort(). */ +int +community_compare (const void *a1, const void *a2) +{ + u_int32_t v1; + u_int32_t v2; + + memcpy (&v1, a1, sizeof (u_int32_t)); + memcpy (&v2, a2, sizeof (u_int32_t)); + v1 = ntohl (v1); + v2 = ntohl (v2); + + if (v1 < v2) + return -1; + if (v1 > v2) + return 1; + return 0; +} + +int +community_include (struct community *com, u_int32_t val) +{ + int i; + + val = htonl (val); + + for (i = 0; i < com->size; i++) + if (memcmp (&val, com_nthval (com, i), sizeof (u_int32_t)) == 0) + return 1; + + return 0; +} + +u_int32_t +community_val_get (struct community *com, int i) +{ + u_char *p; + u_int32_t val; + + p = (u_char *) com->val; + p += (i * 4); + + memcpy (&val, p, sizeof (u_int32_t)); + + return ntohl (val); +} + +/* Sort and uniq given community. */ +struct community * +community_uniq_sort (struct community *com) +{ + int i; + struct community *new; + u_int32_t val; + + if (! com) + return NULL; + + new = community_new ();; + + for (i = 0; i < com->size; i++) + { + val = community_val_get (com, i); + + if (! community_include (new, val)) + community_add_val (new, val); + } + + qsort (new->val, new->size, sizeof (u_int32_t), community_compare); + + return new; +} + +/* Convert communities attribute to string. + + For Well-known communities value, below keyword is used. + + 0x0 "internet" + 0xFFFFFF01 "no-export" + 0xFFFFFF02 "no-advertise" + 0xFFFFFF03 "local-AS" + + For other values, "AS:VAL" format is used. */ +static char * +community_com2str (struct community *com) +{ + int i; + char *str; + char *pnt; + int len; + int first; + u_int32_t comval; + u_int16_t as; + u_int16_t val; + + /* When communities attribute is empty. */ + if (com->size == 0) + { + str = XMALLOC (MTYPE_COMMUNITY_STR, 1); + str[0] = '\0'; + return str; + } + + /* Memory allocation is time consuming work. So we calculate + required string length first. */ + len = 0; + + for (i = 0; i < com->size; i++) + { + memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t)); + comval = ntohl (comval); + + switch (comval) + { + case COMMUNITY_INTERNET: + len += strlen (" internet"); + break; + case COMMUNITY_NO_EXPORT: + len += strlen (" no-export"); + break; + case COMMUNITY_NO_ADVERTISE: + len += strlen (" no-advertise"); + break; + case COMMUNITY_LOCAL_AS: + len += strlen (" local-AS"); + break; + default: + len += strlen (" 65536:65535"); + break; + } + } + + /* Allocate memory. */ + str = pnt = XMALLOC (MTYPE_COMMUNITY_STR, len); + first = 1; + + /* Fill in string. */ + for (i = 0; i < com->size; i++) + { + memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t)); + comval = ntohl (comval); + + if (first) + first = 0; + else + *pnt++ = ' '; + + switch (comval) + { + case COMMUNITY_INTERNET: + strcpy (pnt, "internet"); + pnt += strlen ("internet"); + break; + case COMMUNITY_NO_EXPORT: + strcpy (pnt, "no-export"); + pnt += strlen ("no-export"); + break; + case COMMUNITY_NO_ADVERTISE: + strcpy (pnt, "no-advertise"); + pnt += strlen ("no-advertise"); + break; + case COMMUNITY_LOCAL_AS: + strcpy (pnt, "local-AS"); + pnt += strlen ("local-AS"); + break; + default: + as = (comval >> 16) & 0xFFFF; + val = comval & 0xFFFF; + sprintf (pnt, "%d:%d", as, val); + pnt += strlen (pnt); + break; + } + } + *pnt = '\0'; + + return str; +} + +/* Intern communities attribute. */ +struct community * +community_intern (struct community *com) +{ + struct community *find; + + /* Assert this community structure is not interned. */ + assert (com->refcnt == 0); + + /* Lookup community hash. */ + find = (struct community *) hash_get (comhash, com, hash_alloc_intern); + + /* Arguemnt com is allocated temporary. So when it is not used in + hash, it should be freed. */ + if (find != com) + community_free (com); + + /* Increment refrence counter. */ + find->refcnt++; + + /* Make string. */ + if (! find->str) + find->str = community_com2str (find); + + return find; +} + +/* Free community attribute. */ +void +community_unintern (struct community *com) +{ + struct community *ret; + + if (com->refcnt) + com->refcnt--; + + /* Pull off from hash. */ + if (com->refcnt == 0) + { + /* Community value com must exist in hash. */ + ret = (struct community *) hash_release (comhash, com); + assert (ret != NULL); + + community_free (com); + } +} + +/* Create new community attribute. */ +struct community * +community_parse (char *pnt, u_short length) +{ + struct community tmp; + struct community *new; + + /* If length is malformed return NULL. */ + if (length % 4) + return NULL; + + /* Make temporary community for hash look up. */ + tmp.size = length / 4; + tmp.val = (u_int32_t *) pnt; + + new = community_uniq_sort (&tmp); + + return community_intern (new); +} + +struct community * +community_dup (struct community *com) +{ + struct community *new; + + new = XCALLOC (MTYPE_COMMUNITY, sizeof (struct community)); + new->size = com->size; + if (new->size) + { + new->val = XMALLOC (MTYPE_COMMUNITY_VAL, com->size * 4); + memcpy (new->val, com->val, com->size * 4); + } + else + new->val = NULL; + return new; +} + +/* Retrun string representation of communities attribute. */ +char * +community_str (struct community *com) +{ + if (! com->str) + com->str = community_com2str (com); + return com->str; +} + +/* Make hash value of community attribute. This function is used by + hash package.*/ +unsigned int +community_hash_make (struct community *com) +{ + int c; + unsigned int key; + unsigned char *pnt; + + key = 0; + pnt = (unsigned char *)com->val; + + for(c = 0; c < com->size * 4; c++) + key += pnt[c]; + + return key; +} + +int +community_match (struct community *com1, struct community *com2) +{ + int i = 0; + int j = 0; + + if (com1 == NULL && com2 == NULL) + return 1; + + if (com1 == NULL || com2 == NULL) + return 0; + + if (com1->size < com2->size) + return 0; + + /* Every community on com2 needs to be on com1 for this to match */ + while (i < com1->size && j < com2->size) + { + if (memcmp (com1->val + i, com2->val + j, sizeof (u_int32_t)) == 0) + j++; + i++; + } + + if (j == com2->size) + return 1; + else + return 0; +} + +/* If two aspath have same value then return 1 else return 0. This + function is used by hash package. */ +int +community_cmp (struct community *com1, struct community *com2) +{ + if (com1 == NULL && com2 == NULL) + return 1; + if (com1 == NULL || com2 == NULL) + return 0; + + if (com1->size == com2->size) + if (memcmp (com1->val, com2->val, com1->size * 4) == 0) + return 1; + return 0; +} + +/* Add com2 to the end of com1. */ +struct community * +community_merge (struct community *com1, struct community *com2) +{ + if (com1->val) + com1->val = XREALLOC (MTYPE_COMMUNITY_VAL, com1->val, + (com1->size + com2->size) * 4); + else + com1->val = XMALLOC (MTYPE_COMMUNITY_VAL, (com1->size + com2->size) * 4); + + memcpy (com1->val + com1->size, com2->val, com2->size * 4); + com1->size += com2->size; + + return com1; +} + +/* Community token enum. */ +enum community_token +{ + community_token_val, + community_token_no_export, + community_token_no_advertise, + community_token_local_as, + community_token_unknown +}; + +/* Get next community token from string. */ +char * +community_gettoken (char *buf, enum community_token *token, u_int32_t *val) +{ + char *p = buf; + + /* Skip white space. */ + while (isspace ((int) *p)) + p++; + + /* Check the end of the line. */ + if (*p == '\0') + return NULL; + + /* Well known community string check. */ + if (isalpha ((int) *p)) + { + if (strncmp (p, "internet", strlen ("internet")) == 0) + { + *val = COMMUNITY_INTERNET; + *token = community_token_no_export; + p += strlen ("internet"); + return p; + } + if (strncmp (p, "no-export", strlen ("no-export")) == 0) + { + *val = COMMUNITY_NO_EXPORT; + *token = community_token_no_export; + p += strlen ("no-export"); + return p; + } + if (strncmp (p, "no-advertise", strlen ("no-advertise")) == 0) + { + *val = COMMUNITY_NO_ADVERTISE; + *token = community_token_no_advertise; + p += strlen ("no-advertise"); + return p; + } + if (strncmp (p, "local-AS", strlen ("local-AS")) == 0) + { + *val = COMMUNITY_LOCAL_AS; + *token = community_token_local_as; + p += strlen ("local-AS"); + return p; + } + + /* Unknown string. */ + *token = community_token_unknown; + return p; + } + + /* Community value. */ + if (isdigit ((int) *p)) + { + int separator = 0; + int digit = 0; + u_int32_t community_low = 0; + u_int32_t community_high = 0; + + while (isdigit ((int) *p) || *p == ':') + { + if (*p == ':') + { + if (separator) + { + *token = community_token_unknown; + return p; + } + else + { + separator = 1; + digit = 0; + community_high = community_low << 16; + community_low = 0; + } + } + else + { + digit = 1; + community_low *= 10; + community_low += (*p - '0'); + } + p++; + } + if (! digit) + { + *token = community_token_unknown; + return p; + } + *val = community_high + community_low; + *token = community_token_val; + return p; + } + *token = community_token_unknown; + return p; +} + +/* convert string to community structure */ +struct community * +community_str2com (char *str) +{ + struct community *com = NULL; + struct community *com_sort = NULL; + u_int32_t val; + enum community_token token; + + while ((str = community_gettoken (str, &token, &val))) + { + switch (token) + { + case community_token_val: + case community_token_no_export: + case community_token_no_advertise: + case community_token_local_as: + if (com == NULL) + com = community_new(); + community_add_val (com, val); + break; + case community_token_unknown: + default: + if (com) + community_free (com); + return NULL; + break; + } + } + + if (! com) + return NULL; + + com_sort = community_uniq_sort (com); + community_free (com); + + return com_sort; +} + +/* Return communities hash entry count. */ +unsigned long +community_count () +{ + return comhash->count; +} + +/* Return communities hash. */ +struct hash * +community_hash () +{ + return comhash; +} + +/* Initialize comminity related hash. */ +void +community_init () +{ + comhash = hash_create (community_hash_make, community_cmp); +} diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h new file mode 100644 index 00000000..58b3f9e6 --- /dev/null +++ b/bgpd/bgp_community.h @@ -0,0 +1,68 @@ +/* Community attribute related functions. + Copyright (C) 1998 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* Communities attribute. */ +struct community +{ + /* Reference count of communities value. */ + unsigned long refcnt; + + /* Communities value size. */ + int size; + + /* Communities value. */ + u_int32_t *val; + + /* String of community attribute. This sring is used by vty output + and expanded community-list for regular expression match. */ + char *str; +}; + +/* Well-known communities value. */ +#define COMMUNITY_INTERNET 0x0 +#define COMMUNITY_NO_EXPORT 0xFFFFFF01 +#define COMMUNITY_NO_ADVERTISE 0xFFFFFF02 +#define COMMUNITY_NO_EXPORT_SUBCONFED 0xFFFFFF03 +#define COMMUNITY_LOCAL_AS 0xFFFFFF03 + +/* Macros of community attribute. */ +#define com_length(X) ((X)->size * 4) +#define com_lastval(X) ((X)->val + (X)->size - 1) +#define com_nthval(X,n) ((X)->val + (n)) + +/* Prototypes of communities attribute functions. */ +void community_init (); +void community_free (struct community *); +struct community *community_uniq_sort (struct community *); +struct community *community_parse (char *, u_short); +struct community *community_intern (struct community *); +void community_unintern (struct community *); +char *community_str (struct community *); +unsigned int community_hash_make (struct community *); +struct community *community_str2com (char *); +int community_match (struct community *, struct community *); +int community_cmp (struct community *, struct community *); +struct community *community_merge (struct community *, struct community *); +struct community *community_delete (struct community *, struct community *); +struct community *community_dup (struct community *); +int community_include (struct community *, u_int32_t); +void community_del_val (struct community *, u_int32_t *); +unsigned long community_count (); +struct hash *community_hash (); diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c new file mode 100644 index 00000000..d70105f5 --- /dev/null +++ b/bgpd/bgp_damp.c @@ -0,0 +1,648 @@ +/* BGP flap dampening + Copyright (C) 2001 IP Infusion Inc. + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include +#include + +#include "prefix.h" +#include "memory.h" +#include "command.h" +#include "log.h" +#include "thread.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_damp.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_advertise.h" + +/* Global variable to access damping configuration */ +struct bgp_damp_config bgp_damp_cfg; +struct bgp_damp_config *damp = &bgp_damp_cfg; + +/* Utility macro to add and delete BGP dampening information to no + used list. */ +#define BGP_DAMP_LIST_ADD(N,A) BGP_INFO_ADD(N,A,no_reuse_list) +#define BGP_DAMP_LIST_DEL(N,A) BGP_INFO_DEL(N,A,no_reuse_list) + +/* Calculate reuse list index by penalty value. */ +static int +bgp_reuse_index (int penalty) +{ + int i; + int index; + + i = (int)(((double) penalty / damp->reuse_limit - 1.0) * damp->scale_factor); + + if ( i >= damp->reuse_index_size ) + i = damp->reuse_index_size - 1; + + index = damp->reuse_index[i] - damp->reuse_index[0]; + + return (damp->reuse_offset + index) % damp->reuse_list_size; +} + +/* Add BGP dampening information to reuse list. */ +static void +bgp_reuse_list_add (struct bgp_damp_info *bdi) +{ + int index; + + index = bdi->index = bgp_reuse_index (bdi->penalty); + + bdi->prev = NULL; + bdi->next = damp->reuse_list[index]; + if (damp->reuse_list[index]) + damp->reuse_list[index]->prev = bdi; + damp->reuse_list[index] = bdi; +} + +/* Delete BGP dampening information from reuse list. */ +static void +bgp_reuse_list_delete (struct bgp_damp_info *bdi) +{ + if (bdi->next) + bdi->next->prev = bdi->prev; + if (bdi->prev) + bdi->prev->next = bdi->next; + else + damp->reuse_list[bdi->index] = bdi->next; +} + +/* Return decayed penalty value. */ +int +bgp_damp_decay (time_t tdiff, int penalty) +{ + int i; + + i = (int) ((double) tdiff / DELTA_T); + + if (i == 0) + return penalty; + + if (i >= damp->decay_array_size) + return 0; + + return (int) (penalty * damp->decay_array[i]); +} + +/* Handler of reuse timer event. Each route in the current reuse-list + is evaluated. RFC2439 Section 4.8.7. */ +int +bgp_reuse_timer (struct thread *t) +{ + struct bgp_damp_info *bdi; + struct bgp_damp_info *next; + time_t t_now, t_diff; + struct bgp *bgp; + int bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t); + + damp->t_reuse = NULL; + damp->t_reuse = + thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE); + + bgp = bgp_get_default (); + if (! bgp) + return 0; + + t_now = time (NULL); + + /* 1. save a pointer to the current zeroth queue head and zero the + list head entry. */ + bdi = damp->reuse_list[damp->reuse_offset]; + damp->reuse_list[damp->reuse_offset] = NULL; + + /* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby + rotating the circular queue of list-heads. */ + damp->reuse_offset = (damp->reuse_offset + 1) % damp->reuse_list_size; + + /* 3. if ( the saved list head pointer is non-empty ) */ + for (; bdi; bdi = next) + { + next = bdi->next; + + /* Set t-diff = t-now - t-updated. */ + t_diff = t_now - bdi->t_updated; + + /* Set figure-of-merit = figure-of-merit * decay-array-ok [t-diff] */ + bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty); + + /* Set t-updated = t-now. */ + bdi->t_updated = t_now; + + /* if (figure-of-merit < reuse). */ + if (bdi->penalty < damp->reuse_limit) + { + /* Reuse the route. */ + UNSET_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED); + bdi->suppress_time = 0; + + if (bdi->lastrecord == BGP_RECORD_UPDATE) + { + UNSET_FLAG (bdi->binfo->flags, BGP_INFO_HISTORY); + bgp_aggregate_increment (bgp, &bdi->rn->p, bdi->binfo, + bdi->afi, bdi->safi); + bgp_process (bgp, bdi->rn, bdi->afi, bdi->safi); + } + + if (bdi->penalty <= damp->reuse_limit / 2.0) + bgp_damp_info_free (bdi, 1); + else + BGP_DAMP_LIST_ADD (damp, bdi); + } + else + /* Re-insert into another list (See RFC2439 Section 4.8.6). */ + bgp_reuse_list_add (bdi); + } + + return 0; +} + +/* A route becomes unreachable (RFC2439 Section 4.8.2). */ +int +bgp_damp_withdraw (struct bgp_info *binfo, struct bgp_node *rn, + afi_t afi, safi_t safi, int attr_change) +{ + time_t t_now; + struct bgp_damp_info *bdi; + double last_penalty = 0; + + t_now = time (NULL); + + /* Processing Unreachable Messages. */ + bdi = binfo->damp_info; + + if (bdi == NULL) + { + /* If there is no previous stability history. */ + + /* RFC2439 said: + 1. allocate a damping structure. + 2. set figure-of-merit = 1. + 3. withdraw the route. */ + + bdi = XCALLOC (MTYPE_BGP_DAMP_INFO, sizeof (struct bgp_damp_info)); + bdi->binfo = binfo; + bdi->rn = rn; + bdi->penalty = (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY); + bdi->flap = 1; + bdi->start_time = t_now; + bdi->suppress_time = 0; + bdi->index = -1; + bdi->afi = afi; + bdi->safi = safi; + binfo->damp_info = bdi; + BGP_DAMP_LIST_ADD (damp, bdi); + } + else + { + last_penalty = bdi->penalty; + + /* 1. Set t-diff = t-now - t-updated. */ + bdi->penalty = + (bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty) + + (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY)); + + if (bdi->penalty > damp->ceiling) + bdi->penalty = damp->ceiling; + + bdi->flap++; + } + + bdi->lastrecord = BGP_RECORD_WITHDRAW; + bdi->t_updated = t_now; + + /* Make this route as historical status. */ + SET_FLAG (binfo->flags, BGP_INFO_HISTORY); + + /* Remove the route from a reuse list if it is on one. */ + if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)) + { + /* If decay rate isn't equal to 0, reinsert brn. */ + if (bdi->penalty != last_penalty) + { + bgp_reuse_list_delete (bdi); + bgp_reuse_list_add (bdi); + } + return BGP_DAMP_SUPPRESSED; + } + + /* If not suppressed before, do annonunce this withdraw and + insert into reuse_list. */ + if (bdi->penalty >= damp->suppress_value) + { + SET_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED); + bdi->suppress_time = t_now; + BGP_DAMP_LIST_DEL (damp, bdi); + bgp_reuse_list_add (bdi); + } + + return BGP_DAMP_USED; +} + +int +bgp_damp_update (struct bgp_info *binfo, struct bgp_node *rn, + afi_t afi, safi_t safi) +{ + time_t t_now; + struct bgp_damp_info *bdi; + int status; + + bdi = binfo->damp_info; + if (! bdi) + return BGP_DAMP_USED; + + t_now = time (NULL); + UNSET_FLAG (binfo->flags, BGP_INFO_HISTORY); + + bdi->lastrecord = BGP_RECORD_UPDATE; + bdi->penalty = bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty); + + if (! CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED) + && (bdi->penalty < damp->suppress_value)) + status = BGP_DAMP_USED; + else if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED) + && (bdi->penalty < damp->reuse_limit) ) + { + UNSET_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED); + bgp_reuse_list_delete (bdi); + BGP_DAMP_LIST_ADD (damp, bdi); + bdi->suppress_time = 0; + status = BGP_DAMP_USED; + } + else + status = BGP_DAMP_SUPPRESSED; + + if (bdi->penalty > damp->reuse_limit / 2.0) + bdi->t_updated = t_now; + else + bgp_damp_info_free (bdi, 0); + + return status; +} + +/* Remove dampening information and history route. */ +int +bgp_damp_scan (struct bgp_info *binfo, afi_t afi, safi_t safi) +{ + time_t t_now, t_diff; + struct bgp_damp_info *bdi; + + t_now = time (NULL); + bdi = binfo->damp_info; + + if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) + { + t_diff = t_now - bdi->suppress_time; + + if (t_diff >= damp->max_suppress_time) + { + UNSET_FLAG (binfo->flags, BGP_INFO_DAMPED); + bgp_reuse_list_delete (bdi); + BGP_DAMP_LIST_ADD (damp, bdi); + bdi->penalty = damp->reuse_limit; + bdi->suppress_time = 0; + bdi->t_updated = t_now; + + /* Need to announce UPDATE once this binfo is usable again. */ + if (bdi->lastrecord == BGP_RECORD_UPDATE) + return 1; + else + return 0; + } + } + else + { + t_diff = t_now - bdi->t_updated; + bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty); + + if (bdi->penalty <= damp->reuse_limit / 2.0) + { + /* release the bdi, bdi->binfo. */ + bgp_damp_info_free (bdi, 1); + return 0; + } + else + bdi->t_updated = t_now; + } + return 0; +} + +void +bgp_damp_info_free (struct bgp_damp_info *bdi, int withdraw) +{ + struct bgp_info *binfo; + void bgp_info_delete (struct bgp_node *, struct bgp_info *); + void bgp_info_free (struct bgp_info *); + + if (! bdi) + return; + + binfo = bdi->binfo; + binfo->damp_info = NULL; + + if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) + bgp_reuse_list_delete (bdi); + else + BGP_DAMP_LIST_DEL (damp, bdi); + + UNSET_FLAG (binfo->flags, BGP_INFO_DAMPED); + UNSET_FLAG (binfo->flags, BGP_INFO_HISTORY); + + if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw) + { + bgp_info_delete (bdi->rn, binfo); + bgp_info_free (binfo); + bgp_unlock_node (bdi->rn); + } + XFREE (MTYPE_BGP_DAMP_INFO, bdi); +} + +void +bgp_damp_parameter_set (int hlife, int reuse, int sup, int maxsup) +{ + double reuse_max_ratio; + int i; + double j; + + damp->suppress_value = sup; + damp->half_life = hlife; + damp->reuse_limit = reuse; + damp->max_suppress_time = maxsup; + + /* Initialize params per bgp_damp_config. */ + damp->reuse_index_size = REUSE_ARRAY_SIZE; + + damp->ceiling = (int)(damp->reuse_limit * (pow(2, (double)damp->max_suppress_time/damp->half_life))); + + /* Decay-array computations */ + damp->decay_array_size = ceil ((double) damp->max_suppress_time / DELTA_T); + damp->decay_array = XMALLOC (MTYPE_BGP_DAMP_ARRAY, + sizeof(double) * (damp->decay_array_size)); + damp->decay_array[0] = 1.0; + damp->decay_array[1] = exp ((1.0/((double)damp->half_life/DELTA_T)) * log(0.5)); + + /* Calculate decay values for all possible times */ + for (i = 2; i < damp->decay_array_size; i++) + damp->decay_array[i] = damp->decay_array[i-1] * damp->decay_array[1]; + + /* Reuse-list computations */ + i = ceil ((double)damp->max_suppress_time / DELTA_REUSE) + 1; + if (i > REUSE_LIST_SIZE || i == 0) + i = REUSE_LIST_SIZE; + damp->reuse_list_size = i; + + damp->reuse_list = XCALLOC (MTYPE_BGP_DAMP_ARRAY, + damp->reuse_list_size + * sizeof (struct bgp_reuse_node *)); + memset (damp->reuse_list, 0x00, + damp->reuse_list_size * sizeof (struct bgp_reuse_node *)); + + /* Reuse-array computations */ + damp->reuse_index = XMALLOC (MTYPE_BGP_DAMP_ARRAY, + sizeof(int) * damp->reuse_index_size); + memset (damp->reuse_index, 0x00, + damp->reuse_list_size * sizeof (int)); + + reuse_max_ratio = (double)damp->ceiling/damp->reuse_limit; + j = (exp((double)damp->max_suppress_time/damp->half_life) * log10(2.0)); + if ( reuse_max_ratio > j && j != 0 ) + reuse_max_ratio = j; + + damp->scale_factor = (double)damp->reuse_index_size/(reuse_max_ratio - 1); + + for (i = 0; i < damp->reuse_index_size; i++) + { + damp->reuse_index[i] = + (int)(((double)damp->half_life / DELTA_REUSE) + * log10 (1.0 / (damp->reuse_limit * ( 1.0 + ((double)i/damp->scale_factor)))) / log10(0.5)); + } +} + +int +bgp_damp_enable (struct bgp *bgp, afi_t afi, safi_t safi, int half, + int reuse, int suppress, int max) +{ + if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) + { + if (damp->half_life == half + && damp->reuse_limit == reuse + && damp->suppress_value == suppress + && damp->max_suppress_time == max) + return 0; + bgp_damp_disable (bgp, afi, safi); + } + + SET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING); + bgp_damp_parameter_set (half, reuse, suppress, max); + + /* Register reuse timer. */ + if (! damp->t_reuse) + damp->t_reuse = + thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE); + + return 0; +} + +void +bgp_damp_config_clean (struct bgp_damp_config *damp) +{ + /* Free decay array */ + XFREE (MTYPE_BGP_DAMP_ARRAY, damp->decay_array); + + /* Free reuse index array */ + XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_index); + + /* Free reuse list array. */ + XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_list); +} + +/* Clean all the bgp_damp_info stored in reuse_list. */ +void +bgp_damp_info_clean () +{ + int i; + struct bgp_damp_info *bdi, *next; + + damp->reuse_offset = 0; + + for (i = 0; i < damp->reuse_list_size; i++) + { + if (! damp->reuse_list[i]) + continue; + + for (bdi = damp->reuse_list[i]; bdi; bdi = next) + { + next = bdi->next; + bgp_damp_info_free (bdi, 1); + } + damp->reuse_list[i] = NULL; + } + + for (bdi = damp->no_reuse_list; bdi; bdi = next) + { + next = bdi->next; + bgp_damp_info_free (bdi, 1); + } + damp->no_reuse_list = NULL; +} + +int +bgp_damp_disable (struct bgp *bgp, afi_t afi, safi_t safi) +{ + /* Cancel reuse thread. */ + if (damp->t_reuse ) + thread_cancel (damp->t_reuse); + damp->t_reuse = NULL; + + /* Clean BGP dampening information. */ + bgp_damp_info_clean (); + + /* Clear configuration */ + bgp_damp_config_clean (&bgp_damp_cfg); + + UNSET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING); + return 0; +} + +int +bgp_config_write_damp (struct vty *vty) +{ + if (&bgp_damp_cfg) + { + if (bgp_damp_cfg.half_life == DEFAULT_HALF_LIFE*60 + && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE + && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS + && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4) + vty_out (vty, " bgp dampening%s", VTY_NEWLINE); + else if (bgp_damp_cfg.half_life != DEFAULT_HALF_LIFE*60 + && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE + && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS + && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4) + vty_out (vty, " bgp dampening %d%s", + bgp_damp_cfg.half_life/60, + VTY_NEWLINE); + else + vty_out (vty, " bgp dampening %d %d %d %d%s", + bgp_damp_cfg.half_life/60, + bgp_damp_cfg.reuse_limit, + bgp_damp_cfg.suppress_value, + bgp_damp_cfg.max_suppress_time/60, + VTY_NEWLINE); + return 1; + } + return 0; +} + +#define BGP_UPTIME_LEN 25 + +char * +bgp_get_reuse_time (int penalty, char *buf, size_t len) +{ + time_t reuse_time = 0; + struct tm *tm = NULL; + + if (penalty > damp->reuse_limit) + { + reuse_time = (int) (DELTA_T * ((log((double)damp->reuse_limit/penalty))/(log(damp->decay_array[1])))); + + if (reuse_time > damp->max_suppress_time) + reuse_time = damp->max_suppress_time; + + tm = gmtime (&reuse_time); + } + else + reuse_time = 0; + + /* Making formatted timer strings. */ +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + if (reuse_time == 0) + snprintf (buf, len, "00:00:00"); + else if (reuse_time < ONE_DAY_SECOND) + snprintf (buf, len, "%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (reuse_time < ONE_WEEK_SECOND) + snprintf (buf, len, "%dd%02dh%02dm", + tm->tm_yday, tm->tm_hour, tm->tm_min); + else + snprintf (buf, len, "%02dw%dd%02dh", + tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + + return buf; +} + +void +bgp_damp_info_vty (struct vty *vty, struct bgp_info *binfo) +{ + struct bgp_damp_info *bdi; + time_t t_now, t_diff; + char timebuf[BGP_UPTIME_LEN]; + int penalty; + + /* BGP dampening information. */ + bdi = binfo->damp_info; + + /* If dampening is not enabled or there is no dampening information, + return immediately. */ + if (! damp || ! bdi) + return; + + /* Calculate new penalty. */ + t_now = time (NULL); + t_diff = t_now - bdi->t_updated; + penalty = bgp_damp_decay (t_diff, bdi->penalty); + + vty_out (vty, " Dampinfo: penalty %d, flapped %d times in %s", + penalty, bdi->flap, + peer_uptime (bdi->start_time, timebuf, BGP_UPTIME_LEN)); + + if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED) + && ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) + vty_out (vty, ", reuse in %s", + bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN)); + + vty_out (vty, "%s", VTY_NEWLINE); +} + +char * +bgp_damp_reuse_time_vty (struct vty *vty, struct bgp_info *binfo) +{ + struct bgp_damp_info *bdi; + time_t t_now, t_diff; + char timebuf[BGP_UPTIME_LEN]; + int penalty; + + /* BGP dampening information. */ + bdi = binfo->damp_info; + + /* If dampening is not enabled or there is no dampening information, + return immediately. */ + if (! damp || ! bdi) + return NULL; + + /* Calculate new penalty. */ + t_now = time (NULL); + t_diff = t_now - bdi->t_updated; + penalty = bgp_damp_decay (t_diff, bdi->penalty); + + return bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN); +} diff --git a/bgpd/bgp_damp.h b/bgpd/bgp_damp.h new file mode 100644 index 00000000..f3b9bd6d --- /dev/null +++ b/bgpd/bgp_damp.h @@ -0,0 +1,141 @@ +/* BGP flap dampening + Copyright (C) 2001 IP Infusion Inc. + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* Structure maintained on a per-route basis. */ +struct bgp_damp_info +{ + /* Doubly linked list. This information must be linked to + reuse_list or no_reuse_list. */ + struct bgp_damp_info *next; + struct bgp_damp_info *prev; + + /* Figure-of-merit. */ + int penalty; + + /* Number of flapping. */ + int flap; + + /* First flap time */ + time_t start_time; + + /* Last time penalty was updated. */ + time_t t_updated; + + /* Time of route start to be suppressed. */ + time_t suppress_time; + + /* Back reference to bgp_info. */ + struct bgp_info *binfo; + + /* Back reference to bgp_node. */ + struct bgp_node *rn; + + /* Current index in the reuse_list. */ + int index; + + /* Last time message type. */ + u_char lastrecord; +#define BGP_RECORD_UPDATE 1 +#define BGP_RECORD_WITHDRAW 2 + + afi_t afi; + safi_t safi; +}; + +/* Specified parameter set configuration. */ +struct bgp_damp_config +{ + /* Value over which routes suppressed. */ + int suppress_value; + + /* Value below which suppressed routes reused. */ + int reuse_limit; + + /* Max time a route can be suppressed. */ + int max_suppress_time; + + /* Time during which accumulated penalty reduces by half. */ + int half_life; + + /* Non-configurable parameters but fixed at implementation time. + * To change this values, init_bgp_damp() should be modified. + */ + int tmax; /* Max time previous instability retained */ + int reuse_list_size; /* Number of reuse lists */ + int reuse_index_size; /* Size of reuse index array */ + + /* Non-configurable parameters. Most of these are calculated from + * the configurable parameters above. + */ + unsigned int ceiling; /* Max value a penalty can attain */ + int decay_rate_per_tick; /* Calculated from half-life */ + int decay_array_size; /* Calculated using config parameters */ + double scale_factor; + int reuse_scale_factor; + + /* Decay array per-set based. */ + double *decay_array; + + /* Reuse index array per-set based. */ + int *reuse_index; + + /* Reuse list array per-set based. */ + struct bgp_damp_info **reuse_list; + int reuse_offset; + + /* All dampening information which is not on reuse list. */ + struct bgp_damp_info *no_reuse_list; + + /* Reuse timer thread per-set base. */ + struct thread* t_reuse; +}; + +#define BGP_DAMP_NONE 0 +#define BGP_DAMP_USED 1 +#define BGP_DAMP_SUPPRESSED 2 + +/* Time granularity for reuse lists */ +#define DELTA_REUSE 10 + +/* Time granularity for decay arrays */ +#define DELTA_T 5 + +#define DEFAULT_PENALTY 1000 + +#define DEFAULT_HALF_LIFE 15 +#define DEFAULT_REUSE 750 +#define DEFAULT_SUPPRESS 2000 + +#define REUSE_LIST_SIZE 256 +#define REUSE_ARRAY_SIZE 1024 + +int bgp_damp_enable (struct bgp *, afi_t, safi_t, int, int, int, int); +int bgp_damp_disable (struct bgp *, afi_t, safi_t); +int bgp_damp_withdraw (struct bgp_info *, struct bgp_node *, + afi_t, safi_t, int); +int bgp_damp_update (struct bgp_info *, struct bgp_node *, afi_t, safi_t); +int bgp_damp_scan (struct bgp_info *, afi_t, safi_t); +void bgp_damp_info_free (struct bgp_damp_info *, int); +void bgp_damp_info_clean (); +char * bgp_get_reuse_time (int, char*, size_t); +int bgp_damp_decay (time_t, int); +int bgp_config_write_damp (struct vty *); +void bgp_damp_info_vty (struct vty *, struct bgp_info *); +char * bgp_damp_reuse_time_vty (struct vty *, struct bgp_info *); diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c new file mode 100644 index 00000000..bb1a6107 --- /dev/null +++ b/bgpd/bgp_debug.c @@ -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 + +#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 : ""); +} + +/* Debug option setting interface. */ +unsigned long bgp_debug_option = 0; + +int +debug (unsigned int option) +{ + return bgp_debug_option & option; +} + +DEFUN (debug_bgp_fsm, + debug_bgp_fsm_cmd, + "debug bgp fsm", + DEBUG_STR + BGP_STR + "BGP Finite State Machine\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON (fsm, FSM); + else + { + TERM_DEBUG_ON (fsm, FSM); + vty_out (vty, "BGP fsm debugging is on%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_fsm, + no_debug_bgp_fsm_cmd, + "no debug bgp fsm", + NO_STR + DEBUG_STR + BGP_STR + "Finite State Machine\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF (fsm, FSM); + else + { + TERM_DEBUG_OFF (fsm, FSM); + vty_out (vty, "BGP fsm debugging is off%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_fsm, + undebug_bgp_fsm_cmd, + "undebug bgp fsm", + UNDEBUG_STR + DEBUG_STR + BGP_STR + "Finite State Machine\n") + +DEFUN (debug_bgp_events, + debug_bgp_events_cmd, + "debug bgp events", + DEBUG_STR + BGP_STR + "BGP events\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON (events, EVENTS); + else + { + TERM_DEBUG_ON (events, EVENTS); + vty_out (vty, "BGP events debugging is on%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_events, + no_debug_bgp_events_cmd, + "no debug bgp events", + NO_STR + DEBUG_STR + BGP_STR + "BGP events\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF (events, EVENTS); + else + { + TERM_DEBUG_OFF (events, EVENTS); + vty_out (vty, "BGP events debugging is off%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_events, + undebug_bgp_events_cmd, + "undebug bgp events", + UNDEBUG_STR + BGP_STR + "BGP events\n") + +DEFUN (debug_bgp_filter, + debug_bgp_filter_cmd, + "debug bgp filters", + DEBUG_STR + BGP_STR + "BGP filters\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON (filter, FILTER); + else + { + TERM_DEBUG_ON (filter, FILTER); + vty_out (vty, "BGP filters debugging is on%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_filter, + no_debug_bgp_filter_cmd, + "no debug bgp filters", + NO_STR + DEBUG_STR + BGP_STR + "BGP filters\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF (filter, FILTER); + else + { + TERM_DEBUG_OFF (filter, FILTER); + vty_out (vty, "BGP filters debugging is off%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_filter, + undebug_bgp_filter_cmd, + "undebug bgp filters", + UNDEBUG_STR + BGP_STR + "BGP filters\n") + +DEFUN (debug_bgp_keepalive, + debug_bgp_keepalive_cmd, + "debug bgp keepalives", + DEBUG_STR + BGP_STR + "BGP keepalives\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON (keepalive, KEEPALIVE); + else + { + TERM_DEBUG_ON (keepalive, KEEPALIVE); + vty_out (vty, "BGP keepalives debugging is on%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_keepalive, + no_debug_bgp_keepalive_cmd, + "no debug bgp keepalives", + NO_STR + DEBUG_STR + BGP_STR + "BGP keepalives\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF (keepalive, KEEPALIVE); + else + { + TERM_DEBUG_OFF (keepalive, KEEPALIVE); + vty_out (vty, "BGP keepalives debugging is off%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_keepalive, + undebug_bgp_keepalive_cmd, + "undebug bgp keepalives", + UNDEBUG_STR + BGP_STR + "BGP keepalives\n") + +DEFUN (debug_bgp_update, + debug_bgp_update_cmd, + "debug bgp updates", + DEBUG_STR + BGP_STR + "BGP updates\n") +{ + if (vty->node == CONFIG_NODE) + { + DEBUG_ON (update, UPDATE_IN); + DEBUG_ON (update, UPDATE_OUT); + } + else + { + TERM_DEBUG_ON (update, UPDATE_IN); + TERM_DEBUG_ON (update, UPDATE_OUT); + vty_out (vty, "BGP updates debugging is on%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (debug_bgp_update_direct, + debug_bgp_update_direct_cmd, + "debug bgp updates (in|out)", + DEBUG_STR + BGP_STR + "BGP updates\n" + "Inbound updates\n" + "Outbound updates\n") +{ + if (vty->node == CONFIG_NODE) + { + if (strncmp ("i", argv[0], 1) == 0) + { + DEBUG_OFF (update, UPDATE_OUT); + DEBUG_ON (update, UPDATE_IN); + } + else + { + DEBUG_OFF (update, UPDATE_IN); + DEBUG_ON (update, UPDATE_OUT); + } + } + else + { + if (strncmp ("i", argv[0], 1) == 0) + { + TERM_DEBUG_OFF (update, UPDATE_OUT); + TERM_DEBUG_ON (update, UPDATE_IN); + vty_out (vty, "BGP updates debugging is on (inbound)%s", VTY_NEWLINE); + } + else + { + TERM_DEBUG_OFF (update, UPDATE_IN); + TERM_DEBUG_ON (update, UPDATE_OUT); + vty_out (vty, "BGP updates debugging is on (outbound)%s", VTY_NEWLINE); + } + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_update, + no_debug_bgp_update_cmd, + "no debug bgp updates", + NO_STR + DEBUG_STR + BGP_STR + "BGP updates\n") +{ + if (vty->node == CONFIG_NODE) + { + DEBUG_OFF (update, UPDATE_IN); + DEBUG_OFF (update, UPDATE_OUT); + } + else + { + TERM_DEBUG_OFF (update, UPDATE_IN); + TERM_DEBUG_OFF (update, UPDATE_OUT); + vty_out (vty, "BGP updates debugging is off%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_update, + undebug_bgp_update_cmd, + "undebug bgp updates", + UNDEBUG_STR + BGP_STR + "BGP updates\n") + +DEFUN (debug_bgp_normal, + debug_bgp_normal_cmd, + "debug bgp", + DEBUG_STR + BGP_STR) +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON (normal, NORMAL); + else + { + TERM_DEBUG_ON (normal, NORMAL); + vty_out (vty, "BGP debugging is on%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_normal, + no_debug_bgp_normal_cmd, + "no debug bgp", + NO_STR + DEBUG_STR + BGP_STR) +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF (normal, NORMAL); + else + { + TERM_DEBUG_OFF (normal, NORMAL); + vty_out (vty, "BGP debugging is off%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_normal, + undebug_bgp_normal_cmd, + "undebug bgp", + UNDEBUG_STR + BGP_STR) + +DEFUN (no_debug_bgp_all, + no_debug_bgp_all_cmd, + "no debug all bgp", + NO_STR + DEBUG_STR + "Enable all debugging\n" + BGP_STR) +{ + TERM_DEBUG_OFF (normal, NORMAL); + TERM_DEBUG_OFF (events, EVENTS); + TERM_DEBUG_OFF (keepalive, KEEPALIVE); + TERM_DEBUG_OFF (update, UPDATE_IN); + TERM_DEBUG_OFF (update, UPDATE_OUT); + TERM_DEBUG_OFF (fsm, FSM); + TERM_DEBUG_OFF (filter, FILTER); + vty_out (vty, "All possible debugging has been turned off%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_all, + undebug_bgp_all_cmd, + "undebug all bgp", + UNDEBUG_STR + "Enable all debugging\n" + BGP_STR) + +DEFUN (show_debugging_bgp, + show_debugging_bgp_cmd, + "show debugging bgp", + SHOW_STR + DEBUG_STR + BGP_STR) +{ + vty_out (vty, "BGP debugging status:%s", VTY_NEWLINE); + + if (BGP_DEBUG (normal, NORMAL)) + vty_out (vty, " BGP debugging is on%s", VTY_NEWLINE); + if (BGP_DEBUG (events, EVENTS)) + vty_out (vty, " BGP events debugging is on%s", VTY_NEWLINE); + if (BGP_DEBUG (keepalive, KEEPALIVE)) + vty_out (vty, " BGP keepalives debugging is on%s", VTY_NEWLINE); + if (BGP_DEBUG (update, UPDATE_IN) && BGP_DEBUG (update, UPDATE_OUT)) + vty_out (vty, " BGP updates debugging is on%s", VTY_NEWLINE); + else if (BGP_DEBUG (update, UPDATE_IN)) + vty_out (vty, " BGP updates debugging is on (inbound)%s", VTY_NEWLINE); + else if (BGP_DEBUG (update, UPDATE_OUT)) + vty_out (vty, " BGP updates debugging is on (outbound)%s", VTY_NEWLINE); + if (BGP_DEBUG (fsm, FSM)) + vty_out (vty, " BGP fsm debugging is on%s", VTY_NEWLINE); + if (BGP_DEBUG (filter, FILTER)) + vty_out (vty, " BGP filter debugging is on%s", VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + return CMD_SUCCESS; +} + +int +bgp_config_write_debug (struct vty *vty) +{ + int write = 0; + + if (CONF_BGP_DEBUG (normal, NORMAL)) + { + vty_out (vty, "debug bgp%s", VTY_NEWLINE); + write++; + } + + if (CONF_BGP_DEBUG (events, EVENTS)) + { + vty_out (vty, "debug bgp events%s", VTY_NEWLINE); + write++; + } + + if (CONF_BGP_DEBUG (keepalive, KEEPALIVE)) + { + vty_out (vty, "debug bgp keepalives%s", VTY_NEWLINE); + write++; + } + + if (CONF_BGP_DEBUG (update, UPDATE_IN) && CONF_BGP_DEBUG (update, UPDATE_OUT)) + { + vty_out (vty, "debug bgp updates%s", VTY_NEWLINE); + write++; + } + else if (CONF_BGP_DEBUG (update, UPDATE_IN)) + { + vty_out (vty, "debug bgp updates in%s", VTY_NEWLINE); + write++; + } + else if (CONF_BGP_DEBUG (update, UPDATE_OUT)) + { + vty_out (vty, "debug bgp updates out%s", VTY_NEWLINE); + write++; + } + + if (CONF_BGP_DEBUG (fsm, FSM)) + { + vty_out (vty, "debug bgp fsm%s", VTY_NEWLINE); + write++; + } + + if (CONF_BGP_DEBUG (filter, FILTER)) + { + vty_out (vty, "debug bgp filters%s", VTY_NEWLINE); + write++; + } + + return write; +} + +struct cmd_node debug_node = +{ + DEBUG_NODE, + "", + 1 +}; + +void +bgp_debug_init () +{ + install_node (&debug_node, bgp_config_write_debug); + + install_element (ENABLE_NODE, &show_debugging_bgp_cmd); + + install_element (ENABLE_NODE, &debug_bgp_fsm_cmd); + install_element (CONFIG_NODE, &debug_bgp_fsm_cmd); + install_element (ENABLE_NODE, &debug_bgp_events_cmd); + install_element (CONFIG_NODE, &debug_bgp_events_cmd); + install_element (ENABLE_NODE, &debug_bgp_filter_cmd); + install_element (CONFIG_NODE, &debug_bgp_filter_cmd); + install_element (ENABLE_NODE, &debug_bgp_keepalive_cmd); + install_element (CONFIG_NODE, &debug_bgp_keepalive_cmd); + install_element (ENABLE_NODE, &debug_bgp_update_cmd); + install_element (CONFIG_NODE, &debug_bgp_update_cmd); + install_element (ENABLE_NODE, &debug_bgp_update_direct_cmd); + install_element (CONFIG_NODE, &debug_bgp_update_direct_cmd); + install_element (ENABLE_NODE, &debug_bgp_normal_cmd); + install_element (CONFIG_NODE, &debug_bgp_normal_cmd); + + install_element (ENABLE_NODE, &no_debug_bgp_fsm_cmd); + install_element (ENABLE_NODE, &undebug_bgp_fsm_cmd); + install_element (CONFIG_NODE, &no_debug_bgp_fsm_cmd); + install_element (ENABLE_NODE, &no_debug_bgp_events_cmd); + install_element (ENABLE_NODE, &undebug_bgp_events_cmd); + install_element (CONFIG_NODE, &no_debug_bgp_events_cmd); + install_element (ENABLE_NODE, &no_debug_bgp_filter_cmd); + install_element (ENABLE_NODE, &undebug_bgp_filter_cmd); + install_element (CONFIG_NODE, &no_debug_bgp_filter_cmd); + install_element (ENABLE_NODE, &no_debug_bgp_keepalive_cmd); + install_element (ENABLE_NODE, &undebug_bgp_keepalive_cmd); + install_element (CONFIG_NODE, &no_debug_bgp_keepalive_cmd); + install_element (ENABLE_NODE, &no_debug_bgp_update_cmd); + install_element (ENABLE_NODE, &undebug_bgp_update_cmd); + install_element (CONFIG_NODE, &no_debug_bgp_update_cmd); + install_element (ENABLE_NODE, &no_debug_bgp_normal_cmd); + install_element (ENABLE_NODE, &undebug_bgp_normal_cmd); + install_element (CONFIG_NODE, &no_debug_bgp_normal_cmd); + install_element (ENABLE_NODE, &no_debug_bgp_all_cmd); + install_element (ENABLE_NODE, &undebug_bgp_all_cmd); +} diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h new file mode 100644 index 00000000..06ba0757 --- /dev/null +++ b/bgpd/bgp_debug.h @@ -0,0 +1,113 @@ +/* BGP message debug header. + Copyright (C) 1996, 97, 98 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* sort of packet direction */ +#define DUMP_ON 1 +#define DUMP_SEND 2 +#define DUMP_RECV 4 + +/* for dump_update */ +#define DUMP_WITHDRAW 8 +#define DUMP_NLRI 16 + +/* dump detail */ +#define DUMP_DETAIL 32 + +extern int dump_open; +extern int dump_update; +extern int dump_keepalive; +extern int dump_notify; + +extern int Debug_Event; +extern int Debug_Keepalive; +extern int Debug_Update; +extern int Debug_Radix; + +#define NLRI 1 +#define WITHDRAW 2 +#define NO_OPT 3 +#define SEND 4 +#define RECV 5 +#define DETAIL 6 + +/* Prototypes. */ +void bgp_debug_init (); +void bgp_packet_dump (struct stream *); + +int debug (unsigned int option); + +extern unsigned long conf_bgp_debug_fsm; +extern unsigned long conf_bgp_debug_events; +extern unsigned long conf_bgp_debug_packet; +extern unsigned long conf_bgp_debug_filter; +extern unsigned long conf_bgp_debug_keepalive; +extern unsigned long conf_bgp_debug_update; +extern unsigned long conf_bgp_debug_normal; + +extern unsigned long term_bgp_debug_fsm; +extern unsigned long term_bgp_debug_events; +extern unsigned long term_bgp_debug_packet; +extern unsigned long term_bgp_debug_filter; +extern unsigned long term_bgp_debug_keepalive; +extern unsigned long term_bgp_debug_update; +extern unsigned long term_bgp_debug_normal; + +#define BGP_DEBUG_FSM 0x01 +#define BGP_DEBUG_EVENTS 0x01 +#define BGP_DEBUG_PACKET 0x01 +#define BGP_DEBUG_FILTER 0x01 +#define BGP_DEBUG_KEEPALIVE 0x01 +#define BGP_DEBUG_UPDATE_IN 0x01 +#define BGP_DEBUG_UPDATE_OUT 0x02 +#define BGP_DEBUG_NORMAL 0x01 + +#define BGP_DEBUG_PACKET_SEND 0x01 +#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02 + +#define BGP_DEBUG_PACKET_RECV 0x01 +#define BGP_DEBUG_PACKET_RECV_DETAIL 0x02 + +#define CONF_DEBUG_ON(a, b) (conf_bgp_debug_ ## a |= (BGP_DEBUG_ ## b)) +#define CONF_DEBUG_OFF(a, b) (conf_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b)) + +#define TERM_DEBUG_ON(a, b) (term_bgp_debug_ ## a |= (BGP_DEBUG_ ## b)) +#define TERM_DEBUG_OFF(a, b) (term_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b)) + +#define DEBUG_ON(a, b) \ + do { \ + CONF_DEBUG_ON(a, b); \ + TERM_DEBUG_ON(a, b); \ + } while (0) +#define DEBUG_OFF(a, b) \ + do { \ + CONF_DEBUG_OFF(a, b); \ + TERM_DEBUG_OFF(a, b); \ + } while (0) + +#define BGP_DEBUG(a, b) (term_bgp_debug_ ## a & BGP_DEBUG_ ## b) +#define CONF_BGP_DEBUG(a, b) (conf_bgp_debug_ ## a & BGP_DEBUG_ ## b) + +extern char *bgp_type_str[]; + +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 index 00000000..fca51edc --- /dev/null +++ b/bgpd/bgp_dump.c @@ -0,0 +1,741 @@ +/* BGP-4 dump routine + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "log.h" +#include "stream.h" +#include "sockunion.h" +#include "command.h" +#include "prefix.h" +#include "thread.h" +#include "bgpd/bgp_table.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_dump.h" + +enum bgp_dump_type +{ + BGP_DUMP_ALL, + BGP_DUMP_UPDATES, + BGP_DUMP_ROUTES +}; + +enum MRT_MSG_TYPES { + MSG_NULL, + MSG_START, /* sender is starting up */ + MSG_DIE, /* receiver should shut down */ + MSG_I_AM_DEAD, /* sender is shutting down */ + MSG_PEER_DOWN, /* sender's peer is down */ + MSG_PROTOCOL_BGP, /* msg is a BGP packet */ + MSG_PROTOCOL_RIP, /* msg is a RIP packet */ + MSG_PROTOCOL_IDRP, /* msg is an IDRP packet */ + MSG_PROTOCOL_RIPNG, /* msg is a RIPNG packet */ + MSG_PROTOCOL_BGP4PLUS, /* msg is a BGP4+ packet */ + MSG_PROTOCOL_BGP4PLUS_01, /* msg is a BGP4+ (draft 01) packet */ + MSG_PROTOCOL_OSPF, /* msg is an OSPF packet */ + MSG_TABLE_DUMP /* routing table dump */ +}; + +struct bgp_dump +{ + enum bgp_dump_type type; + + char *filename; + + FILE *fp; + + unsigned int interval; + + char *interval_str; + + struct thread *t_interval; +}; + +/* BGP packet dump output buffer. */ +struct stream *bgp_dump_obuf; + +/* BGP dump strucuture for 'dump bgp all' */ +struct bgp_dump bgp_dump_all; + +/* BGP dump structure for 'dump bgp updates' */ +struct bgp_dump bgp_dump_updates; + +/* BGP dump structure for 'dump bgp routes' */ +struct bgp_dump bgp_dump_routes; + +/* Dump whole BGP table is very heavy process. */ +struct thread *t_bgp_dump_routes; + +/* Some define for BGP packet dump. */ +FILE * +bgp_dump_open_file (struct bgp_dump *bgp_dump) +{ + int ret; + time_t clock; + struct tm *tm; + char fullpath[MAXPATHLEN]; + char realpath[MAXPATHLEN]; + + time (&clock); + tm = localtime (&clock); + + if (bgp_dump->filename[0] != DIRECTORY_SEP) + { + sprintf (fullpath, "%s/%s", vty_get_cwd (), bgp_dump->filename); + ret = strftime (realpath, MAXPATHLEN, fullpath, tm); + } + else + ret = strftime (realpath, MAXPATHLEN, bgp_dump->filename, tm); + + if (ret == 0) + { + zlog_warn ("bgp_dump_open_file: strftime error"); + return NULL; + } + + if (bgp_dump->fp) + fclose (bgp_dump->fp); + + + bgp_dump->fp = fopen (realpath, "w"); + + if (bgp_dump->fp == NULL) + return NULL; + + return bgp_dump->fp; +} + +int +bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval) +{ + int bgp_dump_interval_func (struct thread *); + + bgp_dump->t_interval = thread_add_timer (master, bgp_dump_interval_func, + bgp_dump, interval); + return 0; +} + +/* Dump common header. */ +void +bgp_dump_header (struct stream *obuf, int type, int subtype) +{ + time_t now; + + /* Set header. */ + time (&now); + + /* Put dump packet header. */ + stream_putl (obuf, now); + stream_putw (obuf, type); + stream_putw (obuf, subtype); + + stream_putl (obuf, 0); /* len */ +} + +void +bgp_dump_set_size (struct stream *s, int type) +{ + stream_putl_at (s, 8, stream_get_putp (s) - BGP_DUMP_HEADER_SIZE); +} + +void +bgp_dump_routes_entry (struct prefix *p, struct bgp_info *info, int afi, + int type, unsigned int seq) +{ + struct stream *obuf; + struct attr *attr; + struct peer *peer; + int plen; + int safi = 0; + + /* Make dump stream. */ + obuf = bgp_dump_obuf; + stream_reset (obuf); + + attr = info->attr; + peer = info->peer; + + /* We support MRT's old format. */ + if (type == MSG_TABLE_DUMP) + { + bgp_dump_header (obuf, MSG_TABLE_DUMP, afi); + stream_putw (obuf, 0); /* View # */ + stream_putw (obuf, seq); /* Sequence number. */ + } + else + { + bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY); + + stream_putl (obuf, info->uptime); /* Time Last Change */ + stream_putw (obuf, afi); /* Address Family */ + stream_putc (obuf, safi); /* SAFI */ + } + + if (afi == AFI_IP) + { + if (type == MSG_TABLE_DUMP) + { + /* Prefix */ + stream_put_in_addr (obuf, &p->u.prefix4); + stream_putc (obuf, p->prefixlen); + + /* Status */ + stream_putc (obuf, 1); + + /* Originated */ + stream_putl (obuf, info->uptime); + + /* Peer's IP address */ + stream_put_in_addr (obuf, &peer->su.sin.sin_addr); + + /* Peer's AS number. */ + stream_putw (obuf, peer->as); + + /* Dump attribute. */ + bgp_dump_routes_attr (obuf, attr); + } + else + { + /* Next-Hop-Len */ + stream_putc (obuf, IPV4_MAX_BYTELEN); + stream_put_in_addr (obuf, &attr->nexthop); + stream_putc (obuf, p->prefixlen); + plen = PSIZE (p->prefixlen); + stream_put (obuf, &p->u.prefix4, plen); + bgp_dump_routes_attr (obuf, attr); + } + } +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6) + { + if (type == MSG_TABLE_DUMP) + { + /* Prefix */ + stream_write (obuf, (u_char *)&p->u.prefix6, IPV6_MAX_BYTELEN); + stream_putc (obuf, p->prefixlen); + + /* Status */ + stream_putc (obuf, 1); + + /* Originated */ + stream_putl (obuf, info->uptime); + + /* Peer's IP address */ + stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr, + IPV6_MAX_BYTELEN); + + /* Peer's AS number. */ + stream_putw (obuf, peer->as); + + /* Dump attribute. */ + bgp_dump_routes_attr (obuf, attr); + } + else + { + ; + } + } +#endif /* HAVE_IPV6 */ + + /* Set length. */ + bgp_dump_set_size (obuf, type); + + fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump_routes.fp); + fflush (bgp_dump_routes.fp); +} + +/* Runs under child process. */ +void +bgp_dump_routes_func (int afi) +{ + struct stream *obuf; + struct bgp_node *rn; + struct bgp_info *info; + struct bgp *bgp; + struct bgp_table *table; + unsigned int seq = 0; + + obuf = bgp_dump_obuf; + + bgp = bgp_get_default (); + if (!bgp) + return; + + if (bgp_dump_routes.fp == NULL) + return; + + /* Walk down each BGP route. */ + table = bgp->rib[afi][SAFI_UNICAST]; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + for (info = rn->info; info; info = info->next) + bgp_dump_routes_entry (&rn->p, info, afi, MSG_TABLE_DUMP, seq++); +} + +int +bgp_dump_interval_func (struct thread *t) +{ + struct bgp_dump *bgp_dump; + + bgp_dump = THREAD_ARG (t); + bgp_dump->t_interval = NULL; + + if (bgp_dump_open_file (bgp_dump) == NULL) + return 0; + + /* In case of bgp_dump_routes, we need special route dump function. */ + if (bgp_dump->type == BGP_DUMP_ROUTES) + { + bgp_dump_routes_func (AFI_IP); + bgp_dump_routes_func (AFI_IP6); + } + + bgp_dump_interval_add (bgp_dump, bgp_dump->interval); + + return 0; +} + +/* Dump common information. */ +void +bgp_dump_common (struct stream *obuf, struct peer *peer) +{ + char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + /* Source AS number and Destination AS number. */ + stream_putw (obuf, peer->as); + stream_putw (obuf, peer->local_as); + + if (peer->afc[AFI_IP][SAFI_UNICAST]) + { + stream_putw (obuf, peer->ifindex); + stream_putw (obuf, AFI_IP); + + stream_put (obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN); + + if (peer->su_local) + stream_put (obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN); + else + stream_put (obuf, empty, IPV4_MAX_BYTELEN); + } +#ifdef HAVE_IPV6 + else if (peer->afc[AFI_IP6][SAFI_UNICAST]) + { + /* Interface Index and Address family. */ + stream_putw (obuf, peer->ifindex); + stream_putw (obuf, AFI_IP6); + + /* Source IP Address and Destination IP Address. */ + stream_put (obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN); + + if (peer->su_local) + stream_put (obuf, &peer->su_local->sin6.sin6_addr, IPV6_MAX_BYTELEN); + else + stream_put (obuf, empty, IPV6_MAX_BYTELEN); + } +#endif /* HAVE_IPV6 */ +} + +/* Dump BGP status change. */ +void +bgp_dump_state (struct peer *peer, int status_old, int status_new) +{ + struct stream *obuf; + + /* If dump file pointer is disabled return immediately. */ + if (bgp_dump_all.fp == NULL) + return; + + /* Make dump stream. */ + obuf = bgp_dump_obuf; + stream_reset (obuf); + + bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE); + bgp_dump_common (obuf, peer); + + stream_putw (obuf, status_old); + stream_putw (obuf, status_new); + + /* Set length. */ + bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP); + + /* Write to the stream. */ + fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump_all.fp); + fflush (bgp_dump_all.fp); +} + +void +bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer, + struct stream *packet) +{ + struct stream *obuf; + + /* If dump file pointer is disabled return immediately. */ + if (bgp_dump->fp == NULL) + return; + + /* Make dump stream. */ + obuf = bgp_dump_obuf; + stream_reset (obuf); + + /* Dump header and common part. */ + bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE); + bgp_dump_common (obuf, peer); + + /* Packet contents. */ + stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet)); + + /* Set length. */ + bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP); + + /* Write to the stream. */ + fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump->fp); + fflush (bgp_dump->fp); +} + +/* Called from bgp_packet.c when BGP packet is received. */ +void +bgp_dump_packet (struct peer *peer, int type, struct stream *packet) +{ + /* bgp_dump_all. */ + bgp_dump_packet_func (&bgp_dump_all, peer, packet); + + /* bgp_dump_updates. */ + if (type == BGP_MSG_UPDATE) + bgp_dump_packet_func (&bgp_dump_updates, peer, packet); +} + +unsigned int +bgp_dump_parse_time (char *str) +{ + int i; + int len; + int seen_h; + int seen_m; + int time; + unsigned int total; + + time = 0; + total = 0; + seen_h = 0; + seen_m = 0; + len = strlen (str); + + for (i = 0; i < len; i++) + { + if (isdigit ((int) str[i])) + { + time *= 10; + time += str[i] - '0'; + } + else if (str[i] == 'H' || str[i] == 'h') + { + if (seen_h) + return 0; + if (seen_m) + return 0; + total += time * 60 *60; + time = 0; + seen_h = 1; + } + else if (str[i] == 'M' || str[i] == 'm') + { + if (seen_m) + return 0; + total += time * 60; + time = 0; + seen_h = 1; + } + else + return 0; + } + return total + time; +} + +int +bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump, int type, + char *path, char *interval_str) +{ + if (interval_str) + { + unsigned int interval; + + /* Check interval string. */ + interval = bgp_dump_parse_time (interval_str); + if (interval == 0) + { + vty_out (vty, "Malformed interval string%s", VTY_NEWLINE); + return CMD_WARNING; + } + /* Set interval. */ + bgp_dump->interval = interval; + if (bgp_dump->interval_str) + free (bgp_dump->interval_str); + bgp_dump->interval_str = strdup (interval_str); + + /* Create interval thread. */ + bgp_dump_interval_add (bgp_dump, interval); + } + + /* Set type. */ + bgp_dump->type = type; + + /* Set file name. */ + if (bgp_dump->filename) + free (bgp_dump->filename); + bgp_dump->filename = strdup (path); + + /* This should be called when interval is expired. */ + bgp_dump_open_file (bgp_dump); + + return CMD_SUCCESS; +} + +int +bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump) +{ + /* Set file name. */ + if (bgp_dump->filename) + { + free (bgp_dump->filename); + bgp_dump->filename = NULL; + } + + /* This should be called when interval is expired. */ + if (bgp_dump->fp) + { + fclose (bgp_dump->fp); + bgp_dump->fp = NULL; + } + + /* Create interval thread. */ + if (bgp_dump->t_interval) + { + thread_cancel (bgp_dump->t_interval); + bgp_dump->t_interval = NULL; + } + + bgp_dump->interval = 0; + + if (bgp_dump->interval_str) + { + free (bgp_dump->interval_str); + bgp_dump->interval_str = NULL; + } + + + return CMD_SUCCESS; +} + +DEFUN (dump_bgp_all, + dump_bgp_all_cmd, + "dump bgp all PATH", + "Dump packet\n" + "BGP packet dump\n" + "Dump all BGP packets\n" + "Output filename\n") +{ + return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], NULL); +} + +DEFUN (dump_bgp_all_interval, + dump_bgp_all_interval_cmd, + "dump bgp all PATH INTERVAL", + "Dump packet\n" + "BGP packet dump\n" + "Dump all BGP packets\n" + "Output filename\n" + "Interval of output\n") +{ + return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], argv[1]); +} + +DEFUN (no_dump_bgp_all, + no_dump_bgp_all_cmd, + "no dump bgp all [PATH] [INTERVAL]", + NO_STR + "Dump packet\n" + "BGP packet dump\n" + "Dump all BGP packets\n") +{ + return bgp_dump_unset (vty, &bgp_dump_all); +} + +DEFUN (dump_bgp_updates, + dump_bgp_updates_cmd, + "dump bgp updates PATH", + "Dump packet\n" + "BGP packet dump\n" + "Dump BGP updates only\n" + "Output filename\n") +{ + return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], NULL); +} + +DEFUN (dump_bgp_updates_interval, + dump_bgp_updates_interval_cmd, + "dump bgp updates PATH INTERVAL", + "Dump packet\n" + "BGP packet dump\n" + "Dump BGP updates only\n" + "Output filename\n" + "Interval of output\n") +{ + return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], argv[1]); +} + +DEFUN (no_dump_bgp_updates, + no_dump_bgp_updates_cmd, + "no dump bgp updates [PATH] [INTERVAL]", + NO_STR + "Dump packet\n" + "BGP packet dump\n" + "Dump BGP updates only\n") +{ + return bgp_dump_unset (vty, &bgp_dump_updates); +} + +DEFUN (dump_bgp_routes, + dump_bgp_routes_cmd, + "dump bgp routes-mrt PATH", + "Dump packet\n" + "BGP packet dump\n" + "Dump whole BGP routing table\n" + "Output filename\n") +{ + return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], NULL); +} + +DEFUN (dump_bgp_routes_interval, + dump_bgp_routes_interval_cmd, + "dump bgp routes-mrt PATH INTERVAL", + "Dump packet\n" + "BGP packet dump\n" + "Dump whole BGP routing table\n" + "Output filename\n" + "Interval of output\n") +{ + return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], argv[1]); +} + +DEFUN (no_dump_bgp_routes, + no_dump_bgp_routes_cmd, + "no dump bgp routes-mrt [PATH] [INTERVAL]", + NO_STR + "Dump packet\n" + "BGP packet dump\n" + "Dump whole BGP routing table\n") +{ + return bgp_dump_unset (vty, &bgp_dump_routes); +} + +/* BGP node structure. */ +struct cmd_node bgp_dump_node = +{ + DUMP_NODE, + "", +}; + +#if 0 +char * +config_time2str (unsigned int interval) +{ + static char buf[BUFSIZ]; + + buf[0] = '\0'; + + if (interval / 3600) + { + sprintf (buf, "%dh", interval / 3600); + interval %= 3600; + } + if (interval / 60) + { + sprintf (buf + strlen (buf), "%dm", interval /60); + interval %= 60; + } + if (interval) + { + sprintf (buf + strlen (buf), "%d", interval); + } + return buf; +} +#endif + +int +config_write_bgp_dump (struct vty *vty) +{ + if (bgp_dump_all.filename) + { + if (bgp_dump_all.interval_str) + vty_out (vty, "dump bgp all %s %s%s", + bgp_dump_all.filename, bgp_dump_all.interval_str, + VTY_NEWLINE); + else + vty_out (vty, "dump bgp all %s%s", + bgp_dump_all.filename, VTY_NEWLINE); + } + if (bgp_dump_updates.filename) + { + if (bgp_dump_updates.interval_str) + vty_out (vty, "dump bgp updates %s %s%s", + bgp_dump_updates.filename, bgp_dump_updates.interval_str, + VTY_NEWLINE); + else + vty_out (vty, "dump bgp updates %s%s", + bgp_dump_updates.filename, VTY_NEWLINE); + } + if (bgp_dump_routes.filename) + { + if (bgp_dump_routes.interval_str) + vty_out (vty, "dump bgp routes-mrt %s %s%s", + bgp_dump_routes.filename, bgp_dump_routes.interval_str, + VTY_NEWLINE); + else + vty_out (vty, "dump bgp routes-mrt %s%s", + bgp_dump_routes.filename, VTY_NEWLINE); + } + return 0; +} + +/* Initialize BGP packet dump functionality. */ +void +bgp_dump_init () +{ + memset (&bgp_dump_all, 0, sizeof (struct bgp_dump)); + memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump)); + memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump)); + + bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_HEADER_SIZE); + + install_node (&bgp_dump_node, config_write_bgp_dump); + + install_element (CONFIG_NODE, &dump_bgp_all_cmd); + install_element (CONFIG_NODE, &dump_bgp_all_interval_cmd); + install_element (CONFIG_NODE, &no_dump_bgp_all_cmd); + install_element (CONFIG_NODE, &dump_bgp_updates_cmd); + install_element (CONFIG_NODE, &dump_bgp_updates_interval_cmd); + install_element (CONFIG_NODE, &no_dump_bgp_updates_cmd); + install_element (CONFIG_NODE, &dump_bgp_routes_cmd); + install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd); + install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd); +} diff --git a/bgpd/bgp_dump.h b/bgpd/bgp_dump.h new file mode 100644 index 00000000..d2f96a9e --- /dev/null +++ b/bgpd/bgp_dump.h @@ -0,0 +1,34 @@ +/* BGP dump routine. + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* MRT compatible packet dump values. */ +/* type value */ +#define MSG_PROTOCOL_BGP4MP 16 +/* subtype value */ +#define BGP4MP_STATE_CHANGE 0 +#define BGP4MP_MESSAGE 1 +#define BGP4MP_ENTRY 2 +#define BGP4MP_SNAPSHOT 3 + +#define BGP_DUMP_HEADER_SIZE 12 + +void bgp_dump_init (); +void bgp_dump_state (struct peer *, int, int); +void bgp_dump_packet (struct peer *, int, struct stream *); diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c new file mode 100644 index 00000000..2f9cc945 --- /dev/null +++ b/bgpd/bgp_ecommunity.c @@ -0,0 +1,641 @@ +/* BGP Extended Communities Attribute + Copyright (C) 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "hash.h" +#include "memory.h" +#include "prefix.h" +#include "command.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_ecommunity.h" + +/* Hash of community attribute. */ +struct hash *ecomhash; + +/* Allocate a new ecommunities. */ +struct ecommunity * +ecommunity_new () +{ + return (struct ecommunity *) XCALLOC (MTYPE_ECOMMUNITY, + sizeof (struct ecommunity)); +} + +/* Allocate ecommunities. */ +void +ecommunity_free (struct ecommunity *ecom) +{ + if (ecom->val) + XFREE (MTYPE_ECOMMUNITY_VAL, ecom->val); + if (ecom->str) + XFREE (MTYPE_ECOMMUNITY_STR, ecom->str); + XFREE (MTYPE_ECOMMUNITY, ecom); +} + +/* Add a new Extended Communities value to Extended Communities + Attribute structure. When the value is already exists in the + structure, we don't add the value. Newly added value is sorted by + numerical order. When the value is added to the structure return 1 + else return 0. */ +static int +ecommunity_add_val (struct ecommunity *ecom, struct ecommunity_val *eval) +{ + u_char *p; + int ret; + int c; + + /* When this is fist value, just add it. */ + if (ecom->val == NULL) + { + ecom->size++; + ecom->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom_length (ecom)); + memcpy (ecom->val, eval->val, ECOMMUNITY_SIZE); + return 1; + } + + /* If the value already exists in the structure return 0. */ + c = 0; + for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) + { + ret = memcmp (p, eval->val, ECOMMUNITY_SIZE); + if (ret == 0) + return 0; + if (ret > 0) + break; + } + + /* Add the value to the structure with numerical sorting. */ + ecom->size++; + ecom->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom->val, ecom_length (ecom)); + + memmove (ecom->val + (c + 1) * ECOMMUNITY_SIZE, + ecom->val + c * ECOMMUNITY_SIZE, + (ecom->size - 1 - c) * ECOMMUNITY_SIZE); + memcpy (ecom->val + c * ECOMMUNITY_SIZE, eval->val, ECOMMUNITY_SIZE); + + return 1; +} + +/* This function takes pointer to Extended Communites strucutre then + create a new Extended Communities structure by uniq and sort each + Exteneded Communities value. */ +struct ecommunity * +ecommunity_uniq_sort (struct ecommunity *ecom) +{ + int i; + struct ecommunity *new; + struct ecommunity_val *eval; + + if (! ecom) + return NULL; + + new = ecommunity_new ();; + + for (i = 0; i < ecom->size; i++) + { + eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE)); + ecommunity_add_val (new, eval); + } + return new; +} + +/* Parse Extended Communites Attribute in BGP packet. */ +struct ecommunity * +ecommunity_parse (char *pnt, u_short length) +{ + struct ecommunity tmp; + struct ecommunity *new; + + /* Length check. */ + if (length % ECOMMUNITY_SIZE) + return NULL; + + /* Prepare tmporary structure for making a new Extended Communities + Attribute. */ + tmp.size = length / ECOMMUNITY_SIZE; + tmp.val = pnt; + + /* Create a new Extended Communities Attribute by uniq and sort each + Extended Communities value */ + new = ecommunity_uniq_sort (&tmp); + + return ecommunity_intern (new); +} + +/* Duplicate the Extended Communities Attribute structure. */ +struct ecommunity * +ecommunity_dup (struct ecommunity *ecom) +{ + struct ecommunity *new; + + new = XCALLOC (MTYPE_ECOMMUNITY, sizeof (struct ecommunity)); + new->size = ecom->size; + if (new->size) + { + new->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE); + memcpy (new->val, ecom->val, ecom->size * ECOMMUNITY_SIZE); + } + else + new->val = NULL; + return new; +} + +/* Merge two Extended Communities Attribute structure. */ +struct ecommunity * +ecommunity_merge (struct ecommunity *ecom1, struct ecommunity *ecom2) +{ + if (ecom1->val) + ecom1->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom1->val, + (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE); + else + ecom1->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, + (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE); + + memcpy (ecom1->val + (ecom1->size * ECOMMUNITY_SIZE), + ecom2->val, ecom2->size * ECOMMUNITY_SIZE); + ecom1->size += ecom2->size; + + return ecom1; +} + +/* Intern Extended Communities Attribute. */ +struct ecommunity * +ecommunity_intern (struct ecommunity *ecom) +{ + struct ecommunity *find; + + assert (ecom->refcnt == 0); + + find = (struct ecommunity *) hash_get (ecomhash, ecom, hash_alloc_intern); + + if (find != ecom) + ecommunity_free (ecom); + + find->refcnt++; + + if (! find->str) + find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY); + + return find; +} + +/* Unintern Extended Communities Attribute. */ +void +ecommunity_unintern (struct ecommunity *ecom) +{ + struct ecommunity *ret; + + if (ecom->refcnt) + ecom->refcnt--; + + /* Pull off from hash. */ + if (ecom->refcnt == 0) + { + /* Extended community must be in the hash. */ + ret = (struct ecommunity *) hash_release (ecomhash, ecom); + assert (ret != NULL); + + ecommunity_free (ecom); + } +} + +/* Utinity function to make hash key. */ +unsigned int +ecommunity_hash_make (struct ecommunity *ecom) +{ + int c; + unsigned int key; + unsigned char *pnt; + + key = 0; + pnt = ecom->val; + + for (c = 0; c < ecom->size * ECOMMUNITY_SIZE; c++) + key += pnt[c]; + + return key; +} + +/* Compare two Extended Communities Attribute structure. */ +int +ecommunity_cmp (struct ecommunity *ecom1, struct ecommunity *ecom2) +{ + if (ecom1->size == ecom2->size + && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0) + return 1; + return 0; +} + +/* Initialize Extended Comminities related hash. */ +void +ecommunity_init () +{ + ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp); +} + +/* Extended Communities token enum. */ +enum ecommunity_token +{ + ecommunity_token_rt, + ecommunity_token_soo, + ecommunity_token_val, + ecommunity_token_unknown +}; + +/* Get next Extended Communities token from the string. */ +char * +ecommunity_gettoken (char *str, struct ecommunity_val *eval, + enum ecommunity_token *token) +{ + int ret; + int dot = 0; + int digit = 0; + int separator = 0; + u_int32_t val_low = 0; + u_int32_t val_high = 0; + char *p = str; + struct in_addr ip; + char ipstr[INET_ADDRSTRLEN + 1]; + + /* Skip white space. */ + while (isspace ((int) *p)) + { + p++; + str++; + } + + /* Check the end of the line. */ + if (*p == '\0') + return NULL; + + /* "rt" and "soo" keyword parse. */ + if (! isdigit ((int) *p)) + { + /* "rt" match check. */ + if (tolower ((int) *p) == 'r') + { + p++; + if (tolower ((int) *p) == 't') + { + p++; + *token = ecommunity_token_rt; + return p; + } + if (isspace ((int) *p) || *p == '\0') + { + *token = ecommunity_token_rt; + return p; + } + goto error; + } + /* "soo" match check. */ + else if (tolower ((int) *p) == 's') + { + p++; + if (tolower ((int) *p) == 'o') + { + p++; + if (tolower ((int) *p) == 'o') + { + p++; + *token = ecommunity_token_soo; + return p; + } + if (isspace ((int) *p) || *p == '\0') + { + *token = ecommunity_token_soo; + return p; + } + goto error; + } + if (isspace ((int) *p) || *p == '\0') + { + *token = ecommunity_token_soo; + return p; + } + goto error; + } + goto error; + } + + while (isdigit ((int) *p) || *p == ':' || *p == '.') + { + if (*p == ':') + { + if (separator) + goto error; + + separator = 1; + digit = 0; + + if (dot) + { + if ((p - str) > INET_ADDRSTRLEN) + goto error; + + memset (ipstr, 0, INET_ADDRSTRLEN + 1); + memcpy (ipstr, str, p - str); + + ret = inet_aton (ipstr, &ip); + if (ret == 0) + goto error; + } + else + val_high = val_low; + + val_low = 0; + } + else if (*p == '.') + { + if (separator) + goto error; + dot++; + if (dot > 4) + goto error; + } + else + { + digit = 1; + val_low *= 10; + val_low += (*p - '0'); + } + p++; + } + + /* Low digit part must be there. */ + if (! digit || ! separator) + goto error; + + /* Encode result into routing distinguisher. */ + if (dot) + { + eval->val[0] = ECOMMUNITY_ENCODE_IP; + eval->val[1] = 0; + memcpy (&eval->val[2], &ip, sizeof (struct in_addr)); + eval->val[6] = (val_low >> 8) & 0xff; + eval->val[7] = val_low & 0xff; + } + else + { + eval->val[0] = ECOMMUNITY_ENCODE_AS; + eval->val[1] = 0; + eval->val[2] = (val_high >>8) & 0xff; + eval->val[3] = val_high & 0xff; + eval->val[4] = (val_low >>24) & 0xff; + eval->val[5] = (val_low >>16) & 0xff; + eval->val[6] = (val_low >>8) & 0xff; + eval->val[7] = val_low & 0xff; + } + *token = ecommunity_token_val; + return p; + + error: + *token = ecommunity_token_unknown; + return p; +} + +/* Convert string to extended community attribute. + + When type is already known, please specify both str and type. str + should not include keyword such as "rt" and "soo". Type is + ECOMMUNITY_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 index 00000000..678d1308 --- /dev/null +++ b/bgpd/bgp_ecommunity.h @@ -0,0 +1,72 @@ +/* BGP Extended Communities Attribute. + Copyright (C) 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* 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 index 00000000..b544c716 --- /dev/null +++ b/bgpd/bgp_filter.c @@ -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 + +#include "command.h" +#include "log.h" +#include "memory.h" +#include "buffer.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_regex.h" +#include "bgpd/bgp_filter.h" + +/* List of AS filter list. */ +struct as_list_list +{ + struct as_list *head; + struct as_list *tail; +}; + +/* AS path filter master. */ +struct as_list_master +{ + /* List of access_list which name is number. */ + struct as_list_list num; + + /* List of access_list which name is string. */ + struct as_list_list str; + + /* Hook function which is executed when new access_list is added. */ + void (*add_hook) (); + + /* Hook function which is executed when access_list is deleted. */ + void (*delete_hook) (); +}; + +/* Element of AS path filter. */ +struct as_filter +{ + struct as_filter *next; + struct as_filter *prev; + + enum as_filter_type type; + + regex_t *reg; + char *reg_str; +}; + +enum as_list_type +{ + ACCESS_TYPE_STRING, + ACCESS_TYPE_NUMBER +}; + +/* AS path filter list. */ +struct as_list +{ + char *name; + + enum as_list_type type; + + struct as_list *next; + struct as_list *prev; + + struct as_filter *head; + struct as_filter *tail; +}; + +/* ip as-path access-list 10 permit AS1. */ + +static struct as_list_master as_list_master = +{ + {NULL, NULL}, + {NULL, NULL}, + NULL, + NULL +}; + +/* Allocate new AS filter. */ +struct as_filter * +as_filter_new () +{ + struct as_filter *new; + + new = XMALLOC (MTYPE_AS_FILTER, sizeof (struct as_filter)); + memset (new, 0, sizeof (struct as_filter)); + return new; +} + +/* Free allocated AS filter. */ +void +as_filter_free (struct as_filter *asfilter) +{ + if (asfilter->reg) + bgp_regex_free (asfilter->reg); + if (asfilter->reg_str) + XFREE (MTYPE_AS_FILTER_STR, asfilter->reg_str); + XFREE (MTYPE_AS_FILTER, asfilter); +} + +/* Make new AS filter. */ +struct as_filter * +as_filter_make (regex_t *reg, char *reg_str, enum as_filter_type type) +{ + struct as_filter *asfilter; + + asfilter = as_filter_new (); + asfilter->reg = reg; + asfilter->type = type; + asfilter->reg_str = XSTRDUP (MTYPE_AS_FILTER_STR, reg_str); + + return asfilter; +} + +struct as_filter * +as_filter_lookup (struct as_list *aslist, char *reg_str, + enum as_filter_type type) +{ + struct as_filter *asfilter; + + for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) + if (strcmp (reg_str, asfilter->reg_str) == 0) + return asfilter; + return NULL; +} + +void +as_list_filter_add (struct as_list *aslist, struct as_filter *asfilter) +{ + asfilter->next = NULL; + asfilter->prev = aslist->tail; + + if (aslist->tail) + aslist->tail->next = asfilter; + else + aslist->head = asfilter; + aslist->tail = asfilter; +} + +/* Lookup as_list from list of as_list by name. */ +struct as_list * +as_list_lookup (char *name) +{ + struct as_list *aslist; + + if (name == NULL) + return NULL; + + for (aslist = as_list_master.num.head; aslist; aslist = aslist->next) + if (strcmp (aslist->name, name) == 0) + return aslist; + + for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) + if (strcmp (aslist->name, name) == 0) + return aslist; + + return NULL; +} + +struct as_list * +as_list_new () +{ + struct as_list *new; + + new = XMALLOC (MTYPE_AS_LIST, sizeof (struct as_list)); + memset (new, 0, sizeof (struct as_list)); + return new; +} + +void +as_list_free (struct as_list *aslist) +{ + XFREE (MTYPE_AS_LIST, aslist); +} + +/* Insert new AS list to list of as_list. Each as_list is sorted by + the name. */ +struct as_list * +as_list_insert (char *name) +{ + int i; + long number; + struct as_list *aslist; + struct as_list *point; + struct as_list_list *list; + + /* Allocate new access_list and copy given name. */ + aslist = as_list_new (); + aslist->name = strdup (name); + + /* If name is made by all digit character. We treat it as + number. */ + for (number = 0, i = 0; i < strlen (name); i++) + { + if (isdigit ((int) name[i])) + number = (number * 10) + (name[i] - '0'); + else + break; + } + + /* In case of name is all digit character */ + if (i == strlen (name)) + { + aslist->type = ACCESS_TYPE_NUMBER; + + /* Set access_list to number list. */ + list = &as_list_master.num; + + for (point = list->head; point; point = point->next) + if (atol (point->name) >= number) + break; + } + else + { + aslist->type = ACCESS_TYPE_STRING; + + /* Set access_list to string list. */ + list = &as_list_master.str; + + /* Set point to insertion point. */ + for (point = list->head; point; point = point->next) + if (strcmp (point->name, name) >= 0) + break; + } + + /* In case of this is the first element of master. */ + if (list->head == NULL) + { + list->head = list->tail = aslist; + return aslist; + } + + /* In case of insertion is made at the tail of access_list. */ + if (point == NULL) + { + aslist->prev = list->tail; + list->tail->next = aslist; + list->tail = aslist; + return aslist; + } + + /* In case of insertion is made at the head of access_list. */ + if (point == list->head) + { + aslist->next = list->head; + list->head->prev = aslist; + list->head = aslist; + return aslist; + } + + /* Insertion is made at middle of the access_list. */ + aslist->next = point; + aslist->prev = point->prev; + + if (point->prev) + point->prev->next = aslist; + point->prev = aslist; + + return aslist; +} + +struct as_list * +as_list_get (char *name) +{ + struct as_list *aslist; + + aslist = as_list_lookup (name); + if (aslist == NULL) + { + aslist = as_list_insert (name); + + /* Run hook function. */ + if (as_list_master.add_hook) + (*as_list_master.add_hook) (); + } + + return aslist; +} + +static char * +filter_type_str (enum as_filter_type type) +{ + switch (type) + { + case AS_FILTER_PERMIT: + return "permit"; + break; + case AS_FILTER_DENY: + return "deny"; + break; + default: + return ""; + break; + } +} + +void +as_list_delete (struct as_list *aslist) +{ + struct as_list_list *list; + struct as_filter *filter, *next; + + for (filter = aslist->head; filter; filter = next) + { + next = filter->next; + as_filter_free (filter); + } + + if (aslist->type == ACCESS_TYPE_NUMBER) + list = &as_list_master.num; + else + list = &as_list_master.str; + + if (aslist->next) + aslist->next->prev = aslist->prev; + else + list->tail = aslist->prev; + + if (aslist->prev) + aslist->prev->next = aslist->next; + else + list->head = aslist->next; + + as_list_free (aslist); +} + +static int +as_list_empty (struct as_list *aslist) +{ + if (aslist->head == NULL && aslist->tail == NULL) + return 1; + else + return 0; +} + +void +as_list_filter_delete (struct as_list *aslist, struct as_filter *asfilter) +{ + if (asfilter->next) + asfilter->next->prev = asfilter->prev; + else + aslist->tail = asfilter->prev; + + if (asfilter->prev) + asfilter->prev->next = asfilter->next; + else + aslist->head = asfilter->next; + + as_filter_free (asfilter); + + /* If access_list becomes empty delete it from access_master. */ + if (as_list_empty (aslist)) + as_list_delete (aslist); + + /* Run hook function. */ + if (as_list_master.delete_hook) + (*as_list_master.delete_hook) (); +} + +static int +as_filter_match (struct as_filter *asfilter, struct aspath *aspath) +{ + if (bgp_regexec (asfilter->reg, aspath) != REG_NOMATCH) + return 1; + return 0; +} + +/* Apply AS path filter to AS. */ +enum as_filter_type +as_list_apply (struct as_list *aslist, void *object) +{ + struct as_filter *asfilter; + struct aspath *aspath; + + aspath = (struct aspath *) object; + + if (aslist == NULL) + return AS_FILTER_DENY; + + for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) + { + if (as_filter_match (asfilter, aspath)) + return asfilter->type; + } + return AS_FILTER_DENY; +} + +/* Add hook function. */ +void +as_list_add_hook (void (*func) ()) +{ + as_list_master.add_hook = func; +} + +/* Delete hook function. */ +void +as_list_delete_hook (void (*func) ()) +{ + as_list_master.delete_hook = func; +} + +int +as_list_dup_check (struct as_list *aslist, struct as_filter *new) +{ + struct as_filter *asfilter; + + for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) + { + if (asfilter->type == new->type + && strcmp (asfilter->reg_str, new->reg_str) == 0) + return 1; + } + return 0; +} + +DEFUN (ip_as_path, ip_as_path_cmd, + "ip as-path access-list WORD (deny|permit) .LINE", + IP_STR + "BGP autonomous system path filter\n" + "Specify an access list name\n" + "Regular expression access list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "A regular-expression to match the BGP AS paths\n") +{ + enum as_filter_type type; + struct as_filter *asfilter; + struct as_list *aslist; + regex_t *regex; + struct buffer *b; + int i; + char *regstr; + int first = 0; + + /* Check the filter type. */ + if (strncmp (argv[1], "p", 1) == 0) + type = AS_FILTER_PERMIT; + else if (strncmp (argv[1], "d", 1) == 0) + type = AS_FILTER_DENY; + else + { + vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check AS path regex. */ + b = buffer_new (1024); + for (i = 2; i < argc; i++) + { + if (first) + buffer_putc (b, ' '); + else + first = 1; + + buffer_putstr (b, argv[i]); + } + buffer_putc (b, '\0'); + + regstr = buffer_getstr (b); + buffer_free (b); + + regex = bgp_regcomp (regstr); + if (!regex) + { + free (regstr); + vty_out (vty, "can't compile regexp %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + asfilter = as_filter_make (regex, regstr, type); + + free (regstr); + + /* Install new filter to the access_list. */ + aslist = as_list_get (argv[0]); + + /* Duplicate insertion check. */; + if (as_list_dup_check (aslist, asfilter)) + as_filter_free (asfilter); + else + as_list_filter_add (aslist, asfilter); + + return CMD_SUCCESS; +} + +DEFUN (no_ip_as_path, + no_ip_as_path_cmd, + "no ip as-path access-list WORD (deny|permit) .LINE", + NO_STR + IP_STR + "BGP autonomous system path filter\n" + "Specify an access list name\n" + "Regular expression access list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "A regular-expression to match the BGP AS paths\n") +{ + enum as_filter_type type; + struct as_filter *asfilter; + struct as_list *aslist; + struct buffer *b; + int i; + int first = 0; + char *regstr; + regex_t *regex; + + /* Lookup AS list from AS path list. */ + aslist = as_list_lookup (argv[0]); + if (aslist == NULL) + { + vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check the filter type. */ + if (strncmp (argv[1], "p", 1) == 0) + type = AS_FILTER_PERMIT; + else if (strncmp (argv[1], "d", 1) == 0) + type = AS_FILTER_DENY; + else + { + vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Compile AS path. */ + b = buffer_new (1024); + for (i = 2; i < argc; i++) + { + if (first) + buffer_putc (b, ' '); + else + first = 1; + + buffer_putstr (b, argv[i]); + } + buffer_putc (b, '\0'); + + regstr = buffer_getstr (b); + buffer_free (b); + + regex = bgp_regcomp (regstr); + if (!regex) + { + free (regstr); + vty_out (vty, "can't compile regexp %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Lookup asfilter. */ + asfilter = as_filter_lookup (aslist, regstr, type); + + free (regstr); + bgp_regex_free (regex); + + if (asfilter == NULL) + { + vty_out (vty, "%s", VTY_NEWLINE); + return CMD_WARNING; + } + + as_list_filter_delete (aslist, asfilter); + + return CMD_SUCCESS; +} + +DEFUN (no_ip_as_path_all, + no_ip_as_path_all_cmd, + "no ip as-path access-list WORD", + NO_STR + IP_STR + "BGP autonomous system path filter\n" + "Specify an access list name\n" + "Regular expression access list name\n") +{ + struct as_list *aslist; + + aslist = as_list_lookup (argv[0]); + if (aslist == NULL) + { + vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + as_list_delete (aslist); + + 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 index 00000000..8d55a224 --- /dev/null +++ b/bgpd/bgp_filter.h @@ -0,0 +1,31 @@ +/* AS path filter list. + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +enum as_filter_type +{ + AS_FILTER_DENY, + AS_FILTER_PERMIT +}; + +enum as_filter_type as_list_apply (struct as_list *, void *); + +struct as_list *as_list_lookup (char *); +void as_list_add_hook (void (*func) ()); +void as_list_delete_hook (void (*func) ()); diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c new file mode 100644 index 00000000..64a4c1bd --- /dev/null +++ b/bgpd/bgp_fsm.c @@ -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 + +#include "linklist.h" +#include "prefix.h" +#include "vty.h" +#include "sockunion.h" +#include "thread.h" +#include "log.h" +#include "stream.h" +#include "memory.h" +#include "plist.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_packet.h" +#include "bgpd/bgp_network.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_dump.h" +#include "bgpd/bgp_open.h" +#ifdef HAVE_SNMP +#include "bgpd/bgp_snmp.h" +#endif /* HAVE_SNMP */ + +/* BGP FSM (finite state machine) has three types of functions. Type + one is thread functions. Type two is event functions. Type three + is FSM functions. Timer functions are set by bgp_timer_set + function. */ + +/* BGP event function. */ +int bgp_event (struct thread *); + +/* BGP thread functions. */ +static int bgp_start_timer (struct thread *); +static int bgp_connect_timer (struct thread *); +static int bgp_holdtime_timer (struct thread *); +static int bgp_keepalive_timer (struct thread *); + +/* BGP FSM functions. */ +static int bgp_start (struct peer *); + +/* BGP start timer jitter. */ +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; +} + +/* 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 index 00000000..f051aaa7 --- /dev/null +++ b/bgpd/bgp_fsm.h @@ -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 index 00000000..7fc68fa7 --- /dev/null +++ b/bgpd/bgp_main.c @@ -0,0 +1,285 @@ +/* Main routine of bgpd. + Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "vector.h" +#include "vty.h" +#include "command.h" +#include "getopt.h" +#include "thread.h" +#include "version.h" +#include "memory.h" +#include "prefix.h" +#include "log.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_mplsvpn.h" + +/* bgpd options, we use GNU getopt library. */ +struct option longopts[] = +{ + { "daemon", no_argument, NULL, 'd'}, + { "config_file", required_argument, NULL, 'f'}, + { "pid_file", required_argument, NULL, 'i'}, + { "bgp_port", required_argument, NULL, 'p'}, + { "vty_addr", required_argument, NULL, 'A'}, + { "vty_port", required_argument, NULL, 'P'}, + { "retain", no_argument, NULL, 'r'}, + { "no_kernel", no_argument, NULL, 'n'}, + { "version", no_argument, NULL, 'v'}, + { "help", no_argument, NULL, 'h'}, + { 0 } +}; + +/* Configuration file and directory. */ +char config_current[] = BGP_DEFAULT_CONFIG; +char config_default[] = SYSCONFDIR BGP_DEFAULT_CONFIG; + +/* Route retain mode flag. */ +int retain_mode = 0; + +/* Master of threads. */ +struct thread_master *master; + +/* Manually specified configuration file name. */ +char *config_file = NULL; + +/* Process ID saved for use by init system */ +char *pid_file = PATH_BGPD_PID; + +/* VTY port number and address. */ +int vty_port = BGP_VTY_PORT; +char *vty_addr = NULL; + +/* Help information display. */ +static void +usage (char *progname, int status) +{ + if (status != 0) + fprintf (stderr, "Try `%s --help' for more information.\n", progname); + else + { + printf ("Usage : %s [OPTION...]\n\n\ +Daemon which manages kernel routing table management and \ +redistribution between different routing protocols.\n\n\ +-d, --daemon Runs in daemon mode\n\ +-f, --config_file Set configuration file name\n\ +-i, --pid_file Set process identifier file name\n\ +-p, --bgp_port Set bgp protocol's port number\n\ +-A, --vty_addr Set vty's bind address\n\ +-P, --vty_port Set vty's port number\n\ +-r, --retain When program terminates, retain added route by bgpd.\n\ +-n, --no_kernel Do not install route to kernel.\n\ +-v, --version Print program version\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); + } + + exit (status); +} + +/* SIGHUP handler. */ +void +sighup (int sig) +{ + zlog (NULL, LOG_INFO, "SIGHUP received"); + + /* Terminate all thread. */ + bgp_terminate (); + bgp_reset (); + zlog_info ("bgpd restarting!"); + + /* Reload config file. */ + vty_read_config (config_file, config_current, config_default); + + /* Create VTY's socket */ + vty_serv_sock (vty_addr, vty_port ? vty_port : BGP_VTY_PORT, BGP_VTYSH_PATH); + + /* Try to return to normal operation. */ +} + +/* SIGINT handler. */ +void +sigint (int sig) +{ + zlog (NULL, LOG_INFO, "Terminating on signal"); + + if (! retain_mode) + bgp_terminate (); + + exit (0); +} + +/* SIGUSR1 handler. */ +void +sigusr1 (int sig) +{ + zlog_rotate (NULL); +} + +/* Signale wrapper. */ +RETSIGTYPE * +signal_set (int signo, void (*func)(int)) +{ + int ret; + struct sigaction sig; + struct sigaction osig; + + sig.sa_handler = func; + sigemptyset (&sig.sa_mask); + sig.sa_flags = 0; +#ifdef SA_RESTART + sig.sa_flags |= SA_RESTART; +#endif /* SA_RESTART */ + + ret = sigaction (signo, &sig, &osig); + + if (ret < 0) + return (SIG_ERR); + else + return (osig.sa_handler); +} + +/* Initialization of signal handles. */ +void +signal_init () +{ + signal_set (SIGHUP, sighup); + signal_set (SIGINT, sigint); + signal_set (SIGTERM, sigint); + signal_set (SIGPIPE, SIG_IGN); + signal_set (SIGUSR1, sigusr1); +} + +/* Main routine of bgpd. Treatment of argument and start bgp finite + state machine is handled at here. */ +int +main (int argc, char **argv) +{ + char *p; + int opt; + int daemon_mode = 0; + char *progname; + struct thread thread; + + /* Set umask before anything for security */ + umask (0027); + + /* Preserve name of myself. */ + progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + + zlog_default = openzlog (progname, ZLOG_NOLOG, ZLOG_BGP, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + + /* BGP master init. */ + bgp_master_init (); + + /* Command line argument treatment. */ + while (1) + { + opt = getopt_long (argc, argv, "df:hp:A:P:rnv", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + case 'd': + daemon_mode = 1; + break; + case 'f': + config_file = optarg; + break; + case 'i': + pid_file = optarg; + break; + case 'p': + bm->port = atoi (optarg); + break; + case 'A': + vty_addr = optarg; + break; + case 'P': + vty_port = atoi (optarg); + break; + case 'r': + retain_mode = 1; + break; + case 'n': + bgp_option_set (BGP_OPT_NO_FIB); + break; + case 'v': + print_version (progname); + exit (0); + break; + case 'h': + usage (progname, 0); + break; + default: + usage (progname, 1); + break; + } + } + + /* Make thread master. */ + master = bm->master; + + /* Initializations. */ + srand (time (NULL)); + signal_init (); + cmd_init (1); + vty_init (); + memory_init (); + + /* BGP related initialization. */ + bgp_init (); + + /* Sort CLI commands. */ + sort_node (); + + /* Parse config file. */ + vty_read_config (config_file, config_current, config_default); + + /* Turn into daemon if daemon_mode is set. */ + if (daemon_mode) + daemon (0, 0); + + /* Process ID file creation. */ + pid_output (pid_file); + + /* Make bgp vty socket. */ + vty_serv_sock (vty_addr, vty_port, BGP_VTYSH_PATH); + + /* Print banner. */ + zlog_info ("BGPd %s starting: vty@%d, bgp@%d", ZEBRA_VERSION, + vty_port, bm->port); + + /* Start finite state machine, here we go! */ + while (thread_fetch (master, &thread)) + thread_call (&thread); + + /* Not reached. */ + exit (0); +} diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c new file mode 100644 index 00000000..e820cabf --- /dev/null +++ b/bgpd/bgp_mplsvpn.c @@ -0,0 +1,741 @@ +/* MPLS-VPN + Copyright (C) 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "command.h" +#include "prefix.h" +#include "log.h" +#include "memory.h" +#include "stream.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_mplsvpn.h" + +int route_vty_out (struct vty *, struct prefix *, struct bgp_info *, int, safi_t); +int route_vty_out_tag (struct vty *, struct prefix *, struct bgp_info *, int, safi_t); +void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, safi_t); + +u_int16_t +decode_rd_type (u_char *pnt) +{ + u_int16_t v; + + v = ((u_int16_t) *pnt++ << 8); + v |= (u_int16_t) *pnt; + return v; +} + +u_int32_t +decode_label (u_char *pnt) +{ + u_int32_t l; + + l = ((u_int32_t) *pnt++ << 12); + l |= (u_int32_t) *pnt++ << 4; + l |= (u_int32_t) ((*pnt & 0xf0) >> 4); + return l; +} + +void +decode_rd_as (u_char *pnt, struct rd_as *rd_as) +{ + rd_as->as = (u_int16_t) *pnt++ << 8; + rd_as->as |= (u_int16_t) *pnt++; + + rd_as->val = ((u_int32_t) *pnt++ << 24); + rd_as->val |= ((u_int32_t) *pnt++ << 16); + rd_as->val |= ((u_int32_t) *pnt++ << 8); + rd_as->val |= (u_int32_t) *pnt; +} + +void +decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip) +{ + memcpy (&rd_ip->ip, pnt, 4); + pnt += 4; + + rd_ip->val = ((u_int16_t) *pnt++ << 8); + rd_ip->val |= (u_int16_t) *pnt; +} + +int bgp_update (struct peer *, struct prefix *, struct attr *, + afi_t, safi_t, int, int, struct prefix_rd *, u_char *); + +int bgp_withdraw (struct peer *, struct prefix *, struct attr *, + int, int, int, int, struct prefix_rd *, u_char *); +int +bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, + struct bgp_nlri *packet) +{ + u_char *pnt; + u_char *lim; + struct prefix p; + int psize; + int prefixlen; + u_int32_t label; + u_int16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip; + struct prefix_rd prd; + u_char *tagpnt; + + /* Check peer status. */ + if (peer->status != Established) + return 0; + + /* Make prefix_rd */ + prd.family = AF_UNSPEC; + prd.prefixlen = 64; + + pnt = packet->nlri; + lim = pnt + packet->length; + + for (; pnt < lim; pnt += psize) + { + /* Clear prefix structure. */ + memset (&p, 0, sizeof (struct prefix)); + + /* Fetch prefix length. */ + prefixlen = *pnt++; + p.family = AF_INET; + psize = PSIZE (prefixlen); + + if (prefixlen < 88) + { + zlog_err ("prefix length is less than 88: %d", prefixlen); + return -1; + } + + label = decode_label (pnt); + + /* Copyr label to prefix. */ + tagpnt = pnt;; + + /* Copy routing distinguisher to rd. */ + memcpy (&prd.val, pnt + 3, 8); + + /* Decode RD type. */ + type = decode_rd_type (pnt + 3); + + /* Decode RD value. */ + if (type == RD_TYPE_AS) + decode_rd_as (pnt + 5, &rd_as); + else if (type == RD_TYPE_IP) + decode_rd_ip (pnt + 5, &rd_ip); + else + { + zlog_err ("Invalid RD type %d", type); + return -1; + } + + p.prefixlen = prefixlen - 88; + memcpy (&p.u.prefix, pnt + 11, psize - 11); + +#if 0 + if (type == RD_TYPE_AS) + zlog_info ("prefix %ld:%ld:%ld:%s/%d", label, rd_as.as, rd_as.val, + inet_ntoa (p.u.prefix4), p.prefixlen); + else if (type == RD_TYPE_IP) + zlog_info ("prefix %ld:%s:%ld:%s/%d", label, inet_ntoa (rd_ip.ip), + rd_ip.val, inet_ntoa (p.u.prefix4), p.prefixlen); +#endif /* 0 */ + + if (pnt + psize > lim) + return -1; + + if (attr) + bgp_update (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); + else + bgp_withdraw (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); + } + + /* Packet length consistency check. */ + if (pnt != lim) + return -1; + + return 0; +} + +int +str2prefix_rd (u_char *str, struct prefix_rd *prd) +{ + int ret; + u_char *p; + u_char *p2; + struct stream *s; + u_char *half; + struct in_addr addr; + + s = stream_new (8); + + prd->family = AF_UNSPEC; + prd->prefixlen = 64; + + p = strchr (str, ':'); + if (! p) + return 0; + + if (! all_digit (p + 1)) + return 0; + + half = XMALLOC (MTYPE_TMP, (p - str) + 1); + memcpy (half, str, (p - str)); + half[p - str] = '\0'; + + p2 = strchr (str, '.'); + + if (! p2) + { + if (! all_digit (half)) + { + XFREE (MTYPE_TMP, half); + return 0; + } + stream_putw (s, RD_TYPE_AS); + stream_putw (s, atoi (half)); + stream_putl (s, atol (p + 1)); + } + else + { + ret = inet_aton (half, &addr); + if (! ret) + { + XFREE (MTYPE_TMP, half); + return 0; + } + stream_putw (s, RD_TYPE_IP); + stream_put_in_addr (s, &addr); + stream_putw (s, atol (p + 1)); + } + memcpy (prd->val, s->data, 8); + + return 1; +} + +int +str2tag (u_char *str, u_char *tag) +{ + u_int32_t l; + + l = atol (str); + + tag[0] = (u_char)(l >> 12); + tag[1] = (u_char)(l >> 4); + tag[2] = (u_char)(l << 4); + + return 1; +} + +char * +prefix_rd2str (struct prefix_rd *prd, char *buf, size_t size) +{ + u_char *pnt; + u_int16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip; + + if (size < RD_ADDRSTRLEN) + return NULL; + + pnt = prd->val; + + type = decode_rd_type (pnt); + + if (type == RD_TYPE_AS) + { + decode_rd_as (pnt + 2, &rd_as); + snprintf (buf, size, "%d:%d", rd_as.as, rd_as.val); + return buf; + } + else if (type == RD_TYPE_IP) + { + decode_rd_ip (pnt + 2, &rd_ip); + snprintf (buf, size, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); + return buf; + } + + return NULL; +} + +/* For testing purpose, static route of MPLS-VPN. */ +DEFUN (vpnv4_network, + vpnv4_network_cmd, + "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify Route Distinguisher\n" + "VPN Route Distinguisher\n" + "BGP tag\n" + "tag value\n") +{ + return bgp_static_set_vpnv4 (vty, argv[0], argv[1], argv[2]); +} + +/* For testing purpose, static route of MPLS-VPN. */ +DEFUN (no_vpnv4_network, + no_vpnv4_network_cmd, + "no network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", + NO_STR + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify Route Distinguisher\n" + "VPN Route Distinguisher\n" + "BGP tag\n" + "tag value\n") +{ + return bgp_static_unset_vpnv4 (vty, argv[0], argv[1], argv[2]); +} + +int +show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd) +{ + struct bgp *bgp; + struct bgp_table *table; + struct bgp_node *rn; + struct bgp_node *rm; + struct attr *attr; + int rd_header; + int header = 1; + char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; + + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; + rn = bgp_route_next (rn)) + { + if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) + continue; + + if ((table = rn->info) != NULL) + { + rd_header = 1; + + for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) + if ((attr = rm->info) != NULL) + { + if (header) + { + vty_out (vty, "BGP table version is 0, local router ID is %s%s", + inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", + VTY_NEWLINE); + vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", + VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, v4_header, VTY_NEWLINE); + header = 0; + } + + if (rd_header) + { + u_int16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip; + u_char *pnt; + + pnt = rn->p.u.val; + + /* Decode RD type. */ + type = decode_rd_type (pnt); + /* Decode RD value. */ + if (type == RD_TYPE_AS) + decode_rd_as (pnt + 2, &rd_as); + else if (type == RD_TYPE_IP) + decode_rd_ip (pnt + 2, &rd_ip); + + vty_out (vty, "Route Distinguisher: "); + + if (type == RD_TYPE_AS) + vty_out (vty, "%d:%d", rd_as.as, rd_as.val); + else if (type == RD_TYPE_IP) + vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); + + vty_out (vty, "%s", VTY_NEWLINE); + rd_header = 0; + } + route_vty_out_tmp (vty, &rm->p, attr, SAFI_MPLS_VPN); + } + } + } + return CMD_SUCCESS; +} + +enum bgp_show_type +{ + bgp_show_type_normal, + bgp_show_type_regexp, + bgp_show_type_prefix_list, + bgp_show_type_filter_list, + bgp_show_type_neighbor, + bgp_show_type_cidr_only, + bgp_show_type_prefix_longer, + bgp_show_type_community_all, + bgp_show_type_community, + bgp_show_type_community_exact, + bgp_show_type_community_list, + bgp_show_type_community_list_exact +}; + +int +bgp_show_mpls_vpn (struct vty *vty, struct prefix_rd *prd, enum bgp_show_type type, + void *output_arg, int tags) +{ + struct bgp *bgp; + struct bgp_table *table; + struct bgp_node *rn; + struct bgp_node *rm; + struct bgp_info *ri; + int rd_header; + int header = 1; + char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; + char v4_header_tag[] = " Network Next Hop In tag/Out tag%s"; + + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) + { + if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) + continue; + + if ((table = rn->info) != NULL) + { + rd_header = 1; + + for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) + for (ri = rm->info; ri; ri = ri->next) + { + if (type == bgp_show_type_neighbor) + { + union sockunion *su = output_arg; + + if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su)) + continue; + } + if (header) + { + if (tags) + vty_out (vty, v4_header_tag, VTY_NEWLINE); + else + { + vty_out (vty, "BGP table version is 0, local router ID is %s%s", + inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", + VTY_NEWLINE); + vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", + VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, v4_header, VTY_NEWLINE); + } + header = 0; + } + + if (rd_header) + { + u_int16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip; + u_char *pnt; + + pnt = rn->p.u.val; + + /* Decode RD type. */ + type = decode_rd_type (pnt); + /* Decode RD value. */ + if (type == RD_TYPE_AS) + decode_rd_as (pnt + 2, &rd_as); + else if (type == RD_TYPE_IP) + decode_rd_ip (pnt + 2, &rd_ip); + + vty_out (vty, "Route Distinguisher: "); + + if (type == RD_TYPE_AS) + vty_out (vty, "%d:%d", rd_as.as, rd_as.val); + else if (type == RD_TYPE_IP) + vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); + + vty_out (vty, "%s", VTY_NEWLINE); + rd_header = 0; + } + if (tags) + route_vty_out_tag (vty, &rm->p, ri, 0, SAFI_MPLS_VPN); + else + route_vty_out (vty, &rm->p, ri, 0, SAFI_MPLS_VPN); + } + } + } + return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_vpnv4_all, + show_ip_bgp_vpnv4_all_cmd, + "show ip bgp vpnv4 all", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n") +{ + return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_normal, NULL, 0); +} + +DEFUN (show_ip_bgp_vpnv4_rd, + show_ip_bgp_vpnv4_rd_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n") +{ + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_normal, NULL, 0); +} + +DEFUN (show_ip_bgp_vpnv4_all_tags, + show_ip_bgp_vpnv4_all_tags_cmd, + "show ip bgp vpnv4 all tags", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Display BGP tags for prefixes\n") +{ + return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_normal, NULL, 1); +} + +DEFUN (show_ip_bgp_vpnv4_rd_tags, + show_ip_bgp_vpnv4_rd_tags_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn tags", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Display BGP tags for prefixes\n") +{ + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_normal, NULL, 1); +} + +DEFUN (show_ip_bgp_vpnv4_all_neighbor_routes, + show_ip_bgp_vpnv4_all_neighbor_routes_cmd, + "show ip bgp vpnv4 all neighbors A.B.C.D routes", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + union sockunion *su; + struct peer *peer; + + su = sockunion_str2su (argv[0]); + if (su == NULL) + { + vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, su); + if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_neighbor, su, 0); +} + +DEFUN (show_ip_bgp_vpnv4_rd_neighbor_routes, + show_ip_bgp_vpnv4_rd_neighbor_routes_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + int ret; + union sockunion *su; + struct peer *peer; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + su = sockunion_str2su (argv[1]); + if (su == NULL) + { + vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, su); + if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_neighbor, su, 0); +} + +DEFUN (show_ip_bgp_vpnv4_all_neighbor_advertised_routes, + show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd, + "show ip bgp vpnv4 all neighbors A.B.C.D advertised-routes", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") +{ + int ret; + struct peer *peer; + union sockunion su; + + ret = str2sockunion (argv[0], &su); + if (ret < 0) + { + vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return show_adj_route_vpn (vty, peer, NULL); +} + +DEFUN (show_ip_bgp_vpnv4_rd_neighbor_advertised_routes, + show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") +{ + int ret; + struct peer *peer; + struct prefix_rd prd; + union sockunion su; + + ret = str2sockunion (argv[1], &su); + if (ret < 0) + { + vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return show_adj_route_vpn (vty, peer, &prd); +} + +void +bgp_mplsvpn_init () +{ + install_element (BGP_VPNV4_NODE, &vpnv4_network_cmd); + install_element (BGP_VPNV4_NODE, &no_vpnv4_network_cmd); + + + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_tags_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd); + + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_tags_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd); +} diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h new file mode 100644 index 00000000..cd861a87 --- /dev/null +++ b/bgpd/bgp_mplsvpn.h @@ -0,0 +1,45 @@ +/* MPLS-VPN + Copyright (C) 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#define RD_TYPE_AS 0 +#define RD_TYPE_IP 1 + +#define RD_ADDRSTRLEN 28 + +struct rd_as +{ + u_int16_t type; + as_t as; + u_int32_t val; +}; + +struct rd_ip +{ + u_int16_t type; + struct in_addr ip; + u_int16_t val; +}; + +void bgp_mplsvpn_init (); +int bgp_nlri_parse_vpnv4 (struct peer *, struct attr *, struct bgp_nlri *); +u_int32_t decode_label (u_char *); +int str2prefix_rd (u_char *, struct prefix_rd *); +int str2tag (u_char *, u_char *); +char *prefix_rd2str (struct prefix_rd *, char *, size_t); diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c new file mode 100644 index 00000000..40e9cdb3 --- /dev/null +++ b/bgpd/bgp_network.c @@ -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 + +#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" + +/* 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 index 00000000..b9949873 --- /dev/null +++ b/bgpd/bgp_network.h @@ -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 index 00000000..24a113d9 --- /dev/null +++ b/bgpd/bgp_nexthop.c @@ -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 + +#include "command.h" +#include "thread.h" +#include "prefix.h" +#include "zclient.h" +#include "stream.h" +#include "network.h" +#include "log.h" +#include "memory.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_nexthop.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_damp.h" +#include "zebra/rib.h" +#include "zebra/zserv.h" /* For ZEBRA_SERV_PATH. */ + +struct bgp_nexthop_cache *zlookup_query (struct in_addr); +#ifdef HAVE_IPV6 +struct bgp_nexthop_cache *zlookup_query_ipv6 (struct in6_addr *); +#endif /* HAVE_IPV6 */ + +/* Only one BGP scan thread are activated at the same time. */ +struct thread *bgp_scan_thread = NULL; + +/* BGP import thread */ +struct thread *bgp_import_thread = NULL; + +/* BGP scan interval. */ +int bgp_scan_interval; + +/* BGP import interval. */ +int bgp_import_interval; + +/* Route table for next-hop lookup cache. */ +struct bgp_table *bgp_nexthop_cache_ipv4; +struct bgp_table *cache1; +struct bgp_table *cache2; + +/* Route table for next-hop lookup cache. */ +struct bgp_table *bgp_nexthop_cache_ipv6; +struct bgp_table *cache6_1; +struct bgp_table *cache6_2; + +/* Route table for connected route. */ +struct bgp_table *bgp_connected_ipv4; + +/* Route table for connected route. */ +struct bgp_table *bgp_connected_ipv6; + +/* BGP nexthop lookup query client. */ +static struct zclient *zlookup = NULL; + +/* BGP process function. */ +int bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t); + +/* Add nexthop to the end of the list. */ +void +bnc_nexthop_add (struct bgp_nexthop_cache *bnc, struct nexthop *nexthop) +{ + struct nexthop *last; + + for (last = bnc->nexthop; last && last->next; last = last->next) + ; + if (last) + last->next = nexthop; + else + bnc->nexthop = nexthop; + nexthop->prev = last; +} + +void +bnc_nexthop_free (struct bgp_nexthop_cache *bnc) +{ + struct nexthop *nexthop; + struct nexthop *next = NULL; + + for (nexthop = bnc->nexthop; nexthop; nexthop = next) + { + next = nexthop->next; + XFREE (MTYPE_NEXTHOP, nexthop); + } +} + +struct bgp_nexthop_cache * +bnc_new () +{ + struct bgp_nexthop_cache *new; + + new = XMALLOC (MTYPE_BGP_NEXTHOP_CACHE, sizeof (struct bgp_nexthop_cache)); + memset (new, 0, sizeof (struct bgp_nexthop_cache)); + return new; +} + +void +bnc_free (struct bgp_nexthop_cache *bnc) +{ + bnc_nexthop_free (bnc); + XFREE (MTYPE_BGP_NEXTHOP_CACHE, bnc); +} + +int +bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2) +{ + if (next1->type != next2->type) + return 0; + + switch (next1->type) + { + case ZEBRA_NEXTHOP_IPV4: + if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4)) + return 0; + break; + case ZEBRA_NEXTHOP_IFINDEX: + case ZEBRA_NEXTHOP_IFNAME: + if (next1->ifindex != next2->ifindex) + return 0; + break; +#ifdef HAVE_IPV6 + case ZEBRA_NEXTHOP_IPV6: + if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) + return 0; + break; + case ZEBRA_NEXTHOP_IPV6_IFINDEX: + case ZEBRA_NEXTHOP_IPV6_IFNAME: + if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) + return 0; + if (next1->ifindex != next2->ifindex) + return 0; + break; +#endif /* HAVE_IPV6 */ + } + return 1; +} + +int +bgp_nexthop_cache_changed (struct bgp_nexthop_cache *bnc1, + struct bgp_nexthop_cache *bnc2) +{ + int i; + struct nexthop *next1, *next2; + + if (bnc1->nexthop_num != bnc2->nexthop_num) + return 1; + + next1 = bnc1->nexthop; + next2 = bnc2->nexthop; + + for (i = 0; i < bnc1->nexthop_num; i++) + { + if (! bgp_nexthop_same (next1, next2)) + return 1; + + next1 = next1->next; + next2 = next2->next; + } + return 0; +} + +/* If nexthop exists on connected network return 1. */ +int +bgp_nexthop_check_ebgp (afi_t afi, struct attr *attr) +{ + struct bgp_node *rn; + + /* If zebra is not enabled return */ + if (zlookup->sock < 0) + return 1; + + /* Lookup the address is onlink or not. */ + if (afi == AFI_IP) + { + rn = bgp_node_match_ipv4 (bgp_connected_ipv4, &attr->nexthop); + if (rn) + { + bgp_unlock_node (rn); + return 1; + } + } +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6) + { + if (attr->mp_nexthop_len == 32) + return 1; + else if (attr->mp_nexthop_len == 16) + { + if (IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_global)) + return 1; + + rn = bgp_node_match_ipv6 (bgp_connected_ipv6, + &attr->mp_nexthop_global); + if (rn) + { + bgp_unlock_node (rn); + return 1; + } + } + } +#endif /* HAVE_IPV6 */ + return 0; +} + +#ifdef HAVE_IPV6 +/* Check specified next-hop is reachable or not. */ +int +bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, + int *metricchanged) +{ + struct bgp_node *rn; + struct prefix p; + struct bgp_nexthop_cache *bnc; + struct attr *attr; + + /* If lookup is not enabled, return valid. */ + if (zlookup->sock < 0) + { + ri->igpmetric = 0; + return 1; + } + + /* Only check IPv6 global address only nexthop. */ + attr = ri->attr; + + if (attr->mp_nexthop_len != 16 + || IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_global)) + return 1; + + memset (&p, 0, sizeof (struct prefix)); + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_BITLEN; + p.u.prefix6 = attr->mp_nexthop_global; + + /* IBGP or ebgp-multihop */ + rn = bgp_node_get (bgp_nexthop_cache_ipv6, &p); + + if (rn->info) + { + bnc = rn->info; + bgp_unlock_node (rn); + } + else + { + bnc = zlookup_query_ipv6 (&attr->mp_nexthop_global); + if (bnc) + { + struct bgp_table *old; + struct bgp_node *oldrn; + struct bgp_nexthop_cache *oldbnc; + + if (changed) + { + if (bgp_nexthop_cache_ipv6 == cache6_1) + old = cache6_2; + else + old = cache6_1; + + oldrn = bgp_node_lookup (old, &p); + if (oldrn) + { + oldbnc = oldrn->info; + + bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc); + + if (bnc->metric != oldbnc->metric) + bnc->metricchanged = 1; + } + } + } + else + { + bnc = bnc_new (); + bnc->valid = 0; + } + rn->info = bnc; + } + + if (changed) + *changed = bnc->changed; + + if (metricchanged) + *metricchanged = bnc->metricchanged; + + if (bnc->valid) + ri->igpmetric = bnc->metric; + else + ri->igpmetric = 0; + + return bnc->valid; +} +#endif /* HAVE_IPV6 */ + +/* Check specified next-hop is reachable or not. */ +int +bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, + int *changed, int *metricchanged) +{ + struct bgp_node *rn; + struct prefix p; + struct bgp_nexthop_cache *bnc; + struct in_addr addr; + + /* If lookup is not enabled, return valid. */ + if (zlookup->sock < 0) + { + ri->igpmetric = 0; + return 1; + } + +#ifdef HAVE_IPV6 + if (afi == AFI_IP6) + return bgp_nexthop_lookup_ipv6 (peer, ri, changed, metricchanged); +#endif /* HAVE_IPV6 */ + + addr = ri->attr->nexthop; + + memset (&p, 0, sizeof (struct prefix)); + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = addr; + + /* IBGP or ebgp-multihop */ + rn = bgp_node_get (bgp_nexthop_cache_ipv4, &p); + + if (rn->info) + { + bnc = rn->info; + bgp_unlock_node (rn); + } + else + { + bnc = zlookup_query (addr); + if (bnc) + { + struct bgp_table *old; + struct bgp_node *oldrn; + struct bgp_nexthop_cache *oldbnc; + + if (changed) + { + if (bgp_nexthop_cache_ipv4 == cache1) + old = cache2; + else + old = cache1; + + oldrn = bgp_node_lookup (old, &p); + if (oldrn) + { + oldbnc = oldrn->info; + + bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc); + + if (bnc->metric != oldbnc->metric) + bnc->metricchanged = 1; + } + } + } + else + { + bnc = bnc_new (); + bnc->valid = 0; + } + rn->info = bnc; + } + + if (changed) + *changed = bnc->changed; + + if (metricchanged) + *metricchanged = bnc->metricchanged; + + if (bnc->valid) + ri->igpmetric = bnc->metric; + else + ri->igpmetric = 0; + + return bnc->valid; +} + +/* Reset and free all BGP nexthop cache. */ +void +bgp_nexthop_cache_reset (struct bgp_table *table) +{ + struct bgp_node *rn; + struct bgp_nexthop_cache *bnc; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + if ((bnc = rn->info) != NULL) + { + bnc_free (bnc); + rn->info = NULL; + bgp_unlock_node (rn); + } +} + +void +bgp_scan_ipv4 () +{ + struct bgp_node *rn; + struct bgp *bgp; + struct bgp_info *bi; + struct bgp_info *next; + struct peer *peer; + struct listnode *nn; + int valid; + int current; + int changed; + int metricchanged; + + /* Change cache. */ + if (bgp_nexthop_cache_ipv4 == cache1) + bgp_nexthop_cache_ipv4 = cache2; + else + bgp_nexthop_cache_ipv4 = cache1; + + /* Get default bgp. */ + bgp = bgp_get_default (); + if (bgp == NULL) + return; + + /* Maximum prefix check */ + LIST_LOOP (bgp->peer, peer, nn) + { + if (peer->status != Established) + continue; + + if (peer->afc[AFI_IP][SAFI_UNICAST]) + bgp_maximum_prefix_overflow (peer, AFI_IP, SAFI_UNICAST); + 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; +} + +struct bgp_connected +{ + unsigned int refcnt; +}; + +void +bgp_connected_add (struct connected *ifc) +{ + struct prefix p; + struct prefix *addr; + struct prefix *dest; + struct interface *ifp; + struct bgp_node *rn; + struct bgp_connected *bc; + + ifp = ifc->ifp; + + if (! ifp) + return; + + if (if_is_loopback (ifp)) + return; + + addr = ifc->address; + dest = ifc->destination; + + if (addr->family == AF_INET) + { + memset (&p, 0, sizeof (struct prefix)); + p.family = AF_INET; + p.prefixlen = addr->prefixlen; + + if (if_is_pointopoint (ifp)) + p.u.prefix4 = dest->u.prefix4; + else + p.u.prefix4 = addr->u.prefix4; + + apply_mask_ipv4 ((struct prefix_ipv4 *) &p); + + if (prefix_ipv4_any ((struct prefix_ipv4 *) &p)) + return; + + rn = bgp_node_get (bgp_connected_ipv4, (struct prefix *) &p); + if (rn->info) + { + bc = rn->info; + bc->refcnt++; + } + else + { + bc = XMALLOC (0, sizeof (struct bgp_connected)); + memset (bc, 0, sizeof (struct bgp_connected)); + bc->refcnt = 1; + rn->info = bc; + } + } +#ifdef HAVE_IPV6 + if (addr->family == AF_INET6) + { + memset (&p, 0, sizeof (struct prefix)); + p.family = AF_INET6; + p.prefixlen = addr->prefixlen; + + if (if_is_pointopoint (ifp)) + p.u.prefix6 = dest->u.prefix6; + else + p.u.prefix6 = addr->u.prefix6; + + apply_mask_ipv6 ((struct prefix_ipv6 *) &p); + + if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6)) + return; + + if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) + return; + + rn = bgp_node_get (bgp_connected_ipv6, (struct prefix *) &p); + if (rn->info) + { + bc = rn->info; + bc->refcnt++; + } + else + { + bc = XMALLOC (0, sizeof (struct bgp_connected)); + memset (bc, 0, sizeof (struct bgp_connected)); + bc->refcnt = 1; + rn->info = bc; + } + } +#endif /* HAVE_IPV6 */ +} + +void +bgp_connected_delete (struct connected *ifc) +{ + struct prefix p; + struct prefix *addr; + struct prefix *dest; + struct interface *ifp; + struct bgp_node *rn; + struct bgp_connected *bc; + + ifp = ifc->ifp; + + if (if_is_loopback (ifp)) + return; + + addr = ifc->address; + dest = ifc->destination; + + if (addr->family == AF_INET) + { + memset (&p, 0, sizeof (struct prefix)); + p.family = AF_INET; + p.prefixlen = addr->prefixlen; + + if (if_is_pointopoint (ifp)) + p.u.prefix4 = dest->u.prefix4; + else + p.u.prefix4 = addr->u.prefix4; + + apply_mask_ipv4 ((struct prefix_ipv4 *) &p); + + if (prefix_ipv4_any ((struct prefix_ipv4 *) &p)) + return; + + rn = bgp_node_lookup (bgp_connected_ipv4, &p); + if (! rn) + return; + + bc = rn->info; + bc->refcnt--; + if (bc->refcnt == 0) + { + XFREE (0, bc); + rn->info = NULL; + } + bgp_unlock_node (rn); + bgp_unlock_node (rn); + } +#ifdef HAVE_IPV6 + else if (addr->family == AF_INET6) + { + memset (&p, 0, sizeof (struct prefix)); + p.family = AF_INET6; + p.prefixlen = addr->prefixlen; + + if (if_is_pointopoint (ifp)) + p.u.prefix6 = dest->u.prefix6; + else + p.u.prefix6 = addr->u.prefix6; + + apply_mask_ipv6 ((struct prefix_ipv6 *) &p); + + if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6)) + return; + + if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) + return; + + rn = bgp_node_lookup (bgp_connected_ipv6, (struct prefix *) &p); + if (! rn) + return; + + bc = rn->info; + bc->refcnt--; + if (bc->refcnt == 0) + { + XFREE (0, bc); + rn->info = NULL; + } + bgp_unlock_node (rn); + bgp_unlock_node (rn); + } +#endif /* HAVE_IPV6 */ +} + +int +bgp_nexthop_self (afi_t afi, struct attr *attr) +{ + listnode node; + listnode node2; + struct interface *ifp; + struct connected *ifc; + struct prefix *p; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + + for (node2 = listhead (ifp->connected); node2; nextnode (node2)) + { + ifc = getdata (node2); + p = ifc->address; + + if (p && p->family == AF_INET + && IPV4_ADDR_SAME (&p->u.prefix4, &attr->nexthop)) + return 1; + } + } + return 0; +} + +struct bgp_nexthop_cache * +zlookup_read () +{ + struct stream *s; + u_int16_t length; + u_char command; + int nbytes; + struct in_addr raddr; + u_int32_t metric; + int i; + u_char nexthop_num; + struct nexthop *nexthop; + struct bgp_nexthop_cache *bnc; + + s = zlookup->ibuf; + stream_reset (s); + + nbytes = stream_read (s, zlookup->sock, 2); + length = stream_getw (s); + + nbytes = stream_read (s, zlookup->sock, length - 2); + command = stream_getc (s); + raddr.s_addr = stream_get_ipv4 (s); + metric = stream_getl (s); + nexthop_num = stream_getc (s); + + if (nexthop_num) + { + bnc = bnc_new (); + bnc->valid = 1; + bnc->metric = metric; + bnc->nexthop_num = nexthop_num; + + for (i = 0; i < nexthop_num; i++) + { + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = stream_getc (s); + switch (nexthop->type) + { + case ZEBRA_NEXTHOP_IPV4: + nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); + break; + case ZEBRA_NEXTHOP_IFINDEX: + case ZEBRA_NEXTHOP_IFNAME: + nexthop->ifindex = stream_getl (s); + break; + } + bnc_nexthop_add (bnc, nexthop); + } + } + else + return NULL; + + return bnc; +} + +struct bgp_nexthop_cache * +zlookup_query (struct in_addr addr) +{ + int ret; + struct stream *s; + + /* Check socket. */ + if (zlookup->sock < 0) + return NULL; + + s = zlookup->obuf; + stream_reset (s); + stream_putw (s, 7); + stream_putc (s, ZEBRA_IPV4_NEXTHOP_LOOKUP); + stream_put_in_addr (s, &addr); + + ret = writen (zlookup->sock, s->data, 7); + if (ret < 0) + { + zlog_err ("can't write to zlookup->sock"); + close (zlookup->sock); + zlookup->sock = -1; + return NULL; + } + if (ret == 0) + { + zlog_err ("zlookup->sock connection closed"); + close (zlookup->sock); + zlookup->sock = -1; + return NULL; + } + + return zlookup_read (); +} + +#ifdef HAVE_IPV6 +struct bgp_nexthop_cache * +zlookup_read_ipv6 () +{ + struct stream *s; + u_int16_t length; + u_char command; + int nbytes; + struct in6_addr raddr; + u_int32_t metric; + int i; + u_char nexthop_num; + struct nexthop *nexthop; + struct bgp_nexthop_cache *bnc; + + s = zlookup->ibuf; + stream_reset (s); + + nbytes = stream_read (s, zlookup->sock, 2); + length = stream_getw (s); + + nbytes = stream_read (s, zlookup->sock, length - 2); + command = stream_getc (s); + + stream_get (&raddr, s, 16); + + metric = stream_getl (s); + nexthop_num = stream_getc (s); + + if (nexthop_num) + { + bnc = bnc_new (); + bnc->valid = 1; + bnc->metric = metric; + bnc->nexthop_num = nexthop_num; + + for (i = 0; i < nexthop_num; i++) + { + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = stream_getc (s); + switch (nexthop->type) + { + case ZEBRA_NEXTHOP_IPV6: + stream_get (&nexthop->gate.ipv6, s, 16); + break; + case ZEBRA_NEXTHOP_IPV6_IFINDEX: + case ZEBRA_NEXTHOP_IPV6_IFNAME: + stream_get (&nexthop->gate.ipv6, s, 16); + nexthop->ifindex = stream_getl (s); + break; + case ZEBRA_NEXTHOP_IFINDEX: + case ZEBRA_NEXTHOP_IFNAME: + nexthop->ifindex = stream_getl (s); + break; + } + bnc_nexthop_add (bnc, nexthop); + } + } + else + return NULL; + + return bnc; +} + +struct bgp_nexthop_cache * +zlookup_query_ipv6 (struct in6_addr *addr) +{ + int ret; + struct stream *s; + + /* Check socket. */ + if (zlookup->sock < 0) + return NULL; + + s = zlookup->obuf; + stream_reset (s); + stream_putw (s, 19); + stream_putc (s, ZEBRA_IPV6_NEXTHOP_LOOKUP); + stream_put (s, addr, 16); + + ret = writen (zlookup->sock, s->data, 19); + if (ret < 0) + { + zlog_err ("can't write to zlookup->sock"); + close (zlookup->sock); + zlookup->sock = -1; + return NULL; + } + if (ret == 0) + { + zlog_err ("zlookup->sock connection closed"); + close (zlookup->sock); + zlookup->sock = -1; + return NULL; + } + + return zlookup_read_ipv6 (); +} +#endif /* HAVE_IPV6 */ + +int +bgp_import_check (struct prefix *p, u_int32_t *igpmetric, struct in_addr *igpnexthop) +{ + struct stream *s; + int ret; + u_int16_t length; + u_char command; + int nbytes; + struct in_addr addr; + struct in_addr nexthop; + u_int32_t metric = 0; + u_char nexthop_num; + u_char nexthop_type; + + /* If lookup connection is not available return valid. */ + if (zlookup->sock < 0) + { + if (igpmetric) + *igpmetric = 0; + return 1; + } + + /* Send query to the lookup connection */ + s = zlookup->obuf; + stream_reset (s); + stream_putw (s, 8); + stream_putc (s, ZEBRA_IPV4_IMPORT_LOOKUP); + stream_putc (s, p->prefixlen); + stream_put_in_addr (s, &p->u.prefix4); + + /* Write the packet. */ + ret = writen (zlookup->sock, s->data, 8); + + if (ret < 0) + { + zlog_err ("can't write to zlookup->sock"); + close (zlookup->sock); + zlookup->sock = -1; + return 1; + } + if (ret == 0) + { + zlog_err ("zlookup->sock connection closed"); + close (zlookup->sock); + zlookup->sock = -1; + return 1; + } + + /* Get result. */ + stream_reset (s); + + /* Fetch length. */ + nbytes = stream_read (s, zlookup->sock, 2); + length = stream_getw (s); + + /* Fetch whole data. */ + nbytes = stream_read (s, zlookup->sock, length - 2); + command = stream_getc (s); + addr.s_addr = stream_get_ipv4 (s); + metric = stream_getl (s); + nexthop_num = stream_getc (s); + + /* Set IGP metric value. */ + if (igpmetric) + *igpmetric = metric; + + /* If there is nexthop then this is active route. */ + if (nexthop_num) + { + nexthop.s_addr = 0; + nexthop_type = stream_getc (s); + if (nexthop_type == ZEBRA_NEXTHOP_IPV4) + { + nexthop.s_addr = stream_get_ipv4 (s); + if (igpnexthop) + *igpnexthop = nexthop; + } + else + *igpnexthop = nexthop; + + return 1; + } + else + return 0; +} + +/* Scan all configured BGP route then check the route exists in IGP or + not. */ +int +bgp_import (struct thread *t) +{ + struct bgp *bgp; + struct bgp_node *rn; + struct bgp_static *bgp_static; + 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; +} + +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 index 00000000..5f4255d8 --- /dev/null +++ b/bgpd/bgp_nexthop.h @@ -0,0 +1,52 @@ +/* BGP nexthop scan + Copyright (C) 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#define BGP_SCAN_INTERVAL_DEFAULT 60 +#define BGP_IMPORT_INTERVAL_DEFAULT 15 + +/* BGP nexthop cache value structure. */ +struct bgp_nexthop_cache +{ + /* This nexthop exists in IGP. */ + u_char valid; + + /* Nexthop is changed. */ + u_char changed; + + /* Nexthop is changed. */ + u_char metricchanged; + + /* IGP route's metric. */ + u_int32_t metric; + + /* Nexthop number and nexthop linked list.*/ + u_char nexthop_num; + struct nexthop *nexthop; +}; + +void bgp_scan_init (); +int bgp_nexthop_lookup (afi_t, struct peer *peer, struct bgp_info *, + int *, int *); +void bgp_connected_add (struct connected *c); +void bgp_connected_delete (struct connected *c); +int bgp_multiaccess_check_v4 (struct in_addr, char *); +int bgp_config_write_scan_time (struct vty *); +int bgp_nexthop_check_ebgp (afi_t, struct attr *); +int bgp_nexthop_self (afi_t, struct attr *); diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c new file mode 100644 index 00000000..a3e86b06 --- /dev/null +++ b/bgpd/bgp_open.c @@ -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 + +#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" + +/* 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 index 00000000..af7505a8 --- /dev/null +++ b/bgpd/bgp_open.h @@ -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 index 00000000..48879f35 --- /dev/null +++ b/bgpd/bgp_packet.c @@ -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 + +#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 *); + +/* 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); +} + +/* 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); +} + +/* 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 index 00000000..c1efc8bd --- /dev/null +++ b/bgpd/bgp_packet.h @@ -0,0 +1,49 @@ +/* BGP packet management header. + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#define BGP_NLRI_LENGTH 1 +#define BGP_TOTAL_ATTR_LEN 2 +#define BGP_UNFEASIBLE_LEN 2 +#define BGP_WRITE_PACKET_MAX 10 + +/* When to refresh */ +#define REFRESH_IMMEDIATE 1 +#define REFRESH_DEFER 2 + +/* ORF Common part flag */ +#define ORF_COMMON_PART_ADD 0x00 +#define ORF_COMMON_PART_REMOVE 0x80 +#define ORF_COMMON_PART_REMOVE_ALL 0xC0 +#define ORF_COMMON_PART_PERMIT 0x00 +#define ORF_COMMON_PART_DENY 0x20 + +/* Packet send and receive function prototypes. */ +int bgp_read (struct thread *); +int bgp_write (struct thread *); + +void bgp_keepalive_send (struct peer *); +void bgp_open_send (struct peer *); +void bgp_notify_send (struct peer *, u_char, u_char); +void bgp_notify_send_with_data (struct peer *, u_char, u_char, u_char *, size_t); +void bgp_route_refresh_send (struct peer *, afi_t, safi_t, u_char, u_char, int); +void bgp_capability_send (struct peer *, afi_t, safi_t, int, int); +void bgp_default_update_send (struct peer *, struct attr *, + afi_t, safi_t, struct peer *); +void bgp_default_withdraw_send (struct peer *, afi_t, safi_t); diff --git a/bgpd/bgp_regex.c b/bgpd/bgp_regex.c new file mode 100644 index 00000000..a6b65984 --- /dev/null +++ b/bgpd/bgp_regex.c @@ -0,0 +1,93 @@ +/* AS regular expression routine + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "log.h" +#include "command.h" +#include "memory.h" + +#include "bgpd.h" +#include "bgp_aspath.h" +#include "bgp_regex.h" + +/* Character `_' has special mean. It represents [,{}() ] and the + beginning of the line(^) and the end of the line ($). + + (^|[,{}() ]|$) */ + +regex_t * +bgp_regcomp (char *regstr) +{ + /* Convert _ character to generic regular expression. */ + int i, j; + int len; + int magic = 0; + char *magic_str; + char magic_regexp[] = "(^|[,{}() ]|$)"; + int ret; + regex_t *regex; + + len = strlen (regstr); + for (i = 0; i < len; i++) + if (regstr[i] == '_') + magic++; + + magic_str = XMALLOC (MTYPE_TMP, len + (14 * magic) + 1); + + for (i = 0, j = 0; i < len; i++) + { + if (regstr[i] == '_') + { + memcpy (magic_str + j, magic_regexp, strlen (magic_regexp)); + j += strlen (magic_regexp); + } + else + magic_str[j++] = regstr[i]; + } + magic_str[j] = '\0'; + + regex = XMALLOC (MTYPE_BGP_REGEXP, sizeof (regex_t)); + + ret = regcomp (regex, magic_str, REG_EXTENDED); + + XFREE (MTYPE_TMP, magic_str); + + if (ret != 0) + { + XFREE (MTYPE_BGP_REGEXP, regex); + return NULL; + } + + return regex; +} + +int +bgp_regexec (regex_t *regex, struct aspath *aspath) +{ + return regexec (regex, aspath->str, 0, NULL, 0); +} + +void +bgp_regex_free (regex_t *regex) +{ + regfree (regex); + XFREE (MTYPE_BGP_REGEXP, regex); +} diff --git a/bgpd/bgp_regex.h b/bgpd/bgp_regex.h new file mode 100644 index 00000000..0829dd9a --- /dev/null +++ b/bgpd/bgp_regex.h @@ -0,0 +1,31 @@ +/* AS regular expression routine + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#ifdef HAVE_GNU_REGEX +#include +#else +#include "regex-gnu.h" +#endif /* HAVE_GNU_REGEX */ + +void bgp_regex_free (regex_t *regex); +regex_t *bgp_regcomp (char *str); +int bgp_regexec (regex_t *regex, struct aspath *aspath); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c new file mode 100644 index 00000000..87d305cb --- /dev/null +++ b/bgpd/bgp_route.c @@ -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 + +#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[]; + +struct bgp_node * +bgp_afi_node_get (struct bgp *bgp, afi_t afi, safi_t safi, struct prefix *p, + struct prefix_rd *prd) +{ + struct bgp_node *rn; + struct bgp_node *prn = NULL; + struct bgp_table *table; + + if (safi == SAFI_MPLS_VPN) + { + prn = bgp_node_get (bgp->rib[afi][safi], (struct prefix *) prd); + + if (prn->info == NULL) + prn->info = bgp_table_init (); + else + bgp_unlock_node (prn); + table = prn->info; + } + else + table = bgp->rib[afi][safi]; + + rn = bgp_node_get (table, p); + + if (safi == SAFI_MPLS_VPN) + rn->prn = prn; + + return rn; +} + +/* Allocate new bgp info structure. */ +struct bgp_info * +bgp_info_new () +{ + struct bgp_info *new; + + new = XMALLOC (MTYPE_BGP_ROUTE, sizeof (struct bgp_info)); + memset (new, 0, sizeof (struct bgp_info)); + + return new; +} + +/* Free bgp route information. */ +void +bgp_info_free (struct bgp_info *binfo) +{ + if (binfo->attr) + bgp_attr_unintern (binfo->attr); + + if (binfo->damp_info) + bgp_damp_info_free (binfo->damp_info, 0); + + XFREE (MTYPE_BGP_ROUTE, binfo); +} + +void +bgp_info_add (struct bgp_node *rn, struct bgp_info *ri) +{ + struct bgp_info *top; + + top = rn->info; + + ri->next = rn->info; + ri->prev = NULL; + if (top) + top->prev = ri; + rn->info = ri; +} + +void +bgp_info_delete (struct bgp_node *rn, struct bgp_info *ri) +{ + if (ri->next) + ri->next->prev = ri->prev; + if (ri->prev) + ri->prev->next = ri->next; + else + rn->info = ri->next; +} + +/* Get MED value. If MED value is missing and "bgp bestpath + missing-as-worst" is specified, treat it as the worst value. */ +u_int32_t +bgp_med_value (struct attr *attr, struct bgp *bgp) +{ + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) + return attr->med; + else + { + if (bgp_flag_check (bgp, BGP_FLAG_MED_MISSING_AS_WORST)) + return 4294967295ul; + else + return 0; + } +} + +/* Compare two bgp route entity. br is preferable then return 1. */ +int +bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist) +{ + u_int32_t new_pref; + u_int32_t exist_pref; + u_int32_t new_med; + u_int32_t exist_med; + struct in_addr new_id; + struct in_addr exist_id; + int new_cluster; + int exist_cluster; + int internal_as_route = 0; + int confed_as_route = 0; + int 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; +} + +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; +} + +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; +} + +void +bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) +{ + struct bgp *bgp; + struct attr attr; + struct aspath *aspath; + struct prefix p; + struct bgp_info binfo; + struct peer *from; + int ret = RMAP_DENYMATCH; + + bgp = peer->bgp; + from = bgp->peer_self; + + bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); + aspath = attr.aspath; + attr.local_pref = bgp->default_local_pref; + memcpy (&attr.nexthop, &peer->nexthop.v4, IPV4_MAX_BYTELEN); + + if (afi == AFI_IP) + str2prefix ("0.0.0.0/0", &p); +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6) + { + str2prefix ("::/0", &p); + + /* IPv6 global nexthop must be included. */ + memcpy (&attr.mp_nexthop_global, &peer->nexthop.v6_global, + IPV6_MAX_BYTELEN); + attr.mp_nexthop_len = 16; + + /* If the peer is on shared nextwork and we have link-local + nexthop set it. */ + if (peer->shared_network + && !IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local)) + { + memcpy (&attr.mp_nexthop_local, &peer->nexthop.v6_local, + IPV6_MAX_BYTELEN); + attr.mp_nexthop_len = 32; + } + } +#endif /* HAVE_IPV6 */ + else + return; + + if (peer->default_rmap[afi][safi].name) + { + binfo.peer = bgp->peer_self; + binfo.attr = &attr; + + ret = route_map_apply (peer->default_rmap[afi][safi].map, &p, + RMAP_BGP, &binfo); + + if (ret == RMAP_DENYMATCH) + { + bgp_attr_flush (&attr); + withdraw = 1; + } + } + + if (withdraw) + { + if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) + bgp_default_withdraw_send (peer, afi, safi); + UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE); + } + else + { + SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE); + bgp_default_update_send (peer, &attr, afi, safi, from); + } + + aspath_unintern (aspath); +} + +static void +bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi, + struct bgp_table *table) +{ + struct bgp_node *rn; + struct bgp_info *ri; + struct attr attr; + + if (! table) + table = peer->bgp->rib[afi][safi]; + + if (safi != SAFI_MPLS_VPN + && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) + bgp_default_originate (peer, afi, safi, 0); + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next(rn)) + for (ri = rn->info; ri; ri = ri->next) + if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->peer != peer) + { + if (bgp_announce_check (ri, peer, &rn->p, &attr, afi, safi)) + bgp_adj_out_set (rn, peer, &rn->p, &attr, afi, safi, ri); + else + bgp_adj_out_unset (rn, peer, &rn->p, afi, safi); + } +} + +void +bgp_announce_route (struct peer *peer, afi_t afi, safi_t safi) +{ + struct bgp_node *rn; + struct bgp_table *table; + + if (peer->status != Established) + return; + + if (! peer->afc_nego[afi][safi]) + return; + + /* First update is deferred until ORF or ROUTE-REFRESH is received */ + if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) + return; + + if (safi != SAFI_MPLS_VPN) + bgp_announce_table (peer, afi, safi, NULL); + else + for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; + rn = bgp_route_next(rn)) + if ((table = (rn->info)) != NULL) + bgp_announce_table (peer, afi, safi, table); +} + +void +bgp_announce_route_all (struct peer *peer) +{ + afi_t afi; + safi_t safi; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + bgp_announce_route (peer, afi, safi); +} + +static void +bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi, + struct bgp_table *table) +{ + int ret; + struct bgp_node *rn; + struct bgp_adj_in *ain; + + if (! table) + table = peer->bgp->rib[afi][safi]; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + for (ain = rn->adj_in; ain; ain = ain->next) + { + if (ain->peer == peer) + { + ret = bgp_update (peer, &rn->p, ain->attr, afi, safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, + NULL, NULL, 1); + if (ret < 0) + { + bgp_unlock_node (rn); + return; + } + continue; + } + } +} + +void +bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi) +{ + struct bgp_node *rn; + struct bgp_table *table; + + if (peer->status != Established) + return; + + if (safi != SAFI_MPLS_VPN) + bgp_soft_reconfig_table (peer, afi, safi, NULL); + else + for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; + rn = bgp_route_next (rn)) + if ((table = rn->info) != NULL) + bgp_soft_reconfig_table (peer, afi, safi, table); +} + +static void +bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi, + struct bgp_table *table) +{ + struct bgp_node *rn; + struct bgp_adj_in *ain; + struct bgp_adj_out *aout; + struct bgp_info *ri; + + if (! table) + table = peer->bgp->rib[afi][safi]; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + { + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == peer) + { + 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; + } +} + +/* Delete all kernel routes. */ +void +bgp_terminate () +{ + struct bgp *bgp; + struct listnode *nn; + struct bgp_node *rn; + struct bgp_table *table; + struct bgp_info *ri; + + LIST_LOOP (bm->bgp, bgp, nn) + { + table = bgp->rib[AFI_IP][SAFI_UNICAST]; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + for (ri = rn->info; ri; ri = ri->next) + if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) + && ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_NORMAL) + bgp_zebra_withdraw (&rn->p, ri); + + table = bgp->rib[AFI_IP6][SAFI_UNICAST]; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + for (ri = rn->info; ri; ri = ri->next) + if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) + && ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_NORMAL) + bgp_zebra_withdraw (&rn->p, ri); + } +} + +void +bgp_reset () +{ + vty_reset (); + bgp_zclient_reset (); + access_list_reset (); + prefix_list_reset (); +} + +/* Parse NLRI stream. Withdraw NLRI is recognized by NULL attr + value. */ +int +bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) +{ + u_char *pnt; + u_char *lim; + struct prefix p; + int psize; + int ret; + + /* Check peer status. */ + if (peer->status != Established) + return 0; + + pnt = packet->nlri; + lim = pnt + packet->length; + + for (; pnt < lim; pnt += psize) + { + /* Clear prefix structure. */ + memset (&p, 0, sizeof (struct prefix)); + + /* Fetch prefix length. */ + p.prefixlen = *pnt++; + p.family = afi2family (packet->afi); + + /* Already checked in nlri_sanity_check(). We do double check + here. */ + if ((packet->afi == AFI_IP && p.prefixlen > 32) + || (packet->afi == AFI_IP6 && p.prefixlen > 128)) + return -1; + + /* Packet size overflow check. */ + psize = PSIZE (p.prefixlen); + + /* When packet overflow occur return immediately. */ + if (pnt + psize > lim) + return -1; + + /* Fetch prefix from NLRI packet. */ + memcpy (&p.u.prefix, pnt, psize); + + /* Check address. */ + if (packet->afi == AFI_IP && packet->safi == SAFI_UNICAST) + { + if (IN_CLASSD (ntohl (p.u.prefix4.s_addr))) + { + zlog (peer->log, LOG_ERR, + "IPv4 unicast NLRI is multicast address %s", + inet_ntoa (p.u.prefix4)); + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_NETWORK); + return -1; + } + } + +#ifdef HAVE_IPV6 + /* Check address. */ + if (packet->afi == AFI_IP6 && packet->safi == SAFI_UNICAST) + { + if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) + { + char buf[BUFSIZ]; + + zlog (peer->log, LOG_WARNING, + "IPv6 link-local NLRI received %s ignore this NLRI", + inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ)); + + continue; + } + } +#endif /* HAVE_IPV6 */ + + /* Normal process. */ + if (attr) + ret = bgp_update (peer, &p, attr, packet->afi, packet->safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, 0); + else + ret = bgp_withdraw (peer, &p, attr, packet->afi, packet->safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL); + + /* Address family configuration mismatch or maximum-prefix count + overflow. */ + if (ret < 0) + return -1; + } + + /* Packet length consistency check. */ + if (pnt != lim) + return -1; + + return 0; +} + +/* NLRI encode syntax check routine. */ +int +bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt, + bgp_size_t length) +{ + u_char *end; + u_char prefixlen; + int psize; + + end = pnt + length; + + /* RFC1771 6.3 The NLRI field in the UPDATE message is checked for + syntactic validity. If the field is syntactically incorrect, + then the Error Subcode is set to Invalid Network Field. */ + + while (pnt < end) + { + prefixlen = *pnt++; + + /* Prefix length check. */ + if ((afi == AFI_IP && prefixlen > 32) + || (afi == AFI_IP6 && prefixlen > 128)) + { + plog_err (peer->log, + "%s [Error] Update packet error (wrong prefix length %d)", + peer->host, prefixlen); + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_NETWORK); + return -1; + } + + /* Packet size overflow check. */ + psize = PSIZE (prefixlen); + + if (pnt + psize > end) + { + plog_err (peer->log, + "%s [Error] Update packet error" + " (prefix data overflow prefix size is %d)", + peer->host, psize); + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_NETWORK); + return -1; + } + + pnt += psize; + } + + /* Packet length consistency check. */ + if (pnt != end) + { + plog_err (peer->log, + "%s [Error] Update packet error" + " (prefix length mismatch with total length)", + peer->host); + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_NETWORK); + return -1; + } + return 0; +} + +struct bgp_static * +bgp_static_new () +{ + struct bgp_static *new; + new = XMALLOC (MTYPE_BGP_STATIC, sizeof (struct bgp_static)); + memset (new, 0, sizeof (struct bgp_static)); + return new; +} + +void +bgp_static_free (struct bgp_static *bgp_static) +{ + if (bgp_static->rmap.name) + free (bgp_static->rmap.name); + XFREE (MTYPE_BGP_STATIC, bgp_static); +} + +void +bgp_static_update (struct bgp *bgp, struct prefix *p, + struct bgp_static *bgp_static, afi_t afi, safi_t safi) +{ + struct bgp_node *rn; + struct bgp_info *ri; + struct bgp_info *new; + struct bgp_info info; + struct attr attr; + struct attr *attr_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; +} + +DEFUN (bgp_network, + bgp_network_cmd, + "network A.B.C.D/M", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_static_set (vty, vty->index, argv[0], + AFI_IP, bgp_node_safi (vty), NULL, 0); +} + +DEFUN (bgp_network_route_map, + bgp_network_route_map_cmd, + "network A.B.C.D/M route-map WORD", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") +{ + return bgp_static_set (vty, vty->index, argv[0], + AFI_IP, bgp_node_safi (vty), argv[1], 0); +} + +DEFUN (bgp_network_backdoor, + bgp_network_backdoor_cmd, + "network A.B.C.D/M backdoor", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify a BGP backdoor route\n") +{ + return bgp_static_set (vty, vty->index, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1); +} + +DEFUN (bgp_network_mask, + bgp_network_mask_cmd, + "network A.B.C.D mask A.B.C.D", + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_static_set (vty, vty->index, prefix_str, + AFI_IP, bgp_node_safi (vty), NULL, 0); +} + +DEFUN (bgp_network_mask_route_map, + bgp_network_mask_route_map_cmd, + "network A.B.C.D mask A.B.C.D route-map WORD", + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_static_set (vty, vty->index, prefix_str, + AFI_IP, bgp_node_safi (vty), argv[2], 0); +} + +DEFUN (bgp_network_mask_backdoor, + bgp_network_mask_backdoor_cmd, + "network A.B.C.D mask A.B.C.D backdoor", + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n" + "Specify a BGP backdoor route\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1); +} + +DEFUN (bgp_network_mask_natural, + bgp_network_mask_natural_cmd, + "network A.B.C.D", + "Specify a network to announce via BGP\n" + "Network number\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_static_set (vty, vty->index, prefix_str, + AFI_IP, bgp_node_safi (vty), NULL, 0); +} + +DEFUN (bgp_network_mask_natural_route_map, + bgp_network_mask_natural_route_map_cmd, + "network A.B.C.D route-map WORD", + "Specify a network to announce via BGP\n" + "Network number\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_static_set (vty, vty->index, prefix_str, + AFI_IP, bgp_node_safi (vty), argv[1], 0); +} + +DEFUN (bgp_network_mask_natural_backdoor, + bgp_network_mask_natural_backdoor_cmd, + "network A.B.C.D backdoor", + "Specify a network to announce via BGP\n" + "Network number\n" + "Specify a BGP backdoor route\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1); +} + +DEFUN (no_bgp_network, + no_bgp_network_cmd, + "no network A.B.C.D/M", + NO_STR + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_static_unset (vty, vty->index, argv[0], AFI_IP, + bgp_node_safi (vty)); +} + +ALIAS (no_bgp_network, + no_bgp_network_route_map_cmd, + "no network A.B.C.D/M route-map WORD", + NO_STR + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") + +ALIAS (no_bgp_network, + no_bgp_network_backdoor_cmd, + "no network A.B.C.D/M backdoor", + NO_STR + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify a BGP backdoor route\n") + +DEFUN (no_bgp_network_mask, + no_bgp_network_mask_cmd, + "no network A.B.C.D mask A.B.C.D", + NO_STR + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP, + bgp_node_safi (vty)); +} + +ALIAS (no_bgp_network_mask, + no_bgp_network_mask_route_map_cmd, + "no network A.B.C.D mask A.B.C.D route-map WORD", + NO_STR + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") + +ALIAS (no_bgp_network_mask, + no_bgp_network_mask_backdoor_cmd, + "no network A.B.C.D mask A.B.C.D backdoor", + NO_STR + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n" + "Specify a BGP backdoor route\n") + +DEFUN (no_bgp_network_mask_natural, + no_bgp_network_mask_natural_cmd, + "no network A.B.C.D", + NO_STR + "Specify a network to announce via BGP\n" + "Network number\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP, + bgp_node_safi (vty)); +} + +ALIAS (no_bgp_network_mask_natural, + no_bgp_network_mask_natural_route_map_cmd, + "no network A.B.C.D route-map WORD", + NO_STR + "Specify a network to announce via BGP\n" + "Network number\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") + +ALIAS (no_bgp_network_mask_natural, + no_bgp_network_mask_natural_backdoor_cmd, + "no network A.B.C.D backdoor", + NO_STR + "Specify a network to announce via BGP\n" + "Network number\n" + "Specify a BGP backdoor route\n") + +#ifdef HAVE_IPV6 +DEFUN (ipv6_bgp_network, + ipv6_bgp_network_cmd, + "network X:X::X:X/M", + "Specify a network to announce via BGP\n" + "IPv6 prefix /\n") +{ + return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); +} + +DEFUN (ipv6_bgp_network_route_map, + ipv6_bgp_network_route_map_cmd, + "network X:X::X:X/M route-map WORD", + "Specify a network to announce via BGP\n" + "IPv6 prefix /\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") +{ + return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, + bgp_node_safi (vty), argv[1], 0); +} + +DEFUN (no_ipv6_bgp_network, + no_ipv6_bgp_network_cmd, + "no network X:X::X:X/M", + NO_STR + "Specify a network to announce via BGP\n" + "IPv6 prefix /\n") +{ + return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST); +} + +ALIAS (no_ipv6_bgp_network, + no_ipv6_bgp_network_route_map_cmd, + "no network X:X::X:X/M route-map WORD", + NO_STR + "Specify a network to announce via BGP\n" + "IPv6 prefix /\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") + +ALIAS (ipv6_bgp_network, + old_ipv6_bgp_network_cmd, + "ipv6 bgp network X:X::X:X/M", + IPV6_STR + BGP_STR + "Specify a network to announce via BGP\n" + "IPv6 prefix /, e.g., 3ffe::/16\n") + +ALIAS (no_ipv6_bgp_network, + old_no_ipv6_bgp_network_cmd, + "no ipv6 bgp network X:X::X:X/M", + NO_STR + IPV6_STR + BGP_STR + "Specify a network to announce via BGP\n" + "IPv6 prefix /, e.g., 3ffe::/16\n") +#endif /* HAVE_IPV6 */ + +/* Aggreagete address: + + advertise-map Set condition to advertise attribute + as-set Generate AS set path information + attribute-map Set attributes of aggregate + route-map Set parameters of aggregate + summary-only Filter more specific routes from updates + suppress-map Conditionally filter more specific routes from updates + + */ +struct bgp_aggregate +{ + /* Summary-only flag. */ + u_char summary_only; + + /* AS set generation. */ + u_char as_set; + + /* Route-map for aggregated route. */ + struct route_map *map; + + /* Suppress-count. */ + unsigned long count; + + /* SAFI configuration. */ + safi_t safi; +}; + +struct bgp_aggregate * +bgp_aggregate_new () +{ + struct bgp_aggregate *new; + new = XMALLOC (MTYPE_BGP_AGGREGATE, sizeof (struct bgp_aggregate)); + memset (new, 0, sizeof (struct bgp_aggregate)); + return new; +} + +void +bgp_aggregate_free (struct bgp_aggregate *aggregate) +{ + XFREE (MTYPE_BGP_AGGREGATE, aggregate); +} + +void +bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew, + afi_t afi, safi_t safi, struct bgp_info *del, + struct bgp_aggregate *aggregate) +{ + struct bgp_table *table; + struct bgp_node *top; + struct bgp_node *rn; + u_char origin; + struct aspath *aspath = NULL; + struct aspath *asmerge = NULL; + struct community *community = NULL; + struct community *commerge = NULL; + struct in_addr nexthop; + u_int32_t med = 0; + struct bgp_info *ri; + struct bgp_info *new; + int first = 1; + unsigned long match = 0; + + /* Record adding route's nexthop and med. */ + if (rinew) + { + nexthop = rinew->attr->nexthop; + med = rinew->attr->med; + } + + /* ORIGIN attribute: If at least one route among routes that are + aggregated has ORIGIN with the value INCOMPLETE, then the + aggregated route must have the ORIGIN attribute with the value + INCOMPLETE. Otherwise, if at least one route among routes that + are aggregated has ORIGIN with the value EGP, then the aggregated + route must have the origin attribute with the value EGP. In all + other case the value of the ORIGIN attribute of the aggregated + route is INTERNAL. */ + origin = BGP_ORIGIN_IGP; + + table = bgp->rib[afi][safi]; + + top = bgp_node_get (table, p); + for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top)) + if (rn->p.prefixlen > p->prefixlen) + { + match = 0; + + for (ri = rn->info; ri; ri = ri->next) + { + if (BGP_INFO_HOLDDOWN (ri)) + continue; + + if (del && ri == del) + continue; + + if (! rinew && first) + { + nexthop = ri->attr->nexthop; + med = ri->attr->med; + first = 0; + } + +#ifdef AGGREGATE_NEXTHOP_CHECK + if (! IPV4_ADDR_SAME (&ri->attr->nexthop, &nexthop) + || ri->attr->med != med) + { + if (aspath) + aspath_free (aspath); + if (community) + community_free (community); + bgp_unlock_node (rn); + bgp_unlock_node (top); + return; + } +#endif /* AGGREGATE_NEXTHOP_CHECK */ + + if (ri->sub_type != BGP_ROUTE_AGGREGATE) + { + if (aggregate->summary_only) + { + ri->suppress++; + SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + match++; + } + + aggregate->count++; + + if (aggregate->as_set) + { + if (origin < ri->attr->origin) + origin = ri->attr->origin; + + if (aspath) + { + asmerge = aspath_aggregate (aspath, ri->attr->aspath); + aspath_free (aspath); + aspath = asmerge; + } + else + aspath = aspath_dup (ri->attr->aspath); + + if (ri->attr->community) + { + if (community) + { + commerge = community_merge (community, + ri->attr->community); + community = community_uniq_sort (commerge); + community_free (commerge); + } + else + community = community_dup (ri->attr->community); + } + } + } + } + if (match) + bgp_process (bgp, rn, afi, safi); + } + bgp_unlock_node (top); + + if (rinew) + { + aggregate->count++; + + if (aggregate->summary_only) + rinew->suppress++; + + if (aggregate->as_set) + { + if (origin < rinew->attr->origin) + origin = rinew->attr->origin; + + if (aspath) + { + asmerge = aspath_aggregate (aspath, rinew->attr->aspath); + aspath_free (aspath); + aspath = asmerge; + } + else + aspath = aspath_dup (rinew->attr->aspath); + + if (rinew->attr->community) + { + if (community) + { + commerge = community_merge (community, + rinew->attr->community); + community = community_uniq_sort (commerge); + community_free (commerge); + } + else + community = community_dup (rinew->attr->community); + } + } + } + + if (aggregate->count > 0) + { + rn = bgp_node_get (table, p); + new = bgp_info_new (); + new->type = ZEBRA_ROUTE_BGP; + new->sub_type = BGP_ROUTE_AGGREGATE; + new->peer = bgp->peer_self; + SET_FLAG (new->flags, BGP_INFO_VALID); + new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set); + new->uptime = time (NULL); + + bgp_info_add (rn, new); + bgp_process (bgp, rn, afi, safi); + } + else + { + if (aspath) + aspath_free (aspath); + if (community) + community_free (community); + } +} + +void bgp_aggregate_delete (struct bgp *, struct prefix *, afi_t, safi_t, + struct bgp_aggregate *); + +void +bgp_aggregate_increment (struct bgp *bgp, struct prefix *p, + struct bgp_info *ri, afi_t afi, safi_t safi) +{ + struct bgp_node *child; + struct bgp_node *rn; + struct bgp_aggregate *aggregate; + + /* MPLS-VPN aggregation is not yet supported. */ + if (safi == SAFI_MPLS_VPN) + return; + + if (p->prefixlen == 0) + return; + + if (BGP_INFO_HOLDDOWN (ri)) + return; + + child = bgp_node_get (bgp->aggregate[afi][safi], p); + + /* Aggregate address configuration check. */ + for (rn = child; rn; rn = rn->parent) + if ((aggregate = rn->info) != NULL && rn->p.prefixlen < p->prefixlen) + { + bgp_aggregate_delete (bgp, &rn->p, afi, safi, aggregate); + bgp_aggregate_route (bgp, &rn->p, ri, 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 */ + +/* Redistribute route treatment. */ +void +bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, + u_int32_t metric, u_char type) +{ + struct bgp *bgp; + struct listnode *nn; + struct bgp_info *new; + struct bgp_info *bi; + struct bgp_info info; + struct bgp_node *bn; + struct attr attr; + struct attr attr_new; + struct attr *new_attr; + afi_t afi; + int ret; + + /* Make default attribute. */ + bgp_attr_default_set (&attr, BGP_ORIGIN_INCOMPLETE); + if (nexthop) + attr.nexthop = *nexthop; + + attr.med = metric; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + + LIST_LOOP (bm->bgp, bgp, nn) + { + afi = family2afi (p->family); + + if (bgp->redist[afi][type]) + { + /* Copy attribute for modification. */ + attr_new = attr; + + if (bgp->redist_metric_flag[afi][type]) + attr_new.med = bgp->redist_metric[afi][type]; + + /* Apply route-map. */ + if (bgp->rmap[afi][type].map) + { + info.peer = bgp->peer_self; + info.attr = &attr_new; + + ret = route_map_apply (bgp->rmap[afi][type].map, p, RMAP_BGP, + &info); + if (ret == RMAP_DENYMATCH) + { + /* Free uninterned attribute. */ + bgp_attr_flush (&attr_new); + + /* Unintern original. */ + aspath_unintern (attr.aspath); + bgp_redistribute_delete (p, type); + return; + } + } + + bn = bgp_afi_node_get (bgp, afi, SAFI_UNICAST, p, NULL); + new_attr = bgp_attr_intern (&attr_new); + + for (bi = bn->info; bi; bi = bi->next) + if (bi->peer == bgp->peer_self + && bi->sub_type == BGP_ROUTE_REDISTRIBUTE) + break; + + if (bi) + { + if (attrhash_cmp (bi->attr, new_attr)) + { + bgp_attr_unintern (new_attr); + aspath_unintern (attr.aspath); + bgp_unlock_node (bn); + return; + } + else + { + /* The attribute is changed. */ + SET_FLAG (bi->flags, BGP_INFO_ATTR_CHANGED); + + /* Rewrite BGP route information. */ + bgp_aggregate_decrement (bgp, p, bi, afi, SAFI_UNICAST); + bgp_attr_unintern (bi->attr); + bi->attr = new_attr; + bi->uptime = time (NULL); + + /* Process change. */ + bgp_aggregate_increment (bgp, p, bi, afi, SAFI_UNICAST); + bgp_process (bgp, bn, afi, SAFI_UNICAST); + bgp_unlock_node (bn); + aspath_unintern (attr.aspath); + return; + } + } + + new = bgp_info_new (); + new->type = type; + new->sub_type = BGP_ROUTE_REDISTRIBUTE; + new->peer = bgp->peer_self; + SET_FLAG (new->flags, BGP_INFO_VALID); + new->attr = new_attr; + new->uptime = time (NULL); + + bgp_aggregate_increment (bgp, p, new, afi, SAFI_UNICAST); + bgp_info_add (bn, new); + bgp_process (bgp, bn, afi, SAFI_UNICAST); + } + } + + /* Unintern original. */ + aspath_unintern (attr.aspath); +} + +void +bgp_redistribute_delete (struct prefix *p, u_char type) +{ + struct bgp *bgp; + struct listnode *nn; + afi_t afi; + struct bgp_node *rn; + struct bgp_info *ri; + + LIST_LOOP (bm->bgp, bgp, nn) + { + afi = family2afi (p->family); + + if (bgp->redist[afi][type]) + { + rn = bgp_afi_node_get (bgp, afi, SAFI_UNICAST, p, NULL); + + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == bgp->peer_self + && ri->type == type) + break; + + if (ri) + { + bgp_aggregate_decrement (bgp, p, ri, afi, SAFI_UNICAST); + UNSET_FLAG (ri->flags, BGP_INFO_VALID); + bgp_process (bgp, rn, afi, SAFI_UNICAST); + bgp_info_delete (rn, ri); + bgp_info_free (ri); + bgp_unlock_node (rn); + } + bgp_unlock_node (rn); + } + } +} + +/* Withdraw specified route type's route. */ +void +bgp_redistribute_withdraw (struct bgp *bgp, afi_t afi, int type) +{ + struct bgp_node *rn; + struct bgp_info *ri; + struct bgp_table *table; + + table = bgp->rib[afi][SAFI_UNICAST]; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + { + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == bgp->peer_self + && ri->type == type) + break; + + if (ri) + { + bgp_aggregate_decrement (bgp, &rn->p, ri, afi, SAFI_UNICAST); + UNSET_FLAG (ri->flags, BGP_INFO_VALID); + bgp_process (bgp, rn, afi, SAFI_UNICAST); + bgp_info_delete (rn, ri); + bgp_info_free (ri); + bgp_unlock_node (rn); + } + } +} + +/* Static function to display route. */ +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); +} + +#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 /, e.g., 35.0.0.0/8\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1); +} + +DEFUN (show_ip_bgp_ipv4_prefix, + show_ip_bgp_ipv4_prefix_cmd, + "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1); + + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); +} + +DEFUN (show_ip_bgp_vpnv4_all_prefix, + show_ip_bgp_vpnv4_all_prefix_cmd, + "show ip bgp vpnv4 all A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1); +} + +DEFUN (show_ip_bgp_vpnv4_rd_prefix, + show_ip_bgp_vpnv4_rd_prefix_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 1); +} + +DEFUN (show_ip_bgp_view, + show_ip_bgp_view_cmd, + "show ip bgp view WORD", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "BGP view name\n") +{ + return bgp_show (vty, argv[0], AFI_IP, SAFI_UNICAST, bgp_show_type_normal); +} + +DEFUN (show_ip_bgp_view_route, + show_ip_bgp_view_route_cmd, + "show ip bgp view WORD A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Network in the BGP routing table to display\n") +{ + return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); +} + +DEFUN (show_ip_bgp_view_prefix, + show_ip_bgp_view_prefix_cmd, + "show ip bgp view WORD A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp, + show_bgp_cmd, + "show bgp", + SHOW_STR + BGP_STR) +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal); +} + +ALIAS (show_bgp, + show_bgp_ipv6_cmd, + "show bgp ipv6", + SHOW_STR + BGP_STR + "Address family\n") + +/* old command */ +DEFUN (show_ipv6_bgp, + show_ipv6_bgp_cmd, + "show ipv6 bgp", + SHOW_STR + IP_STR + BGP_STR) +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal); +} + +DEFUN (show_bgp_route, + show_bgp_route_cmd, + "show bgp X:X::X:X", + SHOW_STR + BGP_STR + "Network in the BGP routing table to display\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); +} + +ALIAS (show_bgp_route, + show_bgp_ipv6_route_cmd, + "show bgp ipv6 X:X::X:X", + SHOW_STR + BGP_STR + "Address family\n" + "Network in the BGP routing table to display\n") + +/* old command */ +DEFUN (show_ipv6_bgp_route, + show_ipv6_bgp_route_cmd, + "show ipv6 bgp X:X::X:X", + SHOW_STR + IP_STR + BGP_STR + "Network in the BGP routing table to display\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); +} + +DEFUN (show_bgp_prefix, + show_bgp_prefix_cmd, + "show bgp X:X::X:X/M", + SHOW_STR + BGP_STR + "IPv6 prefix /\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1); +} + +ALIAS (show_bgp_prefix, + show_bgp_ipv6_prefix_cmd, + "show bgp ipv6 X:X::X:X/M", + SHOW_STR + BGP_STR + "Address family\n" + "IPv6 prefix /\n") + +/* old command */ +DEFUN (show_ipv6_bgp_prefix, + show_ipv6_bgp_prefix_cmd, + "show ipv6 bgp X:X::X:X/M", + SHOW_STR + IP_STR + BGP_STR + "IPv6 prefix /, e.g., 3ffe::/16\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1); +} + +/* old command */ +DEFUN (show_ipv6_mbgp, + show_ipv6_mbgp_cmd, + "show ipv6 mbgp", + SHOW_STR + IP_STR + MBGP_STR) +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, bgp_show_type_normal); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_route, + show_ipv6_mbgp_route_cmd, + "show ipv6 mbgp X:X::X:X", + SHOW_STR + IP_STR + MBGP_STR + "Network in the MBGP routing table to display\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 0); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_prefix, + show_ipv6_mbgp_prefix_cmd, + "show ipv6 mbgp X:X::X:X/M", + SHOW_STR + IP_STR + MBGP_STR + "IPv6 prefix /, e.g., 3ffe::/16\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 1); +} +#endif + +void +bgp_show_regexp_clean (struct vty *vty) +{ + bgp_regex_free (vty->output_arg); +} + +int +bgp_show_regexp (struct vty *vty, int argc, char **argv, afi_t afi, + safi_t safi, enum bgp_show_type type) +{ + int i; + struct buffer *b; + char *regstr; + int first; + regex_t *regex; + + first = 0; + b = buffer_new (1024); + for (i = 0; i < argc; i++) + { + if (first) + buffer_putc (b, ' '); + else + { + if ((strcmp (argv[i], "unicast") == 0) || (strcmp (argv[i], "multicast") == 0)) + continue; + first = 1; + } + + buffer_putstr (b, argv[i]); + } + buffer_putc (b, '\0'); + + regstr = buffer_getstr (b); + buffer_free (b); + + regex = bgp_regcomp (regstr); + if (! regex) + { + vty_out (vty, "Can't compile regexp %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + vty->output_arg = regex; + vty->output_clean = bgp_show_regexp_clean; + + return bgp_show (vty, NULL, afi, safi, type); +} + +DEFUN (show_ip_bgp_regexp, + show_ip_bgp_regexp_cmd, + "show ip bgp regexp .LINE", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") +{ + return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, + bgp_show_type_regexp); +} + +DEFUN (show_ip_bgp_flap_regexp, + show_ip_bgp_flap_regexp_cmd, + "show ip bgp flap-statistics regexp .LINE", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") +{ + return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_regexp); +} + +DEFUN (show_ip_bgp_ipv4_regexp, + show_ip_bgp_ipv4_regexp_cmd, + "show ip bgp ipv4 (unicast|multicast) regexp .LINE", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_MULTICAST, + bgp_show_type_regexp); + + return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, + bgp_show_type_regexp); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_regexp, + show_bgp_regexp_cmd, + "show bgp regexp .LINE", + SHOW_STR + BGP_STR + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") +{ + return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_UNICAST, + bgp_show_type_regexp); +} + +ALIAS (show_bgp_regexp, + show_bgp_ipv6_regexp_cmd, + "show bgp ipv6 regexp .LINE", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") + +/* old command */ +DEFUN (show_ipv6_bgp_regexp, + show_ipv6_bgp_regexp_cmd, + "show ipv6 bgp regexp .LINE", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") +{ + return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_UNICAST, + bgp_show_type_regexp); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_regexp, + show_ipv6_mbgp_regexp_cmd, + "show ipv6 mbgp regexp .LINE", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the MBGP AS paths\n") +{ + return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_MULTICAST, + bgp_show_type_regexp); +} +#endif /* HAVE_IPV6 */ + +int +bgp_show_prefix_list (struct vty *vty, char *prefix_list_str, afi_t afi, + safi_t safi, enum bgp_show_type type) +{ + struct prefix_list *plist; + + plist = prefix_list_lookup (afi, prefix_list_str); + if (plist == NULL) + { + vty_out (vty, "%% %s is not a valid prefix-list name%s", + prefix_list_str, VTY_NEWLINE); + return CMD_WARNING; + } + + vty->output_arg = plist; + + return bgp_show (vty, NULL, afi, safi, type); +} + +DEFUN (show_ip_bgp_prefix_list, + show_ip_bgp_prefix_list_cmd, + "show ip bgp prefix-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Display routes conforming to the prefix-list\n" + "IP prefix-list name\n") +{ + return bgp_show_prefix_list (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_prefix_list); +} + +DEFUN (show_ip_bgp_flap_prefix_list, + show_ip_bgp_flap_prefix_list_cmd, + "show ip bgp flap-statistics prefix-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "Display routes conforming to the prefix-list\n" + "IP prefix-list name\n") +{ + return bgp_show_prefix_list (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_prefix_list); +} + +DEFUN (show_ip_bgp_ipv4_prefix_list, + show_ip_bgp_ipv4_prefix_list_cmd, + "show ip bgp ipv4 (unicast|multicast) prefix-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes conforming to the prefix-list\n" + "IP prefix-list name\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_prefix_list (vty, argv[1], AFI_IP, SAFI_MULTICAST, + bgp_show_type_prefix_list); + + return bgp_show_prefix_list (vty, argv[1], AFI_IP, SAFI_UNICAST, + bgp_show_type_prefix_list); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_prefix_list, + show_bgp_prefix_list_cmd, + "show bgp prefix-list WORD", + SHOW_STR + BGP_STR + "Display routes conforming to the prefix-list\n" + "IPv6 prefix-list name\n") +{ + return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_prefix_list); +} + +ALIAS (show_bgp_prefix_list, + show_bgp_ipv6_prefix_list_cmd, + "show bgp ipv6 prefix-list WORD", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes conforming to the prefix-list\n" + "IPv6 prefix-list name\n") + +/* old command */ +DEFUN (show_ipv6_bgp_prefix_list, + show_ipv6_bgp_prefix_list_cmd, + "show ipv6 bgp prefix-list WORD", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the prefix-list\n" + "IPv6 prefix-list name\n") +{ + return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_prefix_list); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_prefix_list, + show_ipv6_mbgp_prefix_list_cmd, + "show ipv6 mbgp prefix-list WORD", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the prefix-list\n" + "IPv6 prefix-list name\n") +{ + return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST, + bgp_show_type_prefix_list); +} +#endif /* HAVE_IPV6 */ + +int +bgp_show_filter_list (struct vty *vty, char *filter, afi_t afi, + safi_t safi, enum bgp_show_type type) +{ + struct as_list *as_list; + + as_list = as_list_lookup (filter); + if (as_list == NULL) + { + vty_out (vty, "%% %s is not a valid AS-path access-list name%s", filter, VTY_NEWLINE); + return CMD_WARNING; + } + + vty->output_arg = as_list; + + return bgp_show (vty, NULL, afi, safi, type); +} + +DEFUN (show_ip_bgp_filter_list, + show_ip_bgp_filter_list_cmd, + "show ip bgp filter-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") +{ + return bgp_show_filter_list (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_filter_list); +} + +DEFUN (show_ip_bgp_flap_filter_list, + show_ip_bgp_flap_filter_list_cmd, + "show ip bgp flap-statistics filter-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") +{ + return bgp_show_filter_list (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_filter_list); +} + +DEFUN (show_ip_bgp_ipv4_filter_list, + show_ip_bgp_ipv4_filter_list_cmd, + "show ip bgp ipv4 (unicast|multicast) filter-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_filter_list (vty, argv[1], AFI_IP, SAFI_MULTICAST, + bgp_show_type_filter_list); + + return bgp_show_filter_list (vty, argv[1], AFI_IP, SAFI_UNICAST, + bgp_show_type_filter_list); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_filter_list, + show_bgp_filter_list_cmd, + "show bgp filter-list WORD", + SHOW_STR + BGP_STR + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") +{ + return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_filter_list); +} + +ALIAS (show_bgp_filter_list, + show_bgp_ipv6_filter_list_cmd, + "show bgp ipv6 filter-list WORD", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") + +/* old command */ +DEFUN (show_ipv6_bgp_filter_list, + show_ipv6_bgp_filter_list_cmd, + "show ipv6 bgp filter-list WORD", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") +{ + return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_filter_list); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_filter_list, + show_ipv6_mbgp_filter_list_cmd, + "show ipv6 mbgp filter-list WORD", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") +{ + return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST, + bgp_show_type_filter_list); +} +#endif /* HAVE_IPV6 */ + +int +bgp_show_route_map (struct vty *vty, char *rmap_str, afi_t afi, + safi_t safi, enum bgp_show_type type) +{ + struct route_map *rmap; + + rmap = route_map_lookup_by_name (rmap_str); + if (! rmap) + { + vty_out (vty, "%% %s is not a valid route-map name%s", + rmap_str, VTY_NEWLINE); + return CMD_WARNING; + } + + vty->output_arg = rmap; + + return bgp_show (vty, NULL, afi, safi, type); +} + +DEFUN (show_ip_bgp_route_map, + show_ip_bgp_route_map_cmd, + "show ip bgp route-map WORD", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the route-map\n" + "A route-map to match on\n") +{ + return bgp_show_route_map (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_route_map); +} + +DEFUN (show_ip_bgp_flap_route_map, + show_ip_bgp_flap_route_map_cmd, + "show ip bgp flap-statistics route-map WORD", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "Display routes matching the route-map\n" + "A route-map to match on\n") +{ + return bgp_show_route_map (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_route_map); +} + +DEFUN (show_ip_bgp_ipv4_route_map, + show_ip_bgp_ipv4_route_map_cmd, + "show ip bgp ipv4 (unicast|multicast) route-map WORD", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the route-map\n" + "A route-map to match on\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_route_map (vty, argv[1], AFI_IP, SAFI_MULTICAST, + bgp_show_type_route_map); + + return bgp_show_route_map (vty, argv[1], AFI_IP, SAFI_UNICAST, + bgp_show_type_route_map); +} + +DEFUN (show_bgp_route_map, + show_bgp_route_map_cmd, + "show bgp route-map WORD", + SHOW_STR + BGP_STR + "Display routes matching the route-map\n" + "A route-map to match on\n") +{ + return bgp_show_route_map (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_route_map); +} + +ALIAS (show_bgp_route_map, + show_bgp_ipv6_route_map_cmd, + "show bgp ipv6 route-map WORD", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the route-map\n" + "A route-map to match on\n") + +DEFUN (show_ip_bgp_cidr_only, + show_ip_bgp_cidr_only_cmd, + "show ip bgp cidr-only", + SHOW_STR + IP_STR + BGP_STR + "Display only routes with non-natural netmasks\n") +{ + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, + bgp_show_type_cidr_only); +} + +DEFUN (show_ip_bgp_flap_cidr_only, + show_ip_bgp_flap_cidr_only_cmd, + "show ip bgp flap-statistics cidr-only", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "Display only routes with non-natural netmasks\n") +{ + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_cidr_only); +} + +DEFUN (show_ip_bgp_ipv4_cidr_only, + show_ip_bgp_ipv4_cidr_only_cmd, + "show ip bgp ipv4 (unicast|multicast) cidr-only", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display only routes with non-natural netmasks\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, + bgp_show_type_cidr_only); + + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, + bgp_show_type_cidr_only); +} + +DEFUN (show_ip_bgp_community_all, + show_ip_bgp_community_all_cmd, + "show ip bgp community", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n") +{ + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, + bgp_show_type_community_all); +} + +DEFUN (show_ip_bgp_ipv4_community_all, + show_ip_bgp_ipv4_community_all_cmd, + "show ip bgp ipv4 (unicast|multicast) community", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, + bgp_show_type_community_all); + + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, + bgp_show_type_community_all); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_community_all, + show_bgp_community_all_cmd, + "show bgp community", + SHOW_STR + BGP_STR + "Display routes matching the communities\n") +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, + bgp_show_type_community_all); +} + +ALIAS (show_bgp_community_all, + show_bgp_ipv6_community_all_cmd, + "show bgp ipv6 community", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n") + +/* old command */ +DEFUN (show_ipv6_bgp_community_all, + show_ipv6_bgp_community_all_cmd, + "show ipv6 bgp community", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n") +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, + bgp_show_type_community_all); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_community_all, + show_ipv6_mbgp_community_all_cmd, + "show ipv6 mbgp community", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n") +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, + bgp_show_type_community_all); +} +#endif /* HAVE_IPV6 */ + +int +bgp_show_community (struct vty *vty, int argc, char **argv, int exact, + u_int16_t afi, u_char safi) +{ + struct community *com; + struct buffer *b; + int i; + char *str; + int first = 0; + + b = buffer_new (1024); + for (i = 0; i < argc; i++) + { + if (first) + buffer_putc (b, ' '); + else + { + if ((strcmp (argv[i], "unicast") == 0) || (strcmp (argv[i], "multicast") == 0)) + continue; + first = 1; + } + + buffer_putstr (b, argv[i]); + } + buffer_putc (b, '\0'); + + str = buffer_getstr (b); + buffer_free (b); + + com = community_str2com (str); + free (str); + if (! com) + { + vty_out (vty, "%% Community malformed: %s", VTY_NEWLINE); + return CMD_WARNING; + } + + vty->output_arg = com; + + if (exact) + return bgp_show (vty, NULL, afi, safi, bgp_show_type_community_exact); + + return bgp_show (vty, NULL, afi, safi, bgp_show_type_community); +} + +DEFUN (show_ip_bgp_community, + show_ip_bgp_community_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") +{ + return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_UNICAST); +} + +ALIAS (show_ip_bgp_community, + show_ip_bgp_community2_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_ip_bgp_community, + show_ip_bgp_community3_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_ip_bgp_community, + show_ip_bgp_community4_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFUN (show_ip_bgp_ipv4_community, + show_ip_bgp_ipv4_community_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_MULTICAST); + + return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_UNICAST); +} + +ALIAS (show_ip_bgp_ipv4_community, + show_ip_bgp_ipv4_community2_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_ip_bgp_ipv4_community, + show_ip_bgp_ipv4_community3_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_ip_bgp_ipv4_community, + show_ip_bgp_ipv4_community4_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFUN (show_ip_bgp_community_exact, + show_ip_bgp_community_exact_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") +{ + return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_UNICAST); +} + +ALIAS (show_ip_bgp_community_exact, + show_ip_bgp_community2_exact_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +ALIAS (show_ip_bgp_community_exact, + show_ip_bgp_community3_exact_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +ALIAS (show_ip_bgp_community_exact, + show_ip_bgp_community4_exact_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFUN (show_ip_bgp_ipv4_community_exact, + show_ip_bgp_ipv4_community_exact_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_MULTICAST); + + return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_UNICAST); +} + +ALIAS (show_ip_bgp_ipv4_community_exact, + show_ip_bgp_ipv4_community2_exact_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +ALIAS (show_ip_bgp_ipv4_community_exact, + show_ip_bgp_ipv4_community3_exact_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +ALIAS (show_ip_bgp_ipv4_community_exact, + show_ip_bgp_ipv4_community4_exact_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_community, + show_bgp_community_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") +{ + return bgp_show_community (vty, argc, argv, 0, AFI_IP6, SAFI_UNICAST); +} + +ALIAS (show_bgp_community, + show_bgp_ipv6_community_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_community, + show_bgp_community2_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_community, + show_bgp_ipv6_community2_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_community, + show_bgp_community3_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_community, + show_bgp_ipv6_community3_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_community, + show_bgp_community4_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_community, + show_bgp_ipv6_community4_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +/* old command */ +DEFUN (show_ipv6_bgp_community, + show_ipv6_bgp_community_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") +{ + return bgp_show_community (vty, argc, argv, 0, AFI_IP6, SAFI_UNICAST); +} + +/* old command */ +ALIAS (show_ipv6_bgp_community, + show_ipv6_bgp_community2_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +/* old command */ +ALIAS (show_ipv6_bgp_community, + show_ipv6_bgp_community3_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +/* old command */ +ALIAS (show_ipv6_bgp_community, + show_ipv6_bgp_community4_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFUN (show_bgp_community_exact, + show_bgp_community_exact_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") +{ + return bgp_show_community (vty, argc, argv, 1, AFI_IP6, SAFI_UNICAST); +} + +ALIAS (show_bgp_community_exact, + show_bgp_ipv6_community_exact_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +ALIAS (show_bgp_community_exact, + show_bgp_community2_exact_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +ALIAS (show_bgp_community_exact, + show_bgp_ipv6_community2_exact_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +ALIAS (show_bgp_community_exact, + show_bgp_community3_exact_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +ALIAS (show_bgp_community_exact, + show_bgp_ipv6_community3_exact_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +ALIAS (show_bgp_community_exact, + show_bgp_community4_exact_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +ALIAS (show_bgp_community_exact, + show_bgp_ipv6_community4_exact_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +/* old command */ +DEFUN (show_ipv6_bgp_community_exact, + show_ipv6_bgp_community_exact_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") +{ + return bgp_show_community (vty, argc, argv, 1, AFI_IP6, SAFI_UNICAST); +} + +/* old command */ +ALIAS (show_ipv6_bgp_community_exact, + show_ipv6_bgp_community2_exact_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +/* old command */ +ALIAS (show_ipv6_bgp_community_exact, + show_ipv6_bgp_community3_exact_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +/* old command */ +ALIAS (show_ipv6_bgp_community_exact, + show_ipv6_bgp_community4_exact_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +/* old command */ +DEFUN (show_ipv6_mbgp_community, + show_ipv6_mbgp_community_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") +{ + return bgp_show_community (vty, argc, argv, 0, AFI_IP6, SAFI_MULTICAST); +} + +/* old command */ +ALIAS (show_ipv6_mbgp_community, + show_ipv6_mbgp_community2_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +/* old command */ +ALIAS (show_ipv6_mbgp_community, + show_ipv6_mbgp_community3_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +/* old command */ +ALIAS (show_ipv6_mbgp_community, + show_ipv6_mbgp_community4_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +/* old command */ +DEFUN (show_ipv6_mbgp_community_exact, + show_ipv6_mbgp_community_exact_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") +{ + return bgp_show_community (vty, argc, argv, 1, AFI_IP6, SAFI_MULTICAST); +} + +/* old command */ +ALIAS (show_ipv6_mbgp_community_exact, + show_ipv6_mbgp_community2_exact_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +/* old command */ +ALIAS (show_ipv6_mbgp_community_exact, + show_ipv6_mbgp_community3_exact_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +/* old command */ +ALIAS (show_ipv6_mbgp_community_exact, + show_ipv6_mbgp_community4_exact_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") +#endif /* HAVE_IPV6 */ + +int +bgp_show_community_list (struct vty *vty, char *com, int exact, + u_int16_t afi, u_char safi) +{ + struct community_list *list; + + list = community_list_lookup (bgp_clist, com, COMMUNITY_LIST_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 */ + +void +bgp_show_prefix_longer_clean (struct vty *vty) +{ + struct prefix *p; + + p = vty->output_arg; + prefix_free (p); +} + +int +bgp_show_prefix_longer (struct vty *vty, char *prefix, afi_t afi, + safi_t safi, enum bgp_show_type type) +{ + int ret; + struct prefix *p; + + p = prefix_new(); + + ret = str2prefix (prefix, p); + if (! ret) + { + vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + vty->output_arg = p; + vty->output_clean = bgp_show_prefix_longer_clean; + + return bgp_show (vty, NULL, afi, safi, type); +} + +DEFUN (show_ip_bgp_prefix_longer, + show_ip_bgp_prefix_longer_cmd, + "show ip bgp A.B.C.D/M longer-prefixes", + SHOW_STR + IP_STR + BGP_STR + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_prefix_longer); +} + +DEFUN (show_ip_bgp_flap_prefix_longer, + show_ip_bgp_flap_prefix_longer_cmd, + "show ip bgp flap-statistics A.B.C.D/M longer-prefixes", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_prefix_longer); +} + +DEFUN (show_ip_bgp_ipv4_prefix_longer, + show_ip_bgp_ipv4_prefix_longer_cmd, + "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_prefix_longer (vty, argv[1], AFI_IP, SAFI_MULTICAST, + bgp_show_type_prefix_longer); + + return bgp_show_prefix_longer (vty, argv[1], AFI_IP, SAFI_UNICAST, + bgp_show_type_prefix_longer); +} + +DEFUN (show_ip_bgp_flap_address, + show_ip_bgp_flap_address_cmd, + "show ip bgp flap-statistics A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "Network in the BGP routing table to display\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_address); +} + +DEFUN (show_ip_bgp_flap_prefix, + show_ip_bgp_flap_prefix_cmd, + "show ip bgp flap-statistics A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_prefix); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_prefix_longer, + show_bgp_prefix_longer_cmd, + "show bgp X:X::X:X/M longer-prefixes", + SHOW_STR + BGP_STR + "IPv6 prefix /\n" + "Display route and more specific routes\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_prefix_longer); +} + +ALIAS (show_bgp_prefix_longer, + show_bgp_ipv6_prefix_longer_cmd, + "show bgp ipv6 X:X::X:X/M longer-prefixes", + SHOW_STR + BGP_STR + "Address family\n" + "IPv6 prefix /\n" + "Display route and more specific routes\n") + +/* old command */ +DEFUN (show_ipv6_bgp_prefix_longer, + show_ipv6_bgp_prefix_longer_cmd, + "show ipv6 bgp X:X::X:X/M longer-prefixes", + SHOW_STR + IPV6_STR + BGP_STR + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Display route and more specific routes\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_prefix_longer); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_prefix_longer, + show_ipv6_mbgp_prefix_longer_cmd, + "show ipv6 mbgp X:X::X:X/M longer-prefixes", + SHOW_STR + IPV6_STR + MBGP_STR + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Display route and more specific routes\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_MULTICAST, + bgp_show_type_prefix_longer); +} +#endif /* HAVE_IPV6 */ + +void +show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, + int in) +{ + struct bgp_table *table; + struct bgp_adj_in *ain; + struct bgp_adj_out *adj; + unsigned long output_count; + struct bgp_node *rn; + int header1 = 1; + struct bgp *bgp; + int header2 = 1; + + bgp = bgp_get_default (); + + if (! bgp) + return; + + table = bgp->rib[afi][safi]; + + output_count = 0; + + if (! in && CHECK_FLAG (peer->af_sflags[afi][safi], + PEER_STATUS_DEFAULT_ORIGINATE)) + { + vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, "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 */ + +DEFUN (show_ip_bgp_neighbor_received_routes, + show_ip_bgp_neighbor_received_routes_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") +{ + return peer_adj_routes (vty, argv[0], AFI_IP, SAFI_UNICAST, 1); +} + +DEFUN (show_ip_bgp_ipv4_neighbor_received_routes, + show_ip_bgp_ipv4_neighbor_received_routes_cmd, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return peer_adj_routes (vty, argv[1], AFI_IP, SAFI_MULTICAST, 1); + + return peer_adj_routes (vty, argv[1], AFI_IP, SAFI_UNICAST, 1); +} + +DEFUN (show_ip_bgp_neighbor_received_prefix_filter, + show_ip_bgp_neighbor_received_prefix_filter_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display information received from a BGP neighbor\n" + "Display the prefixlist filter\n") +{ + char name[BUFSIZ]; + union sockunion *su; + struct peer *peer; + int count; + + su = sockunion_str2su (argv[0]); + if (su == NULL) + return CMD_WARNING; + + peer = peer_lookup (NULL, su); + if (! peer) + return CMD_WARNING; + + sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_UNICAST); + count = prefix_bgp_show_prefix_list (NULL, AFI_IP, name); + if (count) + { + vty_out (vty, "Address family: IPv4 Unicast%s", VTY_NEWLINE); + prefix_bgp_show_prefix_list (vty, AFI_IP, name); + } + + return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_ipv4_neighbor_received_prefix_filter, + show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display information received from a BGP neighbor\n" + "Display the prefixlist filter\n") +{ + char name[BUFSIZ]; + union sockunion *su; + struct peer *peer; + int count; + + su = sockunion_str2su (argv[1]); + if (su == NULL) + return CMD_WARNING; + + peer = peer_lookup (NULL, su); + if (! peer) + return CMD_WARNING; + + if (strncmp (argv[0], "m", 1) == 0) + { + sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_MULTICAST); + count = prefix_bgp_show_prefix_list (NULL, AFI_IP, name); + if (count) + { + vty_out (vty, "Address family: IPv4 Multicast%s", VTY_NEWLINE); + prefix_bgp_show_prefix_list (vty, AFI_IP, name); + } + } + else + { + sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_UNICAST); + count = prefix_bgp_show_prefix_list (NULL, AFI_IP, name); + if (count) + { + vty_out (vty, "Address family: IPv4 Unicast%s", VTY_NEWLINE); + prefix_bgp_show_prefix_list (vty, AFI_IP, name); + } + } + + return CMD_SUCCESS; +} + + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_neighbor_received_routes, + show_bgp_neighbor_received_routes_cmd, + "show bgp neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") +{ + return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_UNICAST, 1); +} + +ALIAS (show_bgp_neighbor_received_routes, + show_bgp_ipv6_neighbor_received_routes_cmd, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + BGP_STR + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") + +DEFUN (show_bgp_neighbor_received_prefix_filter, + show_bgp_neighbor_received_prefix_filter_cmd, + "show bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + SHOW_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display information received from a BGP neighbor\n" + "Display the prefixlist filter\n") +{ + char name[BUFSIZ]; + union sockunion *su; + struct peer *peer; + int count; + + su = sockunion_str2su (argv[0]); + if (su == NULL) + return CMD_WARNING; + + peer = peer_lookup (NULL, su); + if (! peer) + return CMD_WARNING; + + sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, SAFI_UNICAST); + count = prefix_bgp_show_prefix_list (NULL, AFI_IP6, name); + if (count) + { + vty_out (vty, "Address family: IPv6 Unicast%s", VTY_NEWLINE); + prefix_bgp_show_prefix_list (vty, AFI_IP6, name); + } + + return CMD_SUCCESS; +} + +ALIAS (show_bgp_neighbor_received_prefix_filter, + show_bgp_ipv6_neighbor_received_prefix_filter_cmd, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + SHOW_STR + BGP_STR + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display information received from a BGP neighbor\n" + "Display the prefixlist filter\n") + +/* old command */ +DEFUN (ipv6_bgp_neighbor_received_routes, + ipv6_bgp_neighbor_received_routes_cmd, + "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + IPV6_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") +{ + return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_UNICAST, 1); +} + +/* old command */ +DEFUN (ipv6_mbgp_neighbor_received_routes, + ipv6_mbgp_neighbor_received_routes_cmd, + "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + IPV6_STR + MBGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") +{ + return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_MULTICAST, 1); +} +#endif /* HAVE_IPV6 */ + +void +bgp_show_neighbor_route_clean (struct vty *vty) +{ + union sockunion *su; + + su = vty->output_arg; + XFREE (MTYPE_SOCKUNION, su); +} + +int +bgp_show_neighbor_route (struct vty *vty, char *ip_str, afi_t afi, + safi_t safi, enum bgp_show_type type) +{ + union sockunion *su; + struct peer *peer; + + su = sockunion_str2su (ip_str); + if (su == NULL) + { + vty_out (vty, "Malformed address: %s%s", ip_str, VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, su); + if (! peer || ! peer->afc[afi][safi]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + XFREE (MTYPE_SOCKUNION, su); + return CMD_WARNING; + } + + vty->output_arg = su; + vty->output_clean = bgp_show_neighbor_route_clean; + + return bgp_show (vty, NULL, afi, safi, type); +} + +DEFUN (show_ip_bgp_neighbor_routes, + show_ip_bgp_neighbor_routes_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + return bgp_show_neighbor_route (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_neighbor); +} + +DEFUN (show_ip_bgp_neighbor_flap, + show_ip_bgp_neighbor_flap_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display flap statistics of the routes learned from neighbor\n") +{ + return bgp_show_neighbor_route (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_neighbor); +} + +DEFUN (show_ip_bgp_neighbor_damp, + show_ip_bgp_neighbor_damp_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) dampened-routes", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the dampened routes received from neighbor\n") +{ + return bgp_show_neighbor_route (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_damp_neighbor); +} + +DEFUN (show_ip_bgp_ipv4_neighbor_routes, + show_ip_bgp_ipv4_neighbor_routes_cmd, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_neighbor_route (vty, argv[1], AFI_IP, SAFI_MULTICAST, + bgp_show_type_neighbor); + + return bgp_show_neighbor_route (vty, argv[1], AFI_IP, SAFI_UNICAST, + bgp_show_type_neighbor); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_neighbor_routes, + show_bgp_neighbor_routes_cmd, + "show bgp neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + return bgp_show_neighbor_route (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_neighbor); +} + +ALIAS (show_bgp_neighbor_routes, + show_bgp_ipv6_neighbor_routes_cmd, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + BGP_STR + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") + +/* old command */ +DEFUN (ipv6_bgp_neighbor_routes, + ipv6_bgp_neighbor_routes_cmd, + "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + IPV6_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + return bgp_show_neighbor_route (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_neighbor); +} + +/* old command */ +DEFUN (ipv6_mbgp_neighbor_routes, + ipv6_mbgp_neighbor_routes_cmd, + "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + IPV6_STR + MBGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + return bgp_show_neighbor_route (vty, argv[0], AFI_IP6, SAFI_MULTICAST, + bgp_show_type_neighbor); +} +#endif /* HAVE_IPV6 */ + +struct bgp_table *bgp_distance_table; + +struct bgp_distance +{ + /* Distance value for the IP source prefix. */ + u_char distance; + + /* Name of the access-list to be matched. */ + char *access_list; +}; + +struct bgp_distance * +bgp_distance_new () +{ + struct bgp_distance *new; + new = XMALLOC (MTYPE_BGP_DISTANCE, sizeof (struct bgp_distance)); + memset (new, 0, sizeof (struct bgp_distance)); + return new; +} + +void +bgp_distance_free (struct bgp_distance *bdistance) +{ + XFREE (MTYPE_BGP_DISTANCE, bdistance); +} + +int +bgp_distance_set (struct vty *vty, char *distance_str, char *ip_str, + char *access_list_str) +{ + int ret; + struct prefix_ipv4 p; + u_char distance; + struct bgp_node *rn; + struct bgp_distance *bdistance; + + ret = str2prefix_ipv4 (ip_str, &p); + if (ret == 0) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + distance = atoi (distance_str); + + /* Get BGP distance node. */ + rn = bgp_node_get (bgp_distance_table, (struct prefix *) &p); + if (rn->info) + { + bdistance = rn->info; + bgp_unlock_node (rn); + } + else + { + bdistance = bgp_distance_new (); + rn->info = bdistance; + } + + /* Set distance value. */ + bdistance->distance = distance; + + /* Reset access-list configuration. */ + if (bdistance->access_list) + { + free (bdistance->access_list); + bdistance->access_list = NULL; + } + if (access_list_str) + bdistance->access_list = strdup (access_list_str); + + return CMD_SUCCESS; +} + +int +bgp_distance_unset (struct vty *vty, char *distance_str, char *ip_str, + char *access_list_str) +{ + int ret; + struct prefix_ipv4 p; + u_char distance; + struct bgp_node *rn; + struct bgp_distance *bdistance; + + ret = str2prefix_ipv4 (ip_str, &p); + if (ret == 0) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + distance = atoi (distance_str); + + rn = bgp_node_lookup (bgp_distance_table, (struct prefix *)&p); + if (! rn) + { + vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bdistance = rn->info; + + if (bdistance->access_list) + free (bdistance->access_list); + bgp_distance_free (bdistance); + + rn->info = NULL; + bgp_unlock_node (rn); + bgp_unlock_node (rn); + + return CMD_SUCCESS; +} + +void +bgp_distance_reset () +{ + struct bgp_node *rn; + struct bgp_distance *bdistance; + + for (rn = bgp_table_top (bgp_distance_table); rn; rn = bgp_route_next (rn)) + if ((bdistance = rn->info) != NULL) + { + if (bdistance->access_list) + free (bdistance->access_list); + bgp_distance_free (bdistance); + rn->info = NULL; + bgp_unlock_node (rn); + } +} + +/* Apply BGP information to distance method. */ +u_char +bgp_distance_apply (struct prefix *p, struct bgp_info *rinfo, struct bgp *bgp) +{ + struct bgp_node *rn; + struct prefix_ipv4 q; + struct peer *peer; + struct bgp_distance *bdistance; + struct access_list *alist; + struct bgp_static *bgp_static; + + if (! bgp) + return 0; + + if (p->family != AF_INET) + return 0; + + peer = rinfo->peer; + + if (peer->su.sa.sa_family != AF_INET) + return 0; + + memset (&q, 0, sizeof (struct prefix_ipv4)); + q.family = AF_INET; + q.prefix = peer->su.sin.sin_addr; + q.prefixlen = IPV4_MAX_BITLEN; + + /* Check source address. */ + rn = bgp_node_match (bgp_distance_table, (struct prefix *) &q); + if (rn) + { + bdistance = rn->info; + bgp_unlock_node (rn); + + if (bdistance->access_list) + { + alist = access_list_lookup (AFI_IP, bdistance->access_list); + if (alist && access_list_apply (alist, p) == FILTER_PERMIT) + return bdistance->distance; + } + else + return bdistance->distance; + } + + /* Backdoor check. */ + rn = bgp_node_lookup (bgp->route[AFI_IP][SAFI_UNICAST], p); + if (rn) + { + bgp_static = rn->info; + bgp_unlock_node (rn); + + if (bgp_static->backdoor) + { + if (bgp->distance_local) + return bgp->distance_local; + else + return ZEBRA_IBGP_DISTANCE_DEFAULT; + } + } + + if (peer_sort (peer) == BGP_PEER_EBGP) + { + if (bgp->distance_ebgp) + return bgp->distance_ebgp; + return ZEBRA_EBGP_DISTANCE_DEFAULT; + } + else + { + if (bgp->distance_ibgp) + return bgp->distance_ibgp; + return ZEBRA_IBGP_DISTANCE_DEFAULT; + } +} + +DEFUN (bgp_distance, + bgp_distance_cmd, + "distance bgp <1-255> <1-255> <1-255>", + "Define an administrative distance\n" + "BGP distance\n" + "Distance for routes external to the AS\n" + "Distance for routes internal to the AS\n" + "Distance for local routes\n") +{ + struct bgp *bgp; + + bgp = vty->index; + + bgp->distance_ebgp = atoi (argv[0]); + bgp->distance_ibgp = atoi (argv[1]); + bgp->distance_local = atoi (argv[2]); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_distance, + no_bgp_distance_cmd, + "no distance bgp <1-255> <1-255> <1-255>", + NO_STR + "Define an administrative distance\n" + "BGP distance\n" + "Distance for routes external to the AS\n" + "Distance for routes internal to the AS\n" + "Distance for local routes\n") +{ + struct bgp *bgp; + + bgp = vty->index; + + bgp->distance_ebgp= 0; + bgp->distance_ibgp = 0; + bgp->distance_local = 0; + return CMD_SUCCESS; +} + +ALIAS (no_bgp_distance, + no_bgp_distance2_cmd, + "no distance bgp", + NO_STR + "Define an administrative distance\n" + "BGP distance\n") + +DEFUN (bgp_distance_source, + bgp_distance_source_cmd, + "distance <1-255> A.B.C.D/M", + "Define an administrative distance\n" + "Administrative distance\n" + "IP source prefix\n") +{ + bgp_distance_set (vty, argv[0], argv[1], NULL); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_distance_source, + no_bgp_distance_source_cmd, + "no distance <1-255> A.B.C.D/M", + NO_STR + "Define an administrative distance\n" + "Administrative distance\n" + "IP source prefix\n") +{ + bgp_distance_unset (vty, argv[0], argv[1], NULL); + return CMD_SUCCESS; +} + +DEFUN (bgp_distance_source_access_list, + bgp_distance_source_access_list_cmd, + "distance <1-255> A.B.C.D/M WORD", + "Define an administrative distance\n" + "Administrative distance\n" + "IP source prefix\n" + "Access list name\n") +{ + bgp_distance_set (vty, argv[0], argv[1], argv[2]); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_distance_source_access_list, + no_bgp_distance_source_access_list_cmd, + "no distance <1-255> A.B.C.D/M WORD", + NO_STR + "Define an administrative distance\n" + "Administrative distance\n" + "IP source prefix\n" + "Access list name\n") +{ + bgp_distance_unset (vty, argv[0], argv[1], argv[2]); + return CMD_SUCCESS; +} + +DEFUN (bgp_damp_set, + bgp_damp_set_cmd, + "bgp dampening <1-45> <1-20000> <1-20000> <1-255>", + "BGP Specific commands\n" + "Enable route-flap dampening\n" + "Half-life time for the penalty\n" + "Value to start reusing a route\n" + "Value to start suppressing a route\n" + "Maximum duration to suppress a stable route\n") +{ + struct bgp *bgp; + int half = DEFAULT_HALF_LIFE * 60; + int reuse = DEFAULT_REUSE; + int suppress = DEFAULT_SUPPRESS; + int max = 4 * half; + + if (argc == 4) + { + half = atoi (argv[0]) * 60; + reuse = atoi (argv[1]); + suppress = atoi (argv[2]); + max = atoi (argv[3]) * 60; + } + else if (argc == 1) + { + half = atoi (argv[0]) * 60; + max = 4 * half; + } + + bgp = vty->index; + return bgp_damp_enable (bgp, bgp_node_afi (vty), bgp_node_safi (vty), + half, reuse, suppress, max); +} + +ALIAS (bgp_damp_set, + bgp_damp_set2_cmd, + "bgp dampening <1-45>", + "BGP Specific commands\n" + "Enable route-flap dampening\n" + "Half-life time for the penalty\n") + +ALIAS (bgp_damp_set, + bgp_damp_set3_cmd, + "bgp dampening", + "BGP Specific commands\n" + "Enable route-flap dampening\n") + +DEFUN (bgp_damp_unset, + bgp_damp_unset_cmd, + "no bgp dampening", + NO_STR + "BGP Specific commands\n" + "Enable route-flap dampening\n") +{ + struct bgp *bgp; + + bgp = vty->index; + return bgp_damp_disable (bgp, bgp_node_afi (vty), bgp_node_safi (vty)); +} + +ALIAS (bgp_damp_unset, + bgp_damp_unset2_cmd, + "no bgp dampening <1-45> <1-20000> <1-20000> <1-255>", + NO_STR + "BGP Specific commands\n" + "Enable route-flap dampening\n" + "Half-life time for the penalty\n" + "Value to start reusing a route\n" + "Value to start suppressing a route\n" + "Maximum duration to suppress a stable route\n") + +DEFUN (show_ip_bgp_dampened_paths, + show_ip_bgp_dampened_paths_cmd, + "show ip bgp dampened-paths", + SHOW_STR + IP_STR + BGP_STR + "Display paths suppressed due to dampening\n") +{ + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_dampend_paths); +} + +DEFUN (show_ip_bgp_flap_statistics, + show_ip_bgp_flap_statistics_cmd, + "show ip bgp flap-statistics", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n") +{ + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_flap_statistics); +} + +/* Display specified route of BGP table. */ +int +bgp_clear_damp_route (struct vty *vty, char *view_name, char *ip_str, + afi_t afi, safi_t safi, struct prefix_rd *prd, + int prefix_check) +{ + int ret; + struct prefix match; + struct bgp_node *rn; + struct bgp_node *rm; + struct bgp_info *ri; + struct bgp_info *ri_temp; + struct bgp *bgp; + struct bgp_table *table; + + /* BGP structure lookup. */ + if (view_name) + { + bgp = bgp_lookup_by_name (view_name); + if (bgp == NULL) + { + vty_out (vty, "%% Can't find BGP view %s%s", view_name, VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "%% No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + /* Check IP address argument. */ + ret = str2prefix (ip_str, &match); + if (! ret) + { + vty_out (vty, "%% address is malformed%s", VTY_NEWLINE); + return CMD_WARNING; + } + + match.family = afi2family (afi); + + if (safi == SAFI_MPLS_VPN) + { + for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) + { + if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) + continue; + + if ((table = rn->info) != NULL) + if ((rm = bgp_node_match (table, &match)) != NULL) + if (! prefix_check || rm->p.prefixlen == match.prefixlen) + { + ri = rm->info; + while (ri) + { + if (ri->damp_info) + { + ri_temp = ri->next; + bgp_damp_info_free (ri->damp_info, 1); + ri = ri_temp; + } + else + ri = ri->next; + } + } + } + } + else + { + if ((rn = bgp_node_match (bgp->rib[afi][safi], &match)) != NULL) + if (! prefix_check || rn->p.prefixlen == match.prefixlen) + { + ri = rn->info; + while (ri) + { + if (ri->damp_info) + { + ri_temp = ri->next; + bgp_damp_info_free (ri->damp_info, 1); + ri = ri_temp; + } + else + ri = ri->next; + } + } + } + + return CMD_SUCCESS; +} + +DEFUN (clear_ip_bgp_dampening, + clear_ip_bgp_dampening_cmd, + "clear ip bgp dampening", + CLEAR_STR + IP_STR + BGP_STR + "Clear route flap dampening information\n") +{ + bgp_damp_info_clean (); + return CMD_SUCCESS; +} + +DEFUN (clear_ip_bgp_dampening_prefix, + clear_ip_bgp_dampening_prefix_cmd, + "clear ip bgp dampening A.B.C.D/M", + CLEAR_STR + IP_STR + BGP_STR + "Clear route flap dampening information\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_clear_damp_route (vty, NULL, argv[0], AFI_IP, + SAFI_UNICAST, NULL, 1); +} + +DEFUN (clear_ip_bgp_dampening_address, + clear_ip_bgp_dampening_address_cmd, + "clear ip bgp dampening A.B.C.D", + CLEAR_STR + IP_STR + BGP_STR + "Clear route flap dampening information\n" + "Network to clear damping information\n") +{ + return bgp_clear_damp_route (vty, NULL, argv[0], AFI_IP, + SAFI_UNICAST, NULL, 0); +} + +DEFUN (clear_ip_bgp_dampening_address_mask, + clear_ip_bgp_dampening_address_mask_cmd, + "clear ip bgp dampening A.B.C.D A.B.C.D", + CLEAR_STR + IP_STR + BGP_STR + "Clear route flap dampening information\n" + "Network to clear damping information\n" + "Network mask\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_clear_damp_route (vty, NULL, prefix_str, AFI_IP, + SAFI_UNICAST, NULL, 0); +} + +int +bgp_config_write_network_vpnv4 (struct vty *vty, struct bgp *bgp, + afi_t afi, safi_t safi, int *write) +{ + struct bgp_node *prn; + struct bgp_node *rn; + struct bgp_table *table; + struct prefix *p; + struct prefix_rd *prd; + struct bgp_static *bgp_static; + u_int32_t label; + char buf[SU_ADDRSTRLEN]; + char rdbuf[RD_ADDRSTRLEN]; + + /* Network configuration. */ + for (prn = bgp_table_top (bgp->route[afi][safi]); prn; prn = bgp_route_next (prn)) + if ((table = prn->info) != NULL) + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + if ((bgp_static = rn->info) != NULL) + { + p = &rn->p; + prd = (struct prefix_rd *) &prn->p; + + /* "address-family" display. */ + bgp_config_write_family_header (vty, afi, safi, write); + + /* "network" configuration display. */ + prefix_rd2str (prd, rdbuf, RD_ADDRSTRLEN); + label = decode_label (bgp_static->tag); + + vty_out (vty, " network %s/%d rd %s tag %d", + inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen, + rdbuf, label); + vty_out (vty, "%s", VTY_NEWLINE); + } + return 0; +} + +/* Configuration of static route announcement and aggregate + information. */ +int +bgp_config_write_network (struct vty *vty, struct bgp *bgp, + afi_t afi, safi_t safi, int *write) +{ + struct bgp_node *rn; + struct prefix *p; + struct bgp_static *bgp_static; + struct bgp_aggregate *bgp_aggregate; + char buf[SU_ADDRSTRLEN]; + + if (afi == AFI_IP && safi == SAFI_MPLS_VPN) + return bgp_config_write_network_vpnv4 (vty, bgp, afi, safi, write); + + /* Network configuration. */ + for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) + if ((bgp_static = rn->info) != NULL) + { + p = &rn->p; + + /* "address-family" display. */ + bgp_config_write_family_header (vty, afi, safi, write); + + /* "network" configuration display. */ + if (bgp_option_check (BGP_OPT_CONFIG_CISCO) && afi == AFI_IP) + { + u_int32_t destination; + struct in_addr netmask; + + destination = ntohl (p->u.prefix4.s_addr); + masklen2ip (p->prefixlen, &netmask); + vty_out (vty, " network %s", + inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN)); + + if ((IN_CLASSC (destination) && p->prefixlen == 24) + || (IN_CLASSB (destination) && p->prefixlen == 16) + || (IN_CLASSA (destination) && p->prefixlen == 8) + || p->u.prefix4.s_addr == 0) + { + /* Natural mask is not display. */ + } + else + vty_out (vty, " mask %s", inet_ntoa (netmask)); + } + else + { + vty_out (vty, " network %s/%d", + inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + } + + if (bgp_static->rmap.name) + vty_out (vty, " route-map %s", bgp_static->rmap.name); + else if (bgp_static->backdoor) + vty_out (vty, " backdoor"); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Aggregate-address configuration. */ + for (rn = bgp_table_top (bgp->aggregate[afi][safi]); rn; rn = bgp_route_next (rn)) + if ((bgp_aggregate = rn->info) != NULL) + { + p = &rn->p; + + /* "address-family" display. */ + bgp_config_write_family_header (vty, afi, safi, write); + + if (bgp_option_check (BGP_OPT_CONFIG_CISCO) && afi == AFI_IP) + { + struct in_addr netmask; + + masklen2ip (p->prefixlen, &netmask); + vty_out (vty, " aggregate-address %s %s", + inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + inet_ntoa (netmask)); + } + else + { + vty_out (vty, " aggregate-address %s/%d", + inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + } + + if (bgp_aggregate->as_set) + vty_out (vty, " as-set"); + + if (bgp_aggregate->summary_only) + vty_out (vty, " summary-only"); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + return 0; +} + +int +bgp_config_write_distance (struct vty *vty, struct bgp *bgp) +{ + struct bgp_node *rn; + struct bgp_distance *bdistance; + + /* Distance configuration. */ + if (bgp->distance_ebgp + && bgp->distance_ibgp + && bgp->distance_local + && (bgp->distance_ebgp != ZEBRA_EBGP_DISTANCE_DEFAULT + || bgp->distance_ibgp != ZEBRA_IBGP_DISTANCE_DEFAULT + || bgp->distance_local != ZEBRA_IBGP_DISTANCE_DEFAULT)) + vty_out (vty, " distance bgp %d %d %d%s", + bgp->distance_ebgp, bgp->distance_ibgp, bgp->distance_local, + VTY_NEWLINE); + + for (rn = bgp_table_top (bgp_distance_table); rn; rn = bgp_route_next (rn)) + if ((bdistance = rn->info) != NULL) + { + vty_out (vty, " distance %d %s/%d %s%s", bdistance->distance, + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, + bdistance->access_list ? bdistance->access_list : "", + VTY_NEWLINE); + } + + return 0; +} + +/* Allocate routing table structure and install commands. */ +void +bgp_route_init () +{ + /* Init BGP distance table. */ + bgp_distance_table = bgp_table_init (); + + /* IPv4 BGP commands. */ + install_element (BGP_NODE, &bgp_network_cmd); + install_element (BGP_NODE, &bgp_network_mask_cmd); + install_element (BGP_NODE, &bgp_network_mask_natural_cmd); + install_element (BGP_NODE, &bgp_network_route_map_cmd); + install_element (BGP_NODE, &bgp_network_mask_route_map_cmd); + install_element (BGP_NODE, &bgp_network_mask_natural_route_map_cmd); + install_element (BGP_NODE, &bgp_network_backdoor_cmd); + install_element (BGP_NODE, &bgp_network_mask_backdoor_cmd); + install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_cmd); + install_element (BGP_NODE, &no_bgp_network_cmd); + install_element (BGP_NODE, &no_bgp_network_mask_cmd); + install_element (BGP_NODE, &no_bgp_network_mask_natural_cmd); + install_element (BGP_NODE, &no_bgp_network_route_map_cmd); + install_element (BGP_NODE, &no_bgp_network_mask_route_map_cmd); + install_element (BGP_NODE, &no_bgp_network_mask_natural_route_map_cmd); + install_element (BGP_NODE, &no_bgp_network_backdoor_cmd); + install_element (BGP_NODE, &no_bgp_network_mask_backdoor_cmd); + install_element (BGP_NODE, &no_bgp_network_mask_natural_backdoor_cmd); + + install_element (BGP_NODE, &aggregate_address_cmd); + install_element (BGP_NODE, &aggregate_address_mask_cmd); + install_element (BGP_NODE, &aggregate_address_summary_only_cmd); + install_element (BGP_NODE, &aggregate_address_mask_summary_only_cmd); + install_element (BGP_NODE, &aggregate_address_as_set_cmd); + install_element (BGP_NODE, &aggregate_address_mask_as_set_cmd); + install_element (BGP_NODE, &aggregate_address_as_set_summary_cmd); + install_element (BGP_NODE, &aggregate_address_mask_as_set_summary_cmd); + install_element (BGP_NODE, &aggregate_address_summary_as_set_cmd); + install_element (BGP_NODE, &aggregate_address_mask_summary_as_set_cmd); + install_element (BGP_NODE, &no_aggregate_address_cmd); + install_element (BGP_NODE, &no_aggregate_address_summary_only_cmd); + install_element (BGP_NODE, &no_aggregate_address_as_set_cmd); + install_element (BGP_NODE, &no_aggregate_address_as_set_summary_cmd); + install_element (BGP_NODE, &no_aggregate_address_summary_as_set_cmd); + install_element (BGP_NODE, &no_aggregate_address_mask_cmd); + install_element (BGP_NODE, &no_aggregate_address_mask_summary_only_cmd); + install_element (BGP_NODE, &no_aggregate_address_mask_as_set_cmd); + install_element (BGP_NODE, &no_aggregate_address_mask_as_set_summary_cmd); + install_element (BGP_NODE, &no_aggregate_address_mask_summary_as_set_cmd); + + /* IPv4 unicast configuration. */ + install_element (BGP_IPV4_NODE, &bgp_network_cmd); + install_element (BGP_IPV4_NODE, &bgp_network_mask_cmd); + install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_cmd); + install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd); + install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd); + install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_route_map_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_mask_route_map_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_route_map_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_mask_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_summary_only_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_only_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_as_set_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_as_set_summary_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_summary_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_summary_as_set_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_as_set_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_only_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_summary_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_as_set_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_only_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_summary_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_as_set_cmd); + + /* IPv4 multicast configuration. */ + install_element (BGP_IPV4M_NODE, &bgp_network_cmd); + install_element (BGP_IPV4M_NODE, &bgp_network_mask_cmd); + install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_cmd); + install_element (BGP_IPV4M_NODE, &bgp_network_route_map_cmd); + install_element (BGP_IPV4M_NODE, &bgp_network_mask_route_map_cmd); + install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_route_map_cmd); + install_element (BGP_IPV4M_NODE, &no_bgp_network_cmd); + install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_cmd); + install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_cmd); + install_element (BGP_IPV4M_NODE, &no_bgp_network_route_map_cmd); + install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_route_map_cmd); + install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_route_map_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_mask_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_summary_only_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_only_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_summary_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_summary_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_summary_as_set_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_as_set_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_only_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_summary_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_as_set_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_only_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_summary_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_as_set_cmd); + + install_element (VIEW_NODE, &show_ip_bgp_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd); + install_element (VIEW_NODE, &show_ip_bgp_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_view_cmd); + install_element (VIEW_NODE, &show_ip_bgp_view_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_view_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_regexp_cmd); + install_element (VIEW_NODE, &show_ip_bgp_prefix_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_filter_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_filter_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_route_map_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_map_cmd); + install_element (VIEW_NODE, &show_ip_bgp_cidr_only_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_cidr_only_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community_all_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_all_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community2_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community3_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community4_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community2_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community3_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community4_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community_list_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); + install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_address_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_cidr_only_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_regexp_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_filter_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_route_map_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd); + + install_element (ENABLE_NODE, &show_ip_bgp_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_view_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_view_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_view_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_regexp_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_regexp_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_filter_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_filter_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_route_map_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_map_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_cidr_only_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cidr_only_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community_all_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_all_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community2_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community3_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community4_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community2_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community3_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community4_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_address_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_cidr_only_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_regexp_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_filter_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_route_map_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd); + + /* BGP dampening clear commands */ + install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd); + +#ifdef HAVE_IPV6 + /* New config IPv6 BGP commands. */ + install_element (BGP_IPV6_NODE, &ipv6_bgp_network_cmd); + install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd); + install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd); + install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_route_map_cmd); + + install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_cmd); + install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_summary_only_cmd); + install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd); + install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_summary_only_cmd); + + /* Old config IPv6 BGP commands. */ + install_element (BGP_NODE, &old_ipv6_bgp_network_cmd); + install_element (BGP_NODE, &old_no_ipv6_bgp_network_cmd); + + install_element (BGP_NODE, &old_ipv6_aggregate_address_cmd); + install_element (BGP_NODE, &old_ipv6_aggregate_address_summary_only_cmd); + install_element (BGP_NODE, &old_no_ipv6_aggregate_address_cmd); + install_element (BGP_NODE, &old_no_ipv6_aggregate_address_summary_only_cmd); + + install_element (VIEW_NODE, &show_bgp_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_cmd); + install_element (VIEW_NODE, &show_bgp_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_route_cmd); + install_element (VIEW_NODE, &show_bgp_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_regexp_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_regexp_cmd); + install_element (VIEW_NODE, &show_bgp_prefix_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_prefix_list_cmd); + install_element (VIEW_NODE, &show_bgp_filter_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_filter_list_cmd); + install_element (VIEW_NODE, &show_bgp_route_map_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_route_map_cmd); + install_element (VIEW_NODE, &show_bgp_community_all_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community_all_cmd); + install_element (VIEW_NODE, &show_bgp_community_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community_cmd); + install_element (VIEW_NODE, &show_bgp_community2_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community2_cmd); + install_element (VIEW_NODE, &show_bgp_community3_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community3_cmd); + install_element (VIEW_NODE, &show_bgp_community4_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community4_cmd); + install_element (VIEW_NODE, &show_bgp_community_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community_exact_cmd); + install_element (VIEW_NODE, &show_bgp_community2_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community2_exact_cmd); + install_element (VIEW_NODE, &show_bgp_community3_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community3_exact_cmd); + install_element (VIEW_NODE, &show_bgp_community4_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community4_exact_cmd); + install_element (VIEW_NODE, &show_bgp_community_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd); + install_element (VIEW_NODE, &show_bgp_community_list_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd); + install_element (VIEW_NODE, &show_bgp_prefix_longer_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_prefix_longer_cmd); + install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &show_bgp_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &show_bgp_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_bgp_neighbor_received_prefix_filter_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd); + + install_element (ENABLE_NODE, &show_bgp_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_cmd); + install_element (ENABLE_NODE, &show_bgp_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_route_cmd); + install_element (ENABLE_NODE, &show_bgp_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_regexp_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_regexp_cmd); + install_element (ENABLE_NODE, &show_bgp_prefix_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_list_cmd); + install_element (ENABLE_NODE, &show_bgp_filter_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_filter_list_cmd); + install_element (ENABLE_NODE, &show_bgp_route_map_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_route_map_cmd); + install_element (ENABLE_NODE, &show_bgp_community_all_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_all_cmd); + install_element (ENABLE_NODE, &show_bgp_community_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_cmd); + install_element (ENABLE_NODE, &show_bgp_community2_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community2_cmd); + install_element (ENABLE_NODE, &show_bgp_community3_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community3_cmd); + install_element (ENABLE_NODE, &show_bgp_community4_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community4_cmd); + install_element (ENABLE_NODE, &show_bgp_community_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_community2_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community2_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_community3_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community3_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_community4_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community4_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_community_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_cmd); + install_element (ENABLE_NODE, &show_bgp_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_bgp_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &show_bgp_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_neighbor_received_prefix_filter_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd); + + /* old command */ + install_element (VIEW_NODE, &show_ipv6_bgp_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_route_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_prefix_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_regexp_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_prefix_list_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_filter_list_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community_all_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community2_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community3_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community4_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community2_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community3_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community4_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community_list_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community_list_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_route_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_regexp_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_list_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_filter_list_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_all_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community2_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community3_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community4_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community2_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community3_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community4_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd); + + /* old command */ + install_element (ENABLE_NODE, &show_ipv6_bgp_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_route_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_regexp_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_filter_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_all_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community2_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community3_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community4_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community2_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community3_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community4_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_route_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_regexp_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_filter_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_all_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_longer_cmd); + + /* old command */ + install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &ipv6_bgp_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd); + + /* old command */ + install_element (VIEW_NODE, &ipv6_bgp_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &ipv6_bgp_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &ipv6_mbgp_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_received_routes_cmd); + + /* old command */ + install_element (VIEW_NODE, &ipv6_bgp_neighbor_routes_cmd); + install_element (ENABLE_NODE, &ipv6_bgp_neighbor_routes_cmd); + install_element (VIEW_NODE, &ipv6_mbgp_neighbor_routes_cmd); + install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_routes_cmd); +#endif /* HAVE_IPV6 */ + + install_element (BGP_NODE, &bgp_distance_cmd); + install_element (BGP_NODE, &no_bgp_distance_cmd); + install_element (BGP_NODE, &no_bgp_distance2_cmd); + install_element (BGP_NODE, &bgp_distance_source_cmd); + install_element (BGP_NODE, &no_bgp_distance_source_cmd); + install_element (BGP_NODE, &bgp_distance_source_access_list_cmd); + install_element (BGP_NODE, &no_bgp_distance_source_access_list_cmd); + + install_element (BGP_NODE, &bgp_damp_set_cmd); + install_element (BGP_NODE, &bgp_damp_set2_cmd); + install_element (BGP_NODE, &bgp_damp_set3_cmd); + install_element (BGP_NODE, &bgp_damp_unset_cmd); + install_element (BGP_NODE, &bgp_damp_unset2_cmd); + install_element (BGP_IPV4_NODE, &bgp_damp_set_cmd); + install_element (BGP_IPV4_NODE, &bgp_damp_set2_cmd); + install_element (BGP_IPV4_NODE, &bgp_damp_set3_cmd); + install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd); + install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd); +} diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h new file mode 100644 index 00000000..a11aa143 --- /dev/null +++ b/bgpd/bgp_route.h @@ -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 index 00000000..498a6005 --- /dev/null +++ b/bgpd/bgp_routemap.c @@ -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 + +#include "prefix.h" +#include "filter.h" +#include "routemap.h" +#include "command.h" +#include "linklist.h" +#include "plist.h" +#include "memory.h" +#include "log.h" +#ifdef HAVE_GNU_REGEX +#include +#else +#include "regex-gnu.h" +#endif /* HAVE_GNU_REGEX */ +#include "buffer.h" +#include "sockunion.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_regex.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_clist.h" +#include "bgpd/bgp_filter.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_ecommunity.h" + +/* Memo of route-map commands. + +o Cisco route-map + + match as-path : Done + community : Done + interface : Not yet + ip address : Done + ip next-hop : Done + ip route-source : (This will not be implemented by bgpd) + ip prefix-list : Done + ipv6 address : Done + ipv6 next-hop : Done + ipv6 route-source: (This will not be implemented by bgpd) + ipv6 prefix-list : Done + length : (This will not be implemented by bgpd) + metric : Done + route-type : (This will not be implemented by bgpd) + tag : (This will not be implemented by bgpd) + + set as-path prepend : Done + as-path tag : Not yet + automatic-tag : (This will not be implemented by bgpd) + community : Done + comm-list : Not yet + dampning : Not yet + default : (This will not be implemented by bgpd) + interface : (This will not be implemented by bgpd) + ip default : (This will not be implemented by bgpd) + ip next-hop : Done + ip precedence : (This will not be implemented by bgpd) + ip tos : (This will not be implemented by bgpd) + level : (This will not be implemented by bgpd) + local-preference : Done + metric : Done + metric-type : Not yet + origin : Done + tag : (This will not be implemented by bgpd) + weight : Done + +o Local extention + + set ipv6 next-hop global: Done + set ipv6 next-hop local : Done + +*/ + +/* `match ip address IP_ACCESS_LIST' */ + +/* Match function should return 1 if match is success else return + zero. */ +route_map_result_t +route_match_ip_address (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; + /* struct prefix_ipv4 match; */ + + if (type == RMAP_BGP) + { + alist = access_list_lookup (AFI_IP, (char *) rule); + if (alist == NULL) + return RMAP_NOMATCH; + + return (access_list_apply (alist, prefix) == FILTER_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +/* Route map `ip address' match statement. `arg' should be + access-list name. */ +void * +route_match_ip_address_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_ip_address_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip address matching. */ +struct route_map_rule_cmd route_match_ip_address_cmd = +{ + "ip address", + route_match_ip_address, + route_match_ip_address_compile, + route_match_ip_address_free +}; + +/* `match ip next-hop IP_ADDRESS' */ + +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_ip_next_hop (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; + struct bgp_info *bgp_info; + struct prefix_ipv4 p; + + if (type == RMAP_BGP) + { + bgp_info = object; + p.family = AF_INET; + p.prefix = bgp_info->attr->nexthop; + p.prefixlen = IPV4_MAX_BITLEN; + + alist = access_list_lookup (AFI_IP, (char *) rule); + if (alist == NULL) + return RMAP_NOMATCH; + + return (access_list_apply (alist, &p) == FILTER_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +/* Route map `ip next-hop' match statement. `arg' is + access-list name. */ +void * +route_match_ip_next_hop_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_ip_next_hop_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip next-hop matching. */ +struct route_map_rule_cmd route_match_ip_next_hop_cmd = +{ + "ip next-hop", + route_match_ip_next_hop, + route_match_ip_next_hop_compile, + route_match_ip_next_hop_free +}; + +/* `match ip address prefix-list PREFIX_LIST' */ + +route_map_result_t +route_match_ip_address_prefix_list (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; + + if (type == RMAP_BGP) + { + plist = prefix_list_lookup (AFI_IP, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ip_address_prefix_list_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ip_address_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = +{ + "ip address prefix-list", + route_match_ip_address_prefix_list, + route_match_ip_address_prefix_list_compile, + route_match_ip_address_prefix_list_free +}; + +/* `match ip next-hop prefix-list PREFIX_LIST' */ + +route_map_result_t +route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; + struct bgp_info *bgp_info; + struct prefix_ipv4 p; + + if (type == RMAP_BGP) + { + bgp_info = object; + p.family = AF_INET; + p.prefix = bgp_info->attr->nexthop; + p.prefixlen = IPV4_MAX_BITLEN; + + plist = prefix_list_lookup (AFI_IP, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, &p) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ip_next_hop_prefix_list_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ip_next_hop_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = +{ + "ip next-hop prefix-list", + route_match_ip_next_hop_prefix_list, + route_match_ip_next_hop_prefix_list_compile, + route_match_ip_next_hop_prefix_list_free +}; + +/* `match metric METRIC' */ + +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_metric (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_int32_t *med; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + med = rule; + bgp_info = object; + + if (bgp_info->attr->med == *med) + return RMAP_MATCH; + else + return RMAP_NOMATCH; + } + return RMAP_NOMATCH; +} + +/* Route map `match metric' match statement. `arg' is MED value */ +void * +route_match_metric_compile (char *arg) +{ + u_int32_t *med; + char *endptr = NULL; + + med = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); + *med = strtoul (arg, &endptr, 10); + if (*endptr != '\0' || *med == ULONG_MAX) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, med); + return NULL; + } + return med; +} + +/* Free route map's compiled `match metric' value. */ +void +route_match_metric_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for metric matching. */ +struct route_map_rule_cmd route_match_metric_cmd = +{ + "metric", + route_match_metric, + route_match_metric_compile, + route_match_metric_free +}; + +/* `match as-path ASPATH' */ + +/* Match function for as-path match. I assume given object is */ +route_map_result_t +route_match_aspath (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + + struct as_list *as_list; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + as_list = as_list_lookup ((char *) rule); + if (as_list == NULL) + return RMAP_NOMATCH; + + bgp_info = object; + + /* Perform match. */ + return ((as_list_apply (as_list, bgp_info->attr->aspath) == AS_FILTER_DENY) ? RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +/* Compile function for as-path match. */ +void * +route_match_aspath_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Compile function for as-path match. */ +void +route_match_aspath_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for aspath matching. */ +struct route_map_rule_cmd route_match_aspath_cmd = +{ + "as-path", + route_match_aspath, + route_match_aspath_compile, + route_match_aspath_free +}; + +#if ROUTE_MATCH_ASPATH_OLD +/* `match as-path ASPATH' */ + +/* Match function for as-path match. I assume given object is */ +int +route_match_aspath (void *rule, struct prefix *prefix, void *object) +{ + regex_t *regex; + struct bgp_info *bgp_info; + + regex = rule; + bgp_info = object; + + /* Perform match. */ + return bgp_regexec (regex, bgp_info->attr->aspath); +} + +/* Compile function for as-path match. */ +void * +route_match_aspath_compile (char *arg) +{ + regex_t *regex; + + regex = bgp_regcomp (arg); + if (! regex) + return NULL; + + return regex; +} + +/* Compile function for as-path match. */ +void +route_match_aspath_free (void *rule) +{ + regex_t *regex = rule; + + bgp_regex_free (regex); +} + +/* Route map commands for aspath matching. */ +struct route_map_rule_cmd route_match_aspath_cmd = +{ + "as-path", + route_match_aspath, + route_match_aspath_compile, + route_match_aspath_free +}; +#endif /* ROUTE_MATCH_ASPATH_OLD */ + +/* `match community COMMUNIY' */ +struct rmap_community +{ + char *name; + int exact; +}; + +/* Match function for community match. */ +route_map_result_t +route_match_community (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct community_list *list; + struct bgp_info *bgp_info; + struct rmap_community *rcom; + + if (type == RMAP_BGP) + { + bgp_info = object; + rcom = rule; + + list = community_list_lookup (bgp_clist, rcom->name, COMMUNITY_LIST_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 +}; + +/* `match nlri` and `set nlri` are replaced by `address-family ipv4` + and `address-family vpnv4'. */ + +/* `match origin' */ +route_map_result_t +route_match_origin (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_char *origin; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + origin = rule; + bgp_info = object; + + if (bgp_info->attr->origin == *origin) + return RMAP_MATCH; + } + + return RMAP_NOMATCH; +} + +void * +route_match_origin_compile (char *arg) +{ + u_char *origin; + + origin = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_char)); + + if (strcmp (arg, "igp") == 0) + *origin = 0; + else if (strcmp (arg, "egp") == 0) + *origin = 1; + else + *origin = 2; + + return origin; +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_origin_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for origin matching. */ +struct route_map_rule_cmd route_match_origin_cmd = +{ + "origin", + route_match_origin, + route_match_origin_compile, + route_match_origin_free +}; +/* `set ip next-hop IP_ADDRESS' */ + +/* Set nexthop to object. ojbect must be pointer to struct attr. */ +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 +}; + +/* `set local-preference LOCAL_PREF' */ + +/* Set local preference. */ +route_map_result_t +route_set_local_pref (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_int32_t *local_pref; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + /* Fetch routemap's rule information. */ + local_pref = rule; + bgp_info = object; + + /* Set local preference value. */ + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); + bgp_info->attr->local_pref = *local_pref; + } + + return RMAP_OKAY; +} + +/* set local preference compilation. */ +void * +route_set_local_pref_compile (char *arg) +{ + u_int32_t *local_pref; + char *endptr = NULL; + + /* Local preference value shoud be integer. */ + if (! all_digit (arg)) + return NULL; + + local_pref = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); + *local_pref = strtoul (arg, &endptr, 10); + if (*endptr != '\0' || *local_pref == ULONG_MAX) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, local_pref); + return NULL; + } + return local_pref; +} + +/* Free route map's local preference value. */ +void +route_set_local_pref_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set local preference rule structure. */ +struct route_map_rule_cmd route_set_local_pref_cmd = +{ + "local-preference", + route_set_local_pref, + route_set_local_pref_compile, + route_set_local_pref_free, +}; + +/* `set weight WEIGHT' */ + +/* Set weight. */ +route_map_result_t +route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type, + void *object) +{ + u_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, +}; + +/* `set metric METRIC' */ + +/* Set metric to attribute. */ +route_map_result_t +route_set_metric (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + char *metric; + u_int32_t metric_val; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + /* Fetch routemap's rule information. */ + metric = rule; + bgp_info = object; + + if (! (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))) + bgp_info->attr->med = 0; + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + + if (all_digit (metric)) + { + metric_val = strtoul (metric, (char **)NULL, 10); + bgp_info->attr->med = metric_val; + } + else + { + metric_val = strtoul (metric+1, (char **)NULL, 10); + + if (strncmp (metric, "+", 1) == 0) + { + if (bgp_info->attr->med/2 + metric_val/2 > ULONG_MAX/2) + bgp_info->attr->med = ULONG_MAX-1; + else + bgp_info->attr->med += metric_val; + } + else if (strncmp (metric, "-", 1) == 0) + { + if (bgp_info->attr->med <= metric_val) + bgp_info->attr->med = 0; + else + bgp_info->attr->med -= metric_val; + } + } + } + return RMAP_OKAY; +} + +/* set metric compilation. */ +void * +route_set_metric_compile (char *arg) +{ + u_int32_t metric; + char *endptr = NULL; + + if (all_digit (arg)) + { + /* set metric value check*/ + metric = strtoul (arg, &endptr, 10); + if (*endptr != '\0' || metric == ULONG_MAX) + return NULL; + } + else + { + /* set metric +/-value check */ + if ((strncmp (arg, "+", 1) != 0 + && strncmp (arg, "-", 1) != 0) + || (! all_digit (arg+1))) + return NULL; + + metric = strtoul (arg+1, &endptr, 10); + if (*endptr != '\0' || metric == ULONG_MAX) + return NULL; + } + + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `set metric' value. */ +void +route_set_metric_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set metric rule structure. */ +struct route_map_rule_cmd route_set_metric_cmd = +{ + "metric", + route_set_metric, + route_set_metric_compile, + route_set_metric_free, +}; + +/* `set as-path prepend ASPATH' */ + +/* For AS path prepend mechanism. */ +route_map_result_t +route_set_aspath_prepend (void *rule, struct prefix *prefix, route_map_object_t type, void *object) +{ + struct aspath *aspath; + struct aspath *new; + struct bgp_info *binfo; + + if (type == RMAP_BGP) + { + aspath = rule; + binfo = object; + + if (binfo->attr->aspath->refcnt) + new = aspath_dup (binfo->attr->aspath); + else + new = binfo->attr->aspath; + + aspath_prepend (aspath, new); + binfo->attr->aspath = new; + } + + return RMAP_OKAY; +} + +/* Compile function for as-path prepend. */ +void * +route_set_aspath_prepend_compile (char *arg) +{ + struct aspath *aspath; + + aspath = aspath_str2aspath (arg); + if (! aspath) + return NULL; + return aspath; +} + +/* Compile function for as-path prepend. */ +void +route_set_aspath_prepend_free (void *rule) +{ + struct aspath *aspath = rule; + aspath_free (aspath); +} + +/* Set metric rule structure. */ +struct route_map_rule_cmd route_set_aspath_prepend_cmd = +{ + "as-path prepend", + route_set_aspath_prepend, + route_set_aspath_prepend_compile, + route_set_aspath_prepend_free, +}; + +/* `set community COMMUNITY' */ +struct rmap_com_set +{ + struct community *com; + int additive; + int none; +}; + +/* For community set mechanism. */ +route_map_result_t +route_set_community (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct rmap_com_set *rcs; + struct bgp_info *binfo; + struct attr *attr; + struct community *new = NULL; + struct community *old; + struct community *merge; + + if (type == RMAP_BGP) + { + rcs = rule; + binfo = object; + attr = binfo->attr; + old = attr->community; + + /* "none" case. */ + if (rcs->none) + { + attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)); + attr->community = NULL; + return RMAP_OKAY; + } + + /* "additive" case. */ + if (rcs->additive && old) + { + merge = community_merge (community_dup (old), rcs->com); + new = community_uniq_sort (merge); + community_free (merge); + } + else + new = community_dup (rcs->com); + + attr->community = new; + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); + } + + return RMAP_OKAY; +} + +/* Compile function for set community. */ +void * +route_set_community_compile (char *arg) +{ + struct rmap_com_set *rcs; + struct community *com = NULL; + char *sp; + int additive = 0; + int none = 0; + + if (strcmp (arg, "none") == 0) + none = 1; + else + { + sp = strstr (arg, "additive"); + + if (sp && sp > arg) + { + /* "additive" keyworkd is included. */ + additive = 1; + *(sp - 1) = '\0'; + } + + com = community_str2com (arg); + + if (additive) + *(sp - 1) = ' '; + + if (! com) + return NULL; + } + + rcs = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_com_set)); + memset (rcs, 0, sizeof (struct rmap_com_set)); + + rcs->com = com; + rcs->additive = additive; + rcs->none = none; + + return rcs; +} + +/* Free function for set community. */ +void +route_set_community_free (void *rule) +{ + struct rmap_com_set *rcs = rule; + + if (rcs->com) + community_free (rcs->com); + XFREE (MTYPE_ROUTE_MAP_COMPILED, rcs); +} + +/* Set community rule structure. */ +struct route_map_rule_cmd route_set_community_cmd = +{ + "community", + route_set_community, + route_set_community_compile, + route_set_community_free, +}; + +/* `set comm-list (<1-99>|<100-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, +}; + +/* `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, +}; + +/* `set origin ORIGIN' */ + +/* For origin set. */ +route_map_result_t +route_set_origin (void *rule, struct prefix *prefix, route_map_object_t type, void *object) +{ + u_char *origin; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + origin = rule; + bgp_info = object; + + bgp_info->attr->origin = *origin; + } + + return RMAP_OKAY; +} + +/* Compile function for origin set. */ +void * +route_set_origin_compile (char *arg) +{ + u_char *origin; + + origin = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_char)); + + if (strcmp (arg, "igp") == 0) + *origin = 0; + else if (strcmp (arg, "egp") == 0) + *origin = 1; + else + *origin = 2; + + return origin; +} + +/* Compile function for origin set. */ +void +route_set_origin_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set metric rule structure. */ +struct route_map_rule_cmd route_set_origin_cmd = +{ + "origin", + route_set_origin, + route_set_origin_compile, + route_set_origin_free, +}; + +/* `set atomic-aggregate' */ + +/* For atomic aggregate set. */ +route_map_result_t +route_set_atomic_aggregate (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + bgp_info = object; + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); + } + + return RMAP_OKAY; +} + +/* Compile function for atomic aggregate. */ +void * +route_set_atomic_aggregate_compile (char *arg) +{ + return (void *)1; +} + +/* Compile function for atomic aggregate. */ +void +route_set_atomic_aggregate_free (void *rule) +{ + return; +} + +/* Set atomic aggregate rule structure. */ +struct route_map_rule_cmd route_set_atomic_aggregate_cmd = +{ + "atomic-aggregate", + route_set_atomic_aggregate, + route_set_atomic_aggregate_compile, + route_set_atomic_aggregate_free, +}; + +/* `set aggregator as AS A.B.C.D' */ +struct aggregator +{ + as_t as; + struct in_addr address; +}; + +route_map_result_t +route_set_aggregator_as (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct bgp_info *bgp_info; + struct aggregator *aggregator; + + if (type == RMAP_BGP) + { + bgp_info = object; + aggregator = rule; + + bgp_info->attr->aggregator_as = aggregator->as; + bgp_info->attr->aggregator_addr = aggregator->address; + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); + } + + return RMAP_OKAY; +} + +void * +route_set_aggregator_as_compile (char *arg) +{ + struct aggregator *aggregator; + char as[10]; + char address[20]; + + aggregator = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct aggregator)); + memset (aggregator, 0, sizeof (struct aggregator)); + + sscanf (arg, "%s %s", as, address); + + aggregator->as = strtoul (as, NULL, 10); + inet_aton (address, &aggregator->address); + + return aggregator; +} + +void +route_set_aggregator_as_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_set_aggregator_as_cmd = +{ + "aggregator as", + route_set_aggregator_as, + route_set_aggregator_as_compile, + route_set_aggregator_as_free, +}; + +#ifdef HAVE_IPV6 +/* `match ipv6 address IP_ACCESS_LIST' */ + +route_map_result_t +route_match_ipv6_address (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; + + if (type == RMAP_BGP) + { + alist = access_list_lookup (AFI_IP6, (char *) rule); + if (alist == NULL) + return RMAP_NOMATCH; + + return (access_list_apply (alist, prefix) == FILTER_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ipv6_address_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ipv6_address_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip address matching. */ +struct route_map_rule_cmd route_match_ipv6_address_cmd = +{ + "ipv6 address", + route_match_ipv6_address, + route_match_ipv6_address_compile, + route_match_ipv6_address_free +}; + +/* `match ipv6 next-hop IP_ADDRESS' */ + +route_map_result_t +route_match_ipv6_next_hop (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct in6_addr *addr; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + addr = rule; + bgp_info = object; + + if (IPV6_ADDR_SAME (&bgp_info->attr->mp_nexthop_global, rule)) + return RMAP_MATCH; + + if (bgp_info->attr->mp_nexthop_len == 32 && + IPV6_ADDR_SAME (&bgp_info->attr->mp_nexthop_local, rule)) + return RMAP_MATCH; + + return RMAP_NOMATCH; + } + + return RMAP_NOMATCH; +} + +void * +route_match_ipv6_next_hop_compile (char *arg) +{ + struct in6_addr *address; + int ret; + + address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr)); + + ret = inet_pton (AF_INET6, arg, address); + if (!ret) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, address); + return NULL; + } + + return address; +} + +void +route_match_ipv6_next_hop_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ipv6_next_hop_cmd = +{ + "ipv6 next-hop", + route_match_ipv6_next_hop, + route_match_ipv6_next_hop_compile, + route_match_ipv6_next_hop_free +}; + +/* `match ipv6 address prefix-list PREFIX_LIST' */ + +route_map_result_t +route_match_ipv6_address_prefix_list (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; + + if (type == RMAP_BGP) + { + plist = prefix_list_lookup (AFI_IP6, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ipv6_address_prefix_list_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ipv6_address_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = +{ + "ipv6 address prefix-list", + route_match_ipv6_address_prefix_list, + route_match_ipv6_address_prefix_list_compile, + route_match_ipv6_address_prefix_list_free +}; + +/* `set ipv6 nexthop global IP_ADDRESS' */ + +/* Set nexthop to object. ojbect must be pointer to struct attr. */ +route_map_result_t +route_set_ipv6_nexthop_global (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct in6_addr *address; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + /* Fetch routemap's rule information. */ + address = rule; + bgp_info = object; + + /* Set next hop value. */ + bgp_info->attr->mp_nexthop_global = *address; + + /* Set nexthop length. */ + if (bgp_info->attr->mp_nexthop_len == 0) + bgp_info->attr->mp_nexthop_len = 16; + } + + return RMAP_OKAY; +} + +/* Route map `ip next-hop' compile function. Given string is converted + to struct in_addr structure. */ +void * +route_set_ipv6_nexthop_global_compile (char *arg) +{ + int ret; + struct in6_addr *address; + + address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr)); + + ret = inet_pton (AF_INET6, arg, address); + + if (ret == 0) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, address); + return NULL; + } + + return address; +} + +/* Free route map's compiled `ip next-hop' value. */ +void +route_set_ipv6_nexthop_global_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip nexthop set. */ +struct route_map_rule_cmd route_set_ipv6_nexthop_global_cmd = +{ + "ipv6 next-hop global", + route_set_ipv6_nexthop_global, + route_set_ipv6_nexthop_global_compile, + route_set_ipv6_nexthop_global_free +}; + +/* `set ipv6 nexthop local IP_ADDRESS' */ + +/* Set nexthop to object. ojbect must be pointer to struct attr. */ +route_map_result_t +route_set_ipv6_nexthop_local (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct in6_addr *address; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + /* Fetch routemap's rule information. */ + address = rule; + bgp_info = object; + + /* Set next hop value. */ + bgp_info->attr->mp_nexthop_local = *address; + + /* Set nexthop length. */ + if (bgp_info->attr->mp_nexthop_len != 32) + bgp_info->attr->mp_nexthop_len = 32; + } + + return RMAP_OKAY; +} + +/* Route map `ip nexthop' compile function. Given string is converted + to struct in_addr structure. */ +void * +route_set_ipv6_nexthop_local_compile (char *arg) +{ + int ret; + struct in6_addr *address; + + address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr)); + + ret = inet_pton (AF_INET6, arg, address); + + if (ret == 0) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, address); + return NULL; + } + + return address; +} + +/* Free route map's compiled `ip nexthop' value. */ +void +route_set_ipv6_nexthop_local_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip nexthop set. */ +struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = +{ + "ipv6 next-hop local", + route_set_ipv6_nexthop_local, + route_set_ipv6_nexthop_local_compile, + route_set_ipv6_nexthop_local_free +}; +#endif /* HAVE_IPV6 */ + +/* `set vpnv4 nexthop A.B.C.D' */ + +route_map_result_t +route_set_vpnv4_nexthop (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct in_addr *address; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + /* Fetch routemap's rule information. */ + address = rule; + bgp_info = object; + + /* Set next hop value. */ + bgp_info->attr->mp_nexthop_global_in = *address; + } + + return RMAP_OKAY; +} + +void * +route_set_vpnv4_nexthop_compile (char *arg) +{ + int ret; + struct in_addr *address; + + address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr)); + + ret = inet_aton (arg, address); + + if (ret == 0) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, address); + return NULL; + } + + return address; +} + +void +route_set_vpnv4_nexthop_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip nexthop set. */ +struct route_map_rule_cmd route_set_vpnv4_nexthop_cmd = +{ + "vpnv4 next-hop", + route_set_vpnv4_nexthop, + route_set_vpnv4_nexthop_compile, + route_set_vpnv4_nexthop_free +}; + +/* `set originator-id' */ + +/* For origin set. */ +route_map_result_t +route_set_originator_id (void *rule, struct prefix *prefix, route_map_object_t type, void *object) +{ + struct in_addr *address; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + address = rule; + bgp_info = object; + + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID); + bgp_info->attr->originator_id = *address; + } + + return RMAP_OKAY; +} + +/* Compile function for originator-id set. */ +void * +route_set_originator_id_compile (char *arg) +{ + int ret; + struct in_addr *address; + + address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr)); + + ret = inet_aton (arg, address); + + if (ret == 0) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, address); + return NULL; + } + + return address; +} + +/* Compile function for originator_id set. */ +void +route_set_originator_id_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set metric rule structure. */ +struct route_map_rule_cmd route_set_originator_id_cmd = +{ + "originator-id", + route_set_originator_id, + route_set_originator_id_compile, + route_set_originator_id_free, +}; + +/* Add bgp route map rule. */ +int +bgp_route_match_add (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_add_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Delete bgp route map rule. */ +int +bgp_route_match_delete (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_delete_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Add bgp route map rule. */ +int +bgp_route_set_add (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_add_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Delete bgp route map rule. */ +int +bgp_route_set_delete (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_delete_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Hook function for updating route_map assignment. */ +void +bgp_route_map_update () +{ + int i; + afi_t afi; + safi_t safi; + int direct; + struct listnode *nn, *nm; + struct bgp *bgp; + struct peer *peer; + struct peer_group *group; + struct bgp_filter *filter; + struct bgp_node *bn; + struct bgp_static *bgp_static; + + /* For neighbor route-map updates. */ + LIST_LOOP (bm->bgp, bgp, nn) + { + LIST_LOOP (bgp->peer, peer, nm) + { + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + filter = &peer->filter[afi][safi]; + + for (direct = FILTER_IN; direct < FILTER_MAX; direct++) + { + if (filter->map[direct].name) + filter->map[direct].map = + route_map_lookup_by_name (filter->map[direct].name); + else + filter->map[direct].map = NULL; + } + + if (filter->usmap.name) + filter->usmap.map = route_map_lookup_by_name (filter->usmap.name); + else + filter->usmap.map = NULL; + } + } + LIST_LOOP (bgp->group, group, nm) + { + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + filter = &group->conf->filter[afi][safi]; + + for (direct = FILTER_IN; direct < FILTER_MAX; direct++) + { + if (filter->map[direct].name) + filter->map[direct].map = + route_map_lookup_by_name (filter->map[direct].name); + else + filter->map[direct].map = NULL; + } + + if (filter->usmap.name) + filter->usmap.map = route_map_lookup_by_name (filter->usmap.name); + else + filter->usmap.map = NULL; + } + } + } + + /* For default-originate route-map updates. */ + LIST_LOOP (bm->bgp, bgp, nn) + { + LIST_LOOP (bgp->peer, peer, nm) + { + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + if (peer->default_rmap[afi][safi].name) + peer->default_rmap[afi][safi].map = + route_map_lookup_by_name (peer->default_rmap[afi][safi].name); + else + peer->default_rmap[afi][safi].map = NULL; + } + } + } + + /* For network route-map updates. */ + LIST_LOOP (bm->bgp, bgp, nn) + { + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + for (bn = bgp_table_top (bgp->route[afi][safi]); bn; + bn = bgp_route_next (bn)) + if ((bgp_static = bn->info) != NULL) + { + if (bgp_static->rmap.name) + bgp_static->rmap.map = + route_map_lookup_by_name (bgp_static->rmap.name); + else + bgp_static->rmap.map = NULL; + } + } + + /* For redistribute route-map updates. */ + LIST_LOOP (bm->bgp, bgp, nn) + { + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + { + if (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name) + bgp->rmap[ZEBRA_FAMILY_IPV4][i].map = + route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name); +#ifdef HAVE_IPV6 + if (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name) + bgp->rmap[ZEBRA_FAMILY_IPV6][i].map = + route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name); +#endif /* HAVE_IPV6 */ + } + } +} + +DEFUN (match_ip_address, + match_ip_address_cmd, + "match ip address (<1-199>|<1300-2699>|WORD)", + MATCH_STR + IP_STR + "Match address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n") +{ + return bgp_route_match_add (vty, vty->index, "ip address", argv[0]); +} + +DEFUN (no_match_ip_address, + no_match_ip_address_cmd, + "no match ip address", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n") +{ + if (argc == 0) + return bgp_route_match_delete (vty, vty->index, "ip address", NULL); + + return bgp_route_match_delete (vty, vty->index, "ip address", argv[0]); +} + +ALIAS (no_match_ip_address, + no_match_ip_address_val_cmd, + "no match ip address (<1-199>|<1300-2699>|WORD)", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n") + +DEFUN (match_ip_next_hop, + match_ip_next_hop_cmd, + "match ip next-hop (<1-199>|<1300-2699>|WORD)", + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n") +{ + return bgp_route_match_add (vty, vty->index, "ip next-hop", argv[0]); +} + +DEFUN (no_match_ip_next_hop, + no_match_ip_next_hop_cmd, + "no match ip next-hop", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n") +{ + if (argc == 0) + return bgp_route_match_delete (vty, vty->index, "ip next-hop", NULL); + + return bgp_route_match_delete (vty, vty->index, "ip next-hop", argv[0]); +} + +ALIAS (no_match_ip_next_hop, + no_match_ip_next_hop_val_cmd, + "no match ip next-hop (<1-199>|<1300-2699>|WORD)", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n") + +DEFUN (match_ip_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") + + +#ifdef HAVE_IPV6 +DEFUN (match_ipv6_address, + match_ipv6_address_cmd, + "match ipv6 address WORD", + MATCH_STR + IPV6_STR + "Match IPv6 address of route\n" + "IPv6 access-list name\n") +{ + return bgp_route_match_add (vty, vty->index, "ipv6 address", argv[0]); +} + +DEFUN (no_match_ipv6_address, + no_match_ipv6_address_cmd, + "no match ipv6 address WORD", + NO_STR + MATCH_STR + IPV6_STR + "Match IPv6 address of route\n" + "IPv6 access-list name\n") +{ + return bgp_route_match_delete (vty, vty->index, "ipv6 address", argv[0]); +} + +DEFUN (match_ipv6_next_hop, + match_ipv6_next_hop_cmd, + "match ipv6 next-hop X:X::X:X", + MATCH_STR + IPV6_STR + "Match IPv6 next-hop address of route\n" + "IPv6 address of next hop\n") +{ + return bgp_route_match_add (vty, vty->index, "ipv6 next-hop", argv[0]); +} + +DEFUN (no_match_ipv6_next_hop, + no_match_ipv6_next_hop_cmd, + "no match ipv6 next-hop X:X::X:X", + NO_STR + MATCH_STR + IPV6_STR + "Match IPv6 next-hop address of route\n" + "IPv6 address of next hop\n") +{ + return bgp_route_match_delete (vty, vty->index, "ipv6 next-hop", argv[0]); +} + +DEFUN (match_ipv6_address_prefix_list, + match_ipv6_address_prefix_list_cmd, + "match ipv6 address prefix-list WORD", + MATCH_STR + IPV6_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + return bgp_route_match_add (vty, vty->index, "ipv6 address prefix-list", argv[0]); +} + +DEFUN (no_match_ipv6_address_prefix_list, + no_match_ipv6_address_prefix_list_cmd, + "no match ipv6 address prefix-list WORD", + NO_STR + MATCH_STR + IPV6_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + return bgp_route_match_delete (vty, vty->index, "ipv6 address prefix-list", argv[0]); +} + +DEFUN (set_ipv6_nexthop_global, + set_ipv6_nexthop_global_cmd, + "set ipv6 next-hop global X:X::X:X", + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "IPv6 global address\n" + "IPv6 address of next hop\n") +{ + return bgp_route_set_add (vty, vty->index, "ipv6 next-hop global", argv[0]); +} + +DEFUN (no_set_ipv6_nexthop_global, + no_set_ipv6_nexthop_global_cmd, + "no set ipv6 next-hop global", + NO_STR + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "IPv6 global address\n") +{ + if (argc == 0) + return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop global", NULL); + + return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop global", argv[0]); +} + +ALIAS (no_set_ipv6_nexthop_global, + no_set_ipv6_nexthop_global_val_cmd, + "no set ipv6 next-hop global X:X::X:X", + NO_STR + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "IPv6 global address\n" + "IPv6 address of next hop\n") + +DEFUN (set_ipv6_nexthop_local, + set_ipv6_nexthop_local_cmd, + "set ipv6 next-hop local X:X::X:X", + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "IPv6 local address\n" + "IPv6 address of next hop\n") +{ + return bgp_route_set_add (vty, vty->index, "ipv6 next-hop local", argv[0]); +} + +DEFUN (no_set_ipv6_nexthop_local, + no_set_ipv6_nexthop_local_cmd, + "no set ipv6 next-hop local", + NO_STR + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "IPv6 local address\n") +{ + if (argc == 0) + return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop local", NULL); + + return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop local", argv[0]); +} + +ALIAS (no_set_ipv6_nexthop_local, + no_set_ipv6_nexthop_local_val_cmd, + "no set ipv6 next-hop local X:X::X:X", + NO_STR + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "IPv6 local address\n" + "IPv6 address of next hop\n") +#endif /* HAVE_IPV6 */ + +DEFUN (set_vpnv4_nexthop, + set_vpnv4_nexthop_cmd, + "set vpnv4 next-hop A.B.C.D", + SET_STR + "VPNv4 information\n" + "VPNv4 next-hop address\n" + "IP address of next hop\n") +{ + return bgp_route_set_add (vty, vty->index, "vpnv4 next-hop", argv[0]); +} + +DEFUN (no_set_vpnv4_nexthop, + no_set_vpnv4_nexthop_cmd, + "no set vpnv4 next-hop", + NO_STR + SET_STR + "VPNv4 information\n" + "VPNv4 next-hop address\n") +{ + if (argc == 0) + return bgp_route_set_delete (vty, vty->index, "vpnv4 next-hop", NULL); + + return bgp_route_set_delete (vty, vty->index, "vpnv4 next-hop", argv[0]); +} + +ALIAS (no_set_vpnv4_nexthop, + no_set_vpnv4_nexthop_val_cmd, + "no set vpnv4 next-hop A.B.C.D", + NO_STR + SET_STR + "VPNv4 information\n" + "VPNv4 next-hop address\n" + "IP address of next hop\n") + +DEFUN (set_originator_id, + set_originator_id_cmd, + "set originator-id A.B.C.D", + SET_STR + "BGP originator ID attribute\n" + "IP address of originator\n") +{ + return bgp_route_set_add (vty, vty->index, "originator-id", argv[0]); +} + +DEFUN (no_set_originator_id, + no_set_originator_id_cmd, + "no set originator-id", + NO_STR + SET_STR + "BGP originator ID attribute\n") +{ + if (argc == 0) + return bgp_route_set_delete (vty, vty->index, "originator-id", NULL); + + return bgp_route_set_delete (vty, vty->index, "originator-id", argv[0]); +} + +ALIAS (no_set_originator_id, + no_set_originator_id_val_cmd, + "no set originator-id A.B.C.D", + NO_STR + SET_STR + "BGP originator ID attribute\n" + "IP address of originator\n") + + +/* Initialization of route map. */ +void +bgp_route_map_init () +{ + route_map_init (); + route_map_init_vty (); + route_map_add_hook (bgp_route_map_update); + route_map_delete_hook (bgp_route_map_update); + + route_map_install_match (&route_match_ip_address_cmd); + route_map_install_match (&route_match_ip_next_hop_cmd); + route_map_install_match (&route_match_ip_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 index 00000000..bf9c7f87 --- /dev/null +++ b/bgpd/bgp_snmp.c @@ -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 + +#ifdef HAVE_SNMP +#include +#include +#include + +#include "if.h" +#include "log.h" +#include "prefix.h" +#include "command.h" +#include "thread.h" +#include "smux.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_fsm.h" + +/* BGP4-MIB described in RFC1657. */ +#define BGP4MIB 1,3,6,1,2,1,15 + +/* Zebra enterprise BGP MIB. This variable is used for register + OSPF MIB to SNMP agent under SMUX protocol. */ +#define BGPDMIB 1,3,6,1,4,1,3317,1,2,2 + +/* BGP MIB bgpVersion. */ +#define BGPVERSION 0 + +/* BGP MIB bgpLocalAs. */ +#define BGPLOCALAS 0 + +/* BGP MIB bgpPeerTable. */ +#define BGPPEERIDENTIFIER 1 +#define BGPPEERSTATE 2 +#define BGPPEERADMINSTATUS 3 +#define BGPPEERNEGOTIATEDVERSION 4 +#define BGPPEERLOCALADDR 5 +#define BGPPEERLOCALPORT 6 +#define BGPPEERREMOTEADDR 7 +#define BGPPEERREMOTEPORT 8 +#define BGPPEERREMOTEAS 9 +#define BGPPEERINUPDATES 10 +#define BGPPEEROUTUPDATES 11 +#define BGPPEERINTOTALMESSAGES 12 +#define BGPPEEROUTTOTALMESSAGES 13 +#define BGPPEERLASTERROR 14 +#define BGPPEERFSMESTABLISHEDTRANSITIONS 15 +#define BGPPEERFSMESTABLISHEDTIME 16 +#define BGPPEERCONNECTRETRYINTERVAL 17 +#define BGPPEERHOLDTIME 18 +#define BGPPEERKEEPALIVE 19 +#define BGPPEERHOLDTIMECONFIGURED 20 +#define BGPPEERKEEPALIVECONFIGURED 21 +#define BGPPEERMINASORIGINATIONINTERVAL 22 +#define BGPPEERMINROUTEADVERTISEMENTINTERVAL 23 +#define BGPPEERINUPDATEELAPSEDTIME 24 + +/* BGP MIB bgpIdentifier. */ +#define BGPIDENTIFIER 0 + +/* BGP MIB bgpRcvdPathAttrTable */ +#define BGPPATHATTRPEER 1 +#define BGPPATHATTRDESTNETWORK 2 +#define BGPPATHATTRORIGIN 3 +#define BGPPATHATTRASPATH 4 +#define BGPPATHATTRNEXTHOP 5 +#define BGPPATHATTRINTERASMETRIC 6 + +/* BGP MIB bgp4PathAttrTable. */ +#define BGP4PATHATTRPEER 1 +#define BGP4PATHATTRIPADDRPREFIXLEN 2 +#define BGP4PATHATTRIPADDRPREFIX 3 +#define BGP4PATHATTRORIGIN 4 +#define BGP4PATHATTRASPATHSEGMENT 5 +#define BGP4PATHATTRNEXTHOP 6 +#define BGP4PATHATTRMULTIEXITDISC 7 +#define BGP4PATHATTRLOCALPREF 8 +#define BGP4PATHATTRATOMICAGGREGATE 9 +#define BGP4PATHATTRAGGREGATORAS 10 +#define BGP4PATHATTRAGGREGATORADDR 11 +#define BGP4PATHATTRCALCLOCALPREF 12 +#define BGP4PATHATTRBEST 13 +#define BGP4PATHATTRUNKNOWN 14 + +/* SNMP value hack. */ +#define INTEGER ASN_INTEGER +#define INTEGER32 ASN_INTEGER +#define COUNTER32 ASN_COUNTER +#define OCTET_STRING ASN_OCTET_STR +#define IPADDRESS ASN_IPADDRESS +#define GAUGE32 ASN_UNSIGNED + +/* Declare static local variables for convenience. */ +SNMP_LOCAL_VARIABLES + +/* BGP-MIB instances. */ +oid bgp_oid [] = { BGP4MIB }; +oid bgpd_oid [] = { BGPDMIB }; + +/* IP address 0.0.0.0. */ +static struct in_addr bgp_empty_addr = {0}; + +/* Hook functions. */ +static u_char *bgpVersion (); +static u_char *bgpLocalAs (); +static u_char *bgpPeerTable (); +static u_char *bgpRcvdPathAttrTable (); +static u_char *bgpIdentifier (); +static u_char *bgp4PathAttrTable (); +/* static u_char *bgpTraps (); */ + +struct variable bgp_variables[] = +{ + /* BGP version. */ + {BGPVERSION, OCTET_STRING, RONLY, bgpVersion, + 1, {1}}, + /* BGP local AS. */ + {BGPLOCALAS, INTEGER, RONLY, bgpLocalAs, + 1, {2}}, + /* BGP peer table. */ + {BGPPEERIDENTIFIER, IPADDRESS, RONLY, bgpPeerTable, + 3, {3, 1, 1}}, + {BGPPEERSTATE, INTEGER, RONLY, bgpPeerTable, + 3, {3, 1, 2}}, + {BGPPEERADMINSTATUS, INTEGER, RWRITE, bgpPeerTable, + 3, {3, 1, 3}}, + {BGPPEERNEGOTIATEDVERSION, INTEGER32, RONLY, bgpPeerTable, + 3, {3, 1, 4}}, + {BGPPEERLOCALADDR, IPADDRESS, RONLY, bgpPeerTable, + 3, {3, 1, 5}}, + {BGPPEERLOCALPORT, INTEGER, RONLY, bgpPeerTable, + 3, {3, 1, 6}}, + {BGPPEERREMOTEADDR, IPADDRESS, RONLY, bgpPeerTable, + 3, {3, 1, 7}}, + {BGPPEERREMOTEPORT, INTEGER, RONLY, bgpPeerTable, + 3, {3, 1, 8}}, + {BGPPEERREMOTEAS, INTEGER, RONLY, bgpPeerTable, + 3, {3, 1, 9}}, + {BGPPEERINUPDATES, COUNTER32, RONLY, bgpPeerTable, + 3, {3, 1, 10}}, + {BGPPEEROUTUPDATES, COUNTER32, RONLY, bgpPeerTable, + 3, {3, 1, 11}}, + {BGPPEERINTOTALMESSAGES, COUNTER32, RONLY, bgpPeerTable, + 3, {3, 1, 12}}, + {BGPPEEROUTTOTALMESSAGES, COUNTER32, RONLY, bgpPeerTable, + 3, {3, 1, 13}}, + {BGPPEERLASTERROR, OCTET_STRING, RONLY, bgpPeerTable, + 3, {3, 1, 14}}, + {BGPPEERFSMESTABLISHEDTRANSITIONS, COUNTER32, RONLY, bgpPeerTable, + 3, {3, 1, 15}}, + {BGPPEERFSMESTABLISHEDTIME, GAUGE32, RONLY, bgpPeerTable, + 3, {3, 1, 16}}, + {BGPPEERCONNECTRETRYINTERVAL, INTEGER, RWRITE, bgpPeerTable, + 3, {3, 1, 17}}, + {BGPPEERHOLDTIME, INTEGER, RONLY, bgpPeerTable, + 3, {3, 1, 18}}, + {BGPPEERKEEPALIVE, INTEGER, RONLY, bgpPeerTable, + 3, {3, 1, 19}}, + {BGPPEERHOLDTIMECONFIGURED, INTEGER, RWRITE, bgpPeerTable, + 3, {3, 1, 20}}, + {BGPPEERKEEPALIVECONFIGURED, INTEGER, RWRITE, bgpPeerTable, + 3, {3, 1, 21}}, + {BGPPEERMINASORIGINATIONINTERVAL, INTEGER, RWRITE, bgpPeerTable, + 3, {3, 1, 22}}, + {BGPPEERMINROUTEADVERTISEMENTINTERVAL, INTEGER, RWRITE, bgpPeerTable, + 3, {3, 1, 23}}, + {BGPPEERINUPDATEELAPSEDTIME, GAUGE32, RONLY, bgpPeerTable, + 3, {3, 1, 24}}, + /* BGP identifier. */ + {BGPIDENTIFIER, IPADDRESS, RONLY, bgpIdentifier, + 1, {4}}, + /* BGP received path attribute table. */ + {BGPPATHATTRPEER, IPADDRESS, RONLY, bgpRcvdPathAttrTable, + 3, {5, 1, 1}}, + {BGPPATHATTRDESTNETWORK, IPADDRESS, RONLY, bgpRcvdPathAttrTable, + 3, {5, 1, 2}}, + {BGPPATHATTRORIGIN, INTEGER, RONLY, bgpRcvdPathAttrTable, + 3, {5, 1, 3}}, + {BGPPATHATTRASPATH, OCTET_STRING, RONLY, bgpRcvdPathAttrTable, + 3, {5, 1, 4}}, + {BGPPATHATTRNEXTHOP, IPADDRESS, RONLY, bgpRcvdPathAttrTable, + 3, {5, 1, 5}}, + {BGPPATHATTRINTERASMETRIC, INTEGER32, RONLY, bgpRcvdPathAttrTable, + 3, {5, 1, 6}}, + /* BGP-4 received path attribute table. */ + {BGP4PATHATTRPEER, IPADDRESS, RONLY, bgp4PathAttrTable, + 3, {6, 1, 1}}, + {BGP4PATHATTRIPADDRPREFIXLEN, INTEGER, RONLY, bgp4PathAttrTable, + 3, {6, 1, 2}}, + {BGP4PATHATTRIPADDRPREFIX, IPADDRESS, RONLY, bgp4PathAttrTable, + 3, {6, 1, 3}}, + {BGP4PATHATTRORIGIN, INTEGER, RONLY, bgp4PathAttrTable, + 3, {6, 1, 4}}, + {BGP4PATHATTRASPATHSEGMENT, OCTET_STRING, RONLY, bgp4PathAttrTable, + 3, {6, 1, 5}}, + {BGP4PATHATTRNEXTHOP, IPADDRESS, RONLY, bgp4PathAttrTable, + 3, {6, 1, 6}}, + {BGP4PATHATTRMULTIEXITDISC, INTEGER, RONLY, bgp4PathAttrTable, + 3, {6, 1, 7}}, + {BGP4PATHATTRLOCALPREF, INTEGER, RONLY, bgp4PathAttrTable, + 3, {6, 1, 8}}, + {BGP4PATHATTRATOMICAGGREGATE, INTEGER, RONLY, bgp4PathAttrTable, + 3, {6, 1, 9}}, + {BGP4PATHATTRAGGREGATORAS, INTEGER, RONLY, bgp4PathAttrTable, + 3, {6, 1, 10}}, + {BGP4PATHATTRAGGREGATORADDR, IPADDRESS, RONLY, bgp4PathAttrTable, + 3, {6, 1, 11}}, + {BGP4PATHATTRCALCLOCALPREF, INTEGER, RONLY, bgp4PathAttrTable, + 3, {6, 1, 12}}, + {BGP4PATHATTRBEST, INTEGER, RONLY, bgp4PathAttrTable, + 3, {6, 1, 13}}, + {BGP4PATHATTRUNKNOWN, OCTET_STRING, RONLY, bgp4PathAttrTable, + 3, {6, 1, 14}}, +}; + +static u_char * +bgpVersion (struct variable *v, oid name[], size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + static u_char version; + + if (smux_header_generic(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + /* Retrun BGP version. Zebra bgpd only support version 4. */ + version = (0x80 >> (BGP_VERSION_4 - 1)); + + /* Return octet string length 1. */ + *var_len = 1; + return (u_char *)&version; +} + +static u_char * +bgpLocalAs (struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + struct bgp *bgp; + + if (smux_header_generic(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + /* Get BGP structure. */ + bgp = bgp_get_default (); + if (! bgp) + return NULL; + + return SNMP_INTEGER (bgp->as); +} + +struct peer * +peer_lookup_addr_ipv4 (struct in_addr *src) +{ + struct bgp *bgp; + struct peer *peer; + struct listnode *nn; + struct in_addr addr; + int ret; + + bgp = bgp_get_default (); + if (! bgp) + return NULL; + + LIST_LOOP (bgp->peer, peer, nn) + { + ret = inet_pton (AF_INET, peer->host, &addr); + if (ret > 0) + { + if (IPV4_ADDR_SAME (&addr, src)) + return peer; + } + } + return NULL; +} + +struct peer * +bgp_peer_lookup_next (struct in_addr *src) +{ + struct bgp *bgp; + struct peer *peer; + struct listnode *nn; + struct in_addr *p; + union sockunion su; + int ret; + + memset (&su, 0, sizeof (union sockunion)); + + bgp = bgp_get_default (); + if (! bgp) + return NULL; + + LIST_LOOP (bgp->peer, peer, nn) + { + ret = inet_pton (AF_INET, peer->host, &su.sin.sin_addr); + if (ret > 0) + { + p = &su.sin.sin_addr; + + if (ntohl (p->s_addr) > ntohl (src->s_addr)) + { + src->s_addr = p->s_addr; + return peer; + } + } + } + return NULL; +} + +struct peer * +bgpPeerTable_lookup (struct variable *v, oid name[], size_t *length, + struct in_addr *addr, int exact) +{ + struct peer *peer = NULL; + int len; + + if (exact) + { + /* Check the length. */ + if (*length - v->namelen != sizeof (struct in_addr)) + return NULL; + + oid2in_addr (name + v->namelen, IN_ADDR_SIZE, addr); + + peer = peer_lookup_addr_ipv4 (addr); + return peer; + } + else + { + len = *length - v->namelen; + if (len > 4) len = 4; + + oid2in_addr (name + v->namelen, len, addr); + + peer = bgp_peer_lookup_next (addr); + + if (peer == NULL) + return NULL; + + oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr)); + *length = sizeof (struct in_addr) + v->namelen; + + return peer; + } + return NULL; +} + +/* BGP write methods. */ +int +write_bgpPeerTable (int action, u_char *var_val, + u_char var_val_type, size_t var_val_len, + u_char *statP, oid *name, size_t length, + struct variable *v) +{ + struct in_addr addr; + struct peer *peer; + long intval; + int bigsize = SNMP_MAX_LEN; + + if (var_val_type != ASN_INTEGER) + { + return SNMP_ERR_WRONGTYPE; + } + if (var_val_len != sizeof (long)) + { + return SNMP_ERR_WRONGLENGTH; + } + + if (! asn_parse_int(var_val, &bigsize, &var_val_type, + &intval, sizeof(long))) + { + return SNMP_ERR_WRONGENCODING; + } + + memset (&addr, 0, sizeof (struct in_addr)); + + peer = bgpPeerTable_lookup (v, name, &length, &addr, 1); + if (! peer) + return SNMP_ERR_NOSUCHNAME; + + printf ("val: %ld\n", intval); + + switch (v->magic) + { + case BGPPEERADMINSTATUS: +#define BGP_PeerAdmin_stop 1 +#define BGP_PeerAdmin_start 2 + /* When the peer is established, */ + if (intval == BGP_PeerAdmin_stop) + BGP_EVENT_ADD (peer, BGP_Stop); + else if (intval == BGP_PeerAdmin_start) + ; /* Do nothing. */ + else + return SNMP_ERR_NOSUCHNAME; + break; + case 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; +} + +/* 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 index 00000000..a8af0329 --- /dev/null +++ b/bgpd/bgp_snmp.h @@ -0,0 +1,23 @@ +/* BGP4 SNMP support + Copyright (C) 1999, 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +void bgp_snmp_init (); +void bgpTrapEstablished (struct peer *); +void bgpTrapBackwardTransition (struct peer *); diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c new file mode 100644 index 00000000..a2a3c97b --- /dev/null +++ b/bgpd/bgp_table.c @@ -0,0 +1,489 @@ +/* BGP routing table + Copyright (C) 1998, 2001 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "prefix.h" +#include "memory.h" +#include "sockunion.h" +#include "vty.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" + +void bgp_node_delete (struct bgp_node *); +void bgp_table_free (struct bgp_table *); + +struct bgp_table * +bgp_table_init (void) +{ + struct bgp_table *rt; + + rt = XMALLOC (MTYPE_BGP_TABLE, sizeof (struct bgp_table)); + memset (rt, 0, sizeof (struct bgp_table)); + return rt; +} + +void +bgp_table_finish (struct bgp_table *rt) +{ + bgp_table_free (rt); +} + +struct bgp_node * +bgp_node_create () +{ + struct bgp_node *rn; + + rn = (struct bgp_node *) XMALLOC (MTYPE_BGP_NODE, sizeof (struct bgp_node)); + memset (rn, 0, sizeof (struct bgp_node)); + return rn; +} + +/* Allocate new route node with prefix set. */ +struct bgp_node * +bgp_node_set (struct bgp_table *table, struct prefix *prefix) +{ + struct bgp_node *node; + + node = bgp_node_create (); + + prefix_copy (&node->p, prefix); + node->table = table; + + return node; +} + +/* Free route node. */ +void +bgp_node_free (struct bgp_node *node) +{ + XFREE (MTYPE_BGP_NODE, node); +} + +/* Free route table. */ +void +bgp_table_free (struct bgp_table *rt) +{ + struct bgp_node *tmp_node; + struct bgp_node *node; + + if (rt == NULL) + return; + + node = rt->top; + + while (node) + { + if (node->l_left) + { + node = node->l_left; + continue; + } + + if (node->l_right) + { + node = node->l_right; + continue; + } + + tmp_node = node; + node = node->parent; + + if (node != NULL) + { + if (node->l_left == tmp_node) + node->l_left = NULL; + else + node->l_right = NULL; + + bgp_node_free (tmp_node); + } + else + { + bgp_node_free (tmp_node); + break; + } + } + + XFREE (MTYPE_BGP_TABLE, rt); + return; +} + +/* Utility mask array. */ +static u_char maskbit[] = +{ + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff +}; + +/* Common prefix route genaration. */ +static void +route_common (struct prefix *n, struct prefix *p, struct prefix *new) +{ + int i; + u_char diff; + u_char mask; + + u_char *np = (u_char *)&n->u.prefix; + u_char *pp = (u_char *)&p->u.prefix; + u_char *newp = (u_char *)&new->u.prefix; + + for (i = 0; i < p->prefixlen / 8; i++) + { + if (np[i] == pp[i]) + newp[i] = np[i]; + else + break; + } + + new->prefixlen = i * 8; + + if (new->prefixlen != p->prefixlen) + { + diff = np[i] ^ pp[i]; + mask = 0x80; + while (new->prefixlen < p->prefixlen && !(mask & diff)) + { + mask >>= 1; + new->prefixlen++; + } + newp[i] = np[i] & maskbit[new->prefixlen % 8]; + } +} + +/* Macro version of check_bit (). */ +#define CHECK_BIT(X,P) ((((u_char *)(X))[(P) / 8]) >> (7 - ((P) % 8)) & 1) + +/* Check bit of the prefix. */ +static int +check_bit (u_char *prefix, u_char prefixlen) +{ + int offset; + int shift; + u_char *p = (u_char *)prefix; + + assert (prefixlen <= 128); + + offset = prefixlen / 8; + shift = 7 - (prefixlen % 8); + + return (p[offset] >> shift & 1); +} + +/* Macro version of set_link (). */ +#define SET_LINK(X,Y) (X)->link[CHECK_BIT(&(Y)->prefix,(X)->prefixlen)] = (Y);\ + (Y)->parent = (X) + +static void +set_link (struct bgp_node *node, struct bgp_node *new) +{ + int bit; + + bit = check_bit (&new->p.u.prefix, node->p.prefixlen); + + assert (bit == 0 || bit == 1); + + node->link[bit] = new; + new->parent = node; +} + +/* Lock node. */ +struct bgp_node * +bgp_lock_node (struct bgp_node *node) +{ + node->lock++; + return node; +} + +/* Unlock node. */ +void +bgp_unlock_node (struct bgp_node *node) +{ + node->lock--; + + if (node->lock == 0) + bgp_node_delete (node); +} + +/* Find matched prefix. */ +struct bgp_node * +bgp_node_match (struct bgp_table *table, struct prefix *p) +{ + struct bgp_node *node; + struct bgp_node *matched; + + matched = NULL; + node = table->top; + + /* Walk down tree. If there is matched route then store it to + matched. */ + while (node && node->p.prefixlen <= p->prefixlen && + prefix_match (&node->p, p)) + { + if (node->info) + matched = node; + node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)]; + } + + /* If matched route found, return it. */ + if (matched) + return bgp_lock_node (matched); + + return NULL; +} + +struct bgp_node * +bgp_node_match_ipv4 (struct bgp_table *table, struct in_addr *addr) +{ + struct prefix_ipv4 p; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = *addr; + + return bgp_node_match (table, (struct prefix *) &p); +} + +#ifdef HAVE_IPV6 +struct bgp_node * +bgp_node_match_ipv6 (struct bgp_table *table, struct in6_addr *addr) +{ + struct prefix_ipv6 p; + + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_PREFIXLEN; + p.prefix = *addr; + + return bgp_node_match (table, (struct prefix *) &p); +} +#endif /* HAVE_IPV6 */ + +/* Lookup same prefix node. Return NULL when we can't find route. */ +struct bgp_node * +bgp_node_lookup (struct bgp_table *table, struct prefix *p) +{ + struct bgp_node *node; + + node = table->top; + + while (node && node->p.prefixlen <= p->prefixlen && + prefix_match (&node->p, p)) + { + if (node->p.prefixlen == p->prefixlen && node->info) + return bgp_lock_node (node); + + node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)]; + } + + return NULL; +} + +/* Add node to routing table. */ +struct bgp_node * +bgp_node_get (struct bgp_table *table, struct prefix *p) +{ + struct bgp_node *new; + struct bgp_node *node; + struct bgp_node *match; + + match = NULL; + node = table->top; + while (node && node->p.prefixlen <= p->prefixlen && + prefix_match (&node->p, p)) + { + if (node->p.prefixlen == p->prefixlen) + { + bgp_lock_node (node); + return node; + } + match = node; + node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)]; + } + + if (node == NULL) + { + new = bgp_node_set (table, p); + if (match) + set_link (match, new); + else + table->top = new; + } + else + { + new = bgp_node_create (); + route_common (&node->p, p, &new->p); + new->p.family = p->family; + new->table = table; + set_link (new, node); + + if (match) + set_link (match, new); + else + table->top = new; + + if (new->p.prefixlen != p->prefixlen) + { + match = new; + new = bgp_node_set (table, p); + set_link (match, new); + } + } + bgp_lock_node (new); + + return new; +} + +/* Delete node from the routing table. */ +void +bgp_node_delete (struct bgp_node *node) +{ + struct bgp_node *child; + struct bgp_node *parent; + + assert (node->lock == 0); + assert (node->info == NULL); + + if (node->l_left && node->l_right) + return; + + if (node->l_left) + child = node->l_left; + else + child = node->l_right; + + parent = node->parent; + + if (child) + child->parent = parent; + + if (parent) + { + if (parent->l_left == node) + parent->l_left = child; + else + parent->l_right = child; + } + else + node->table->top = child; + + bgp_node_free (node); + + /* If parent node is stub then delete it also. */ + if (parent && parent->lock == 0) + bgp_node_delete (parent); +} + +/* Get fist node and lock it. This function is useful when one want + to lookup all the node exist in the routing table. */ +struct bgp_node * +bgp_table_top (struct bgp_table *table) +{ + /* If there is no node in the routing table return NULL. */ + if (table->top == NULL) + return NULL; + + /* Lock the top node and return it. */ + bgp_lock_node (table->top); + return table->top; +} + +/* Unlock current node and lock next node then return it. */ +struct bgp_node * +bgp_route_next (struct bgp_node *node) +{ + struct bgp_node *next; + struct bgp_node *start; + + /* Node may be deleted from bgp_unlock_node so we have to preserve + next node's pointer. */ + + if (node->l_left) + { + next = node->l_left; + bgp_lock_node (next); + bgp_unlock_node (node); + return next; + } + if (node->l_right) + { + next = node->l_right; + bgp_lock_node (next); + bgp_unlock_node (node); + return next; + } + + start = node; + while (node->parent) + { + if (node->parent->l_left == node && node->parent->l_right) + { + next = node->parent->l_right; + bgp_lock_node (next); + bgp_unlock_node (start); + return next; + } + node = node->parent; + } + bgp_unlock_node (start); + return NULL; +} + +/* Unlock current node and lock next node until limit. */ +struct bgp_node * +bgp_route_next_until (struct bgp_node *node, struct bgp_node *limit) +{ + struct bgp_node *next; + struct bgp_node *start; + + /* Node may be deleted from bgp_unlock_node so we have to preserve + next node's pointer. */ + + if (node->l_left) + { + next = node->l_left; + bgp_lock_node (next); + bgp_unlock_node (node); + return next; + } + if (node->l_right) + { + next = node->l_right; + bgp_lock_node (next); + bgp_unlock_node (node); + return next; + } + + start = node; + while (node->parent && node != limit) + { + if (node->parent->l_left == node && node->parent->l_right) + { + next = node->parent->l_right; + bgp_lock_node (next); + bgp_unlock_node (start); + return next; + } + node = node->parent; + } + bgp_unlock_node (start); + return NULL; +} diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h new file mode 100644 index 00000000..52eb6a49 --- /dev/null +++ b/bgpd/bgp_table.h @@ -0,0 +1,65 @@ +/* BGP routing table + Copyright (C) 1998, 2001 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +struct bgp_table +{ + struct bgp_node *top; +}; + +struct bgp_node +{ + struct prefix p; + + struct bgp_table *table; + struct bgp_node *parent; + struct bgp_node *link[2]; +#define l_left link[0] +#define l_right link[1] + + unsigned int lock; + + void *info; + + struct bgp_adj_out *adj_out; + + struct bgp_adj_in *adj_in; + + void *aggregate; + + struct bgp_node *prn; +}; + +struct bgp_table *bgp_table_init (void); +void bgp_table_finish (struct bgp_table *); +void bgp_unlock_node (struct bgp_node *node); +void bgp_node_delete (struct bgp_node *node); +struct bgp_node *bgp_table_top (struct bgp_table *); +struct bgp_node *bgp_route_next (struct bgp_node *); +struct bgp_node *bgp_route_next_until (struct bgp_node *, struct bgp_node *); +struct bgp_node *bgp_node_get (struct bgp_table *, struct prefix *); +struct bgp_node *bgp_node_lookup (struct bgp_table *, struct prefix *); +struct bgp_node *bgp_lock_node (struct bgp_node *node); +struct bgp_node *bgp_node_match (struct bgp_table *, struct prefix *); +struct bgp_node *bgp_node_match_ipv4 (struct bgp_table *, + struct in_addr *); +#ifdef HAVE_IPV6 +struct bgp_node *bgp_node_match_ipv6 (struct bgp_table *, + struct in6_addr *); +#endif /* HAVE_IPV6 */ diff --git a/bgpd/bgp_view.c b/bgpd/bgp_view.c new file mode 100644 index 00000000..795d1551 --- /dev/null +++ b/bgpd/bgp_view.c @@ -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 + +#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 index 00000000..c1bae93e --- /dev/null +++ b/bgpd/bgp_vty.c @@ -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 + +#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; +} + +/* "router bgp" commands. */ +DEFUN (router_bgp, + router_bgp_cmd, + "router bgp <1-65535>", + ROUTER_STR + BGP_STR + AS_STR) +{ + int ret; + as_t as; + struct bgp *bgp; + char *name = NULL; + + VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, 65535); + + if (argc == 2) + name = argv[1]; + + ret = bgp_get (&bgp, &as, name); + switch (ret) + { + case BGP_ERR_MULTIPLE_INSTANCE_NOT_SET: + vty_out (vty, "Please specify 'bgp multiple-instance' first%s", + VTY_NEWLINE); + return CMD_WARNING; + break; + case BGP_ERR_AS_MISMATCH: + vty_out (vty, "BGP is already running; AS is %d%s", as, VTY_NEWLINE); + return CMD_WARNING; + break; + case BGP_ERR_INSTANCE_MISMATCH: + vty_out (vty, "BGP view name and AS number mismatch%s", VTY_NEWLINE); + vty_out (vty, "BGP instance is already running; AS is %d%s", + as, VTY_NEWLINE); + return CMD_WARNING; + break; + } + + vty->node = BGP_NODE; + vty->index = bgp; + + return CMD_SUCCESS; +} + +ALIAS (router_bgp, + router_bgp_view_cmd, + "router bgp <1-65535> view WORD", + ROUTER_STR + BGP_STR + AS_STR + "BGP view\n" + "view name\n") + +/* "no router bgp" commands. */ +DEFUN (no_router_bgp, + no_router_bgp_cmd, + "no router bgp <1-65535>", + NO_STR + ROUTER_STR + BGP_STR + AS_STR) +{ + as_t as; + struct bgp *bgp; + char *name = NULL; + + VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, 65535); + + if (argc == 2) + name = argv[1]; + + /* Lookup bgp structure. */ + bgp = bgp_lookup (as, name); + if (! bgp) + { + vty_out (vty, "%% Can't find BGP instance%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_delete (bgp); + + return CMD_SUCCESS; +} + +ALIAS (no_router_bgp, + no_router_bgp_view_cmd, + "no router bgp <1-65535> view WORD", + NO_STR + ROUTER_STR + BGP_STR + AS_STR + "BGP view\n" + "view name\n") + +/* BGP router-id. */ + +DEFUN (bgp_router_id, + bgp_router_id_cmd, + "bgp router-id A.B.C.D", + BGP_STR + "Override configured router identifier\n" + "Manually configured router identifier\n") +{ + int ret; + struct in_addr id; + struct bgp *bgp; + + bgp = vty->index; + + ret = inet_aton (argv[0], &id); + if (! ret) + { + vty_out (vty, "%% Malformed bgp router identifier%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_router_id_set (bgp, &id); + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_router_id, + no_bgp_router_id_cmd, + "no bgp router-id", + NO_STR + BGP_STR + "Override configured router identifier\n") +{ + int ret; + struct in_addr id; + struct bgp *bgp; + + bgp = vty->index; + + if (argc == 1) + { + ret = inet_aton (argv[0], &id); + if (! ret) + { + vty_out (vty, "%% Malformed BGP router identifier%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (! IPV4_ADDR_SAME (&bgp->router_id, &id)) + { + vty_out (vty, "%% BGP router-id doesn't match%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + bgp_router_id_unset (bgp); + + return CMD_SUCCESS; +} + +ALIAS (no_bgp_router_id, + no_bgp_router_id_val_cmd, + "no bgp router-id A.B.C.D", + NO_STR + BGP_STR + "Override configured router identifier\n" + "Manually configured router identifier\n") + +/* BGP Cluster ID. */ + +DEFUN (bgp_cluster_id, + bgp_cluster_id_cmd, + "bgp cluster-id A.B.C.D", + BGP_STR + "Configure Route-Reflector Cluster-id\n" + "Route-Reflector Cluster-id in IP address format\n") +{ + int ret; + struct bgp *bgp; + struct in_addr cluster; + + bgp = vty->index; + + ret = inet_aton (argv[0], &cluster); + if (! ret) + { + vty_out (vty, "%% Malformed bgp cluster identifier%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_cluster_id_set (bgp, &cluster); + + return CMD_SUCCESS; +} + +ALIAS (bgp_cluster_id, + bgp_cluster_id32_cmd, + "bgp cluster-id <1-4294967295>", + BGP_STR + "Configure Route-Reflector Cluster-id\n" + "Route-Reflector Cluster-id as 32 bit quantity\n") + +DEFUN (no_bgp_cluster_id, + no_bgp_cluster_id_cmd, + "no bgp cluster-id", + NO_STR + BGP_STR + "Configure Route-Reflector Cluster-id\n") +{ + int ret; + struct bgp *bgp; + struct in_addr cluster; + + bgp = vty->index; + + if (argc == 1) + { + ret = inet_aton (argv[0], &cluster); + if (! ret) + { + vty_out (vty, "%% Malformed bgp cluster identifier%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + bgp_cluster_id_unset (bgp); + + return CMD_SUCCESS; +} + +ALIAS (no_bgp_cluster_id, + no_bgp_cluster_id_arg_cmd, + "no bgp cluster-id A.B.C.D", + NO_STR + BGP_STR + "Configure Route-Reflector Cluster-id\n" + "Route-Reflector Cluster-id in IP address format\n") + +DEFUN (bgp_confederation_identifier, + bgp_confederation_identifier_cmd, + "bgp confederation identifier <1-65535>", + "BGP specific commands\n" + "AS confederation parameters\n" + "AS number\n" + "Set routing domain confederation AS\n") +{ + struct bgp *bgp; + as_t as; + + bgp = vty->index; + + VTY_GET_INTEGER ("AS", as, argv[0]); + + bgp_confederation_id_set (bgp, as); + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_confederation_identifier, + no_bgp_confederation_identifier_cmd, + "no bgp confederation identifier", + NO_STR + "BGP specific commands\n" + "AS confederation parameters\n" + "AS number\n") +{ + struct bgp *bgp; + as_t as; + + bgp = vty->index; + + if (argc == 1) + VTY_GET_INTEGER ("AS", as, argv[0]); + + bgp_confederation_id_unset (bgp); + + return CMD_SUCCESS; +} + +ALIAS (no_bgp_confederation_identifier, + no_bgp_confederation_identifier_arg_cmd, + "no bgp confederation identifier <1-65535>", + NO_STR + "BGP specific commands\n" + "AS confederation parameters\n" + "AS number\n" + "Set routing domain confederation AS\n") + +DEFUN (bgp_confederation_peers, + bgp_confederation_peers_cmd, + "bgp confederation peers .<1-65535>", + "BGP specific commands\n" + "AS confederation parameters\n" + "Peer ASs in BGP confederation\n" + AS_STR) +{ + struct bgp *bgp; + as_t as; + int i; + + bgp = vty->index; + + for (i = 0; i < argc; i++) + { + VTY_GET_INTEGER_RANGE ("AS", as, argv[i], 1, 65535); + + if (bgp->as == as) + { + vty_out (vty, "%% Local member-AS not allowed in confed peer list%s", + VTY_NEWLINE); + continue; + } + + bgp_confederation_peers_add (bgp, as); + } + return CMD_SUCCESS; +} + +DEFUN (no_bgp_confederation_peers, + no_bgp_confederation_peers_cmd, + "no bgp confederation peers .<1-65535>", + NO_STR + "BGP specific commands\n" + "AS confederation parameters\n" + "Peer ASs in BGP confederation\n" + AS_STR) +{ + struct bgp *bgp; + as_t as; + int i; + + bgp = vty->index; + + for (i = 0; i < argc; i++) + { + VTY_GET_INTEGER_RANGE ("AS", as, argv[i], 1, 65535); + + bgp_confederation_peers_remove (bgp, as); + } + return CMD_SUCCESS; +} + +/* BGP timers. */ + +DEFUN (bgp_timers, + bgp_timers_cmd, + "timers bgp <0-65535> <0-65535>", + "Adjust routing timers\n" + "BGP timers\n" + "Keepalive interval\n" + "Holdtime\n") +{ + struct bgp *bgp; + unsigned long keepalive = 0; + unsigned long holdtime = 0; + + bgp = vty->index; + + VTY_GET_INTEGER ("keepalive", keepalive, argv[0]); + VTY_GET_INTEGER ("holdtime", holdtime, argv[1]); + + /* Holdtime value check. */ + if (holdtime < 3 && holdtime != 0) + { + vty_out (vty, "%% hold time value must be either 0 or greater than 3%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_timers_set (bgp, keepalive, holdtime); + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_timers, + no_bgp_timers_cmd, + "no timers bgp", + NO_STR + "Adjust routing timers\n" + "BGP timers\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_timers_unset (bgp); + + return CMD_SUCCESS; +} + +ALIAS (no_bgp_timers, + no_bgp_timers_arg_cmd, + "no timers bgp <0-65535> <0-65535>", + NO_STR + "Adjust routing timers\n" + "BGP timers\n" + "Keepalive interval\n" + "Holdtime\n") + +DEFUN (bgp_client_to_client_reflection, + bgp_client_to_client_reflection_cmd, + "bgp client-to-client reflection", + "BGP specific commands\n" + "Configure client to client route reflection\n" + "reflection of routes allowed\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_client_to_client_reflection, + no_bgp_client_to_client_reflection_cmd, + "no bgp client-to-client reflection", + NO_STR + "BGP specific commands\n" + "Configure client to client route reflection\n" + "reflection of routes allowed\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT); + return CMD_SUCCESS; +} + +/* "bgp always-compare-med" configuration. */ +DEFUN (bgp_always_compare_med, + bgp_always_compare_med_cmd, + "bgp always-compare-med", + "BGP specific commands\n" + "Allow comparing MED from different neighbors\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_ALWAYS_COMPARE_MED); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_always_compare_med, + no_bgp_always_compare_med_cmd, + "no bgp always-compare-med", + NO_STR + "BGP specific commands\n" + "Allow comparing MED from different neighbors\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_ALWAYS_COMPARE_MED); + return CMD_SUCCESS; +} + +/* "bgp deterministic-med" configuration. */ +DEFUN (bgp_deterministic_med, + bgp_deterministic_med_cmd, + "bgp deterministic-med", + "BGP specific commands\n" + "Pick the best-MED path among paths advertised from the neighboring AS\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_DETERMINISTIC_MED); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_deterministic_med, + no_bgp_deterministic_med_cmd, + "no bgp deterministic-med", + NO_STR + "BGP specific commands\n" + "Pick the best-MED path among paths advertised from the neighboring AS\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_DETERMINISTIC_MED); + return CMD_SUCCESS; +} + +/* "bgp fast-external-failover" configuration. */ +DEFUN (bgp_fast_external_failover, + bgp_fast_external_failover_cmd, + "bgp fast-external-failover", + BGP_STR + "Immediately reset session if a link to a directly connected external peer goes down\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_NO_FAST_EXT_FAILOVER); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_fast_external_failover, + no_bgp_fast_external_failover_cmd, + "no bgp fast-external-failover", + NO_STR + BGP_STR + "Immediately reset session if a link to a directly connected external peer goes down\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_NO_FAST_EXT_FAILOVER); + return CMD_SUCCESS; +} + +/* "bgp enforce-first-as" configuration. */ +DEFUN (bgp_enforce_first_as, + bgp_enforce_first_as_cmd, + "bgp enforce-first-as", + BGP_STR + "Enforce the first AS for EBGP routes\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_ENFORCE_FIRST_AS); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_enforce_first_as, + no_bgp_enforce_first_as_cmd, + "no bgp enforce-first-as", + NO_STR + BGP_STR + "Enforce the first AS for EBGP routes\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_ENFORCE_FIRST_AS); + return CMD_SUCCESS; +} + +/* "bgp bestpath compare-routerid" configuration. */ +DEFUN (bgp_bestpath_compare_router_id, + bgp_bestpath_compare_router_id_cmd, + "bgp bestpath compare-routerid", + "BGP specific commands\n" + "Change the default bestpath selection\n" + "Compare router-id for identical EBGP paths\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_COMPARE_ROUTER_ID); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_bestpath_compare_router_id, + no_bgp_bestpath_compare_router_id_cmd, + "no bgp bestpath compare-routerid", + NO_STR + "BGP specific commands\n" + "Change the default bestpath selection\n" + "Compare router-id for identical EBGP paths\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_COMPARE_ROUTER_ID); + return CMD_SUCCESS; +} + +/* "bgp bestpath as-path ignore" configuration. */ +DEFUN (bgp_bestpath_aspath_ignore, + bgp_bestpath_aspath_ignore_cmd, + "bgp bestpath as-path ignore", + "BGP specific commands\n" + "Change the default bestpath selection\n" + "AS-path attribute\n" + "Ignore as-path length in selecting a route\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_ASPATH_IGNORE); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_bestpath_aspath_ignore, + no_bgp_bestpath_aspath_ignore_cmd, + "no bgp bestpath as-path ignore", + NO_STR + "BGP specific commands\n" + "Change the default bestpath selection\n" + "AS-path attribute\n" + "Ignore as-path length in selecting a route\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_ASPATH_IGNORE); + return CMD_SUCCESS; +} + +/* "bgp bestpath med" configuration. */ +DEFUN (bgp_bestpath_med, + bgp_bestpath_med_cmd, + "bgp bestpath med (confed|missing-as-worst)", + "BGP specific commands\n" + "Change the default bestpath selection\n" + "MED attribute\n" + "Compare MED among confederation paths\n" + "Treat missing MED as the least preferred one\n") +{ + struct bgp *bgp; + + bgp = vty->index; + + if (strncmp (argv[0], "confed", 1) == 0) + bgp_flag_set (bgp, BGP_FLAG_MED_CONFED); + else + bgp_flag_set (bgp, BGP_FLAG_MED_MISSING_AS_WORST); + + return CMD_SUCCESS; +} + +DEFUN (bgp_bestpath_med2, + bgp_bestpath_med2_cmd, + "bgp bestpath med confed missing-as-worst", + "BGP specific commands\n" + "Change the default bestpath selection\n" + "MED attribute\n" + "Compare MED among confederation paths\n" + "Treat missing MED as the least preferred one\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_MED_CONFED); + bgp_flag_set (bgp, BGP_FLAG_MED_MISSING_AS_WORST); + return CMD_SUCCESS; +} + +ALIAS (bgp_bestpath_med2, + bgp_bestpath_med3_cmd, + "bgp bestpath med missing-as-worst confed", + "BGP specific commands\n" + "Change the default bestpath selection\n" + "MED attribute\n" + "Treat missing MED as the least preferred one\n" + "Compare MED among confederation paths\n") + +DEFUN (no_bgp_bestpath_med, + no_bgp_bestpath_med_cmd, + "no bgp bestpath med (confed|missing-as-worst)", + NO_STR + "BGP specific commands\n" + "Change the default bestpath selection\n" + "MED attribute\n" + "Compare MED among confederation paths\n" + "Treat missing MED as the least preferred one\n") +{ + struct bgp *bgp; + + bgp = vty->index; + + if (strncmp (argv[0], "confed", 1) == 0) + bgp_flag_unset (bgp, BGP_FLAG_MED_CONFED); + else + bgp_flag_unset (bgp, BGP_FLAG_MED_MISSING_AS_WORST); + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_bestpath_med2, + no_bgp_bestpath_med2_cmd, + "no bgp bestpath med confed missing-as-worst", + NO_STR + "BGP specific commands\n" + "Change the default bestpath selection\n" + "MED attribute\n" + "Compare MED among confederation paths\n" + "Treat missing MED as the least preferred one\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_MED_CONFED); + bgp_flag_unset (bgp, BGP_FLAG_MED_MISSING_AS_WORST); + return CMD_SUCCESS; +} + +ALIAS (no_bgp_bestpath_med2, + no_bgp_bestpath_med3_cmd, + "no bgp bestpath med missing-as-worst confed", + NO_STR + "BGP specific commands\n" + "Change the default bestpath selection\n" + "MED attribute\n" + "Treat missing MED as the least preferred one\n" + "Compare MED among confederation paths\n") + +/* "no bgp default ipv4-unicast". */ +DEFUN (no_bgp_default_ipv4_unicast, + no_bgp_default_ipv4_unicast_cmd, + "no bgp default ipv4-unicast", + NO_STR + "BGP specific commands\n" + "Configure BGP defaults\n" + "Activate ipv4-unicast for a peer by default\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_NO_DEFAULT_IPV4); + return CMD_SUCCESS; +} + +DEFUN (bgp_default_ipv4_unicast, + bgp_default_ipv4_unicast_cmd, + "bgp default ipv4-unicast", + "BGP specific commands\n" + "Configure BGP defaults\n" + "Activate ipv4-unicast for a peer by default\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_NO_DEFAULT_IPV4); + return CMD_SUCCESS; +} + +/* "bgp import-check" configuration. */ +DEFUN (bgp_network_import_check, + bgp_network_import_check_cmd, + "bgp network import-check", + "BGP specific commands\n" + "BGP network command\n" + "Check BGP network route exists in IGP\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_IMPORT_CHECK); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_network_import_check, + no_bgp_network_import_check_cmd, + "no bgp network import-check", + NO_STR + "BGP specific commands\n" + "BGP network command\n" + "Check BGP network route exists in IGP\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK); + return CMD_SUCCESS; +} + +DEFUN (bgp_default_local_preference, + bgp_default_local_preference_cmd, + "bgp default local-preference <0-4294967295>", + "BGP specific commands\n" + "Configure BGP defaults\n" + "local preference (higher=more preferred)\n" + "Configure default local preference value\n") +{ + struct bgp *bgp; + u_int32_t local_pref; + + bgp = vty->index; + + VTY_GET_INTEGER ("local preference", local_pref, argv[0]); + + bgp_default_local_preference_set (bgp, local_pref); + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_default_local_preference, + no_bgp_default_local_preference_cmd, + "no bgp default local-preference", + NO_STR + "BGP specific commands\n" + "Configure BGP defaults\n" + "local preference (higher=more preferred)\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_default_local_preference_unset (bgp); + return CMD_SUCCESS; +} + +ALIAS (no_bgp_default_local_preference, + no_bgp_default_local_preference_val_cmd, + "no bgp default local-preference <0-4294967295>", + NO_STR + "BGP specific commands\n" + "Configure BGP defaults\n" + "local preference (higher=more preferred)\n" + "Configure default local preference value\n") + +static int +peer_remote_as_vty (struct vty *vty, char *peer_str, char *as_str, afi_t afi, + safi_t safi) +{ + int ret; + struct bgp *bgp; + as_t as; + union sockunion su; + + bgp = vty->index; + + /* Get AS number. */ + VTY_GET_INTEGER_RANGE ("AS", as, as_str, 1, 65535); + + /* If peer is peer group, call proper function. */ + ret = str2sockunion (peer_str, &su); + if (ret < 0) + { + ret = peer_group_remote_as (bgp, peer_str, &as); + if (ret < 0) + { + vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; + } + + if (peer_address_self_check (&su)) + { + vty_out (vty, "%% Can not configure the local system as neighbor%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ret = peer_remote_as (bgp, &su, &as, afi, safi); + + /* This peer belongs to peer group. */ + switch (ret) + { + case BGP_ERR_PEER_GROUP_MEMBER: + vty_out (vty, "%% Peer-group AS %d. Cannot configure remote-as for member%s", as, VTY_NEWLINE); + return CMD_WARNING; + break; + case BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT: + vty_out (vty, "%% The AS# can not be changed from %d to %s, peer-group members must be all internal or all external%s", as, as_str, VTY_NEWLINE); + return CMD_WARNING; + break; + } + return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_remote_as, + neighbor_remote_as_cmd, + NEIGHBOR_CMD2 "remote-as <1-65535>", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Specify a BGP neighbor\n" + AS_STR) +{ + return peer_remote_as_vty (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST); +} + +DEFUN (neighbor_peer_group, + neighbor_peer_group_cmd, + "neighbor WORD peer-group", + NEIGHBOR_STR + "Neighbor tag\n" + "Configure peer-group\n") +{ + struct bgp *bgp; + struct peer_group *group; + + bgp = vty->index; + + group = peer_group_get (bgp, argv[0]); + if (! group) + return CMD_WARNING; + + return CMD_SUCCESS; +} + +DEFUN (no_neighbor, + no_neighbor_cmd, + NO_NEIGHBOR_CMD2, + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2) +{ + int ret; + union sockunion su; + struct peer_group *group; + struct peer *peer; + + ret = str2sockunion (argv[0], &su); + if (ret < 0) + { + group = peer_group_lookup (vty->index, argv[0]); + if (group) + peer_group_delete (group); + else + { + vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + peer = peer_lookup (vty->index, &su); + if (peer) + peer_delete (peer); + } + + return CMD_SUCCESS; +} + +ALIAS (no_neighbor, + no_neighbor_remote_as_cmd, + NO_NEIGHBOR_CMD "remote-as <1-65535>", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Specify a BGP neighbor\n" + AS_STR) + +DEFUN (no_neighbor_peer_group, + no_neighbor_peer_group_cmd, + "no neighbor WORD peer-group", + NO_STR + NEIGHBOR_STR + "Neighbor tag\n" + "Configure peer-group\n") +{ + struct peer_group *group; + + group = peer_group_lookup (vty->index, argv[0]); + if (group) + peer_group_delete (group); + else + { + vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +DEFUN (no_neighbor_peer_group_remote_as, + no_neighbor_peer_group_remote_as_cmd, + "no neighbor WORD remote-as <1-65535>", + NO_STR + NEIGHBOR_STR + "Neighbor tag\n" + "Specify a BGP neighbor\n" + AS_STR) +{ + struct peer_group *group; + + group = peer_group_lookup (vty->index, argv[0]); + if (group) + peer_group_remote_as_delete (group); + else + { + vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +DEFUN (neighbor_local_as, + neighbor_local_as_cmd, + NEIGHBOR_CMD2 "local-as <1-65535>", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Specify a local-as number\n" + "AS number used as local AS\n") +{ + struct peer *peer; + int ret; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + ret = peer_local_as_set (peer, atoi (argv[1]), 0); + return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_local_as_no_prepend, + neighbor_local_as_no_prepend_cmd, + NEIGHBOR_CMD2 "local-as <1-65535> no-prepend", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Specify a local-as number\n" + "AS number used as local AS\n" + "Do not prepend local-as to updates from ebgp peers\n") +{ + struct peer *peer; + int ret; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + ret = peer_local_as_set (peer, atoi (argv[1]), 1); + return bgp_vty_return (vty, ret); +} + +DEFUN (no_neighbor_local_as, + no_neighbor_local_as_cmd, + NO_NEIGHBOR_CMD2 "local-as", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Specify a local-as number\n") +{ + struct peer *peer; + int ret; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + ret = peer_local_as_unset (peer); + return bgp_vty_return (vty, ret); +} + +ALIAS (no_neighbor_local_as, + no_neighbor_local_as_val_cmd, + NO_NEIGHBOR_CMD2 "local-as <1-65535>", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Specify a local-as number\n" + "AS number used as local AS\n") + +ALIAS (no_neighbor_local_as, + no_neighbor_local_as_val2_cmd, + NO_NEIGHBOR_CMD2 "local-as <1-65535> no-prepend", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Specify a local-as number\n" + "AS number used as local AS\n" + "Do not prepend local-as to updates from ebgp peers\n") + +DEFUN (neighbor_activate, + neighbor_activate_cmd, + NEIGHBOR_CMD2 "activate", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Enable the Address Family for this Neighbor\n") +{ + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + peer_activate (peer, bgp_node_afi (vty), bgp_node_safi (vty)); + + return CMD_SUCCESS; +} + +DEFUN (no_neighbor_activate, + no_neighbor_activate_cmd, + NO_NEIGHBOR_CMD2 "activate", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Enable the Address Family for this Neighbor\n") +{ + int ret; + struct peer *peer; + + /* Lookup peer. */ + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + ret = peer_deactivate (peer, bgp_node_afi (vty), bgp_node_safi (vty)); + + return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_set_peer_group, + neighbor_set_peer_group_cmd, + NEIGHBOR_CMD "peer-group WORD", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Member of the peer-group\n" + "peer-group name\n") +{ + int ret; + as_t as; + union sockunion su; + struct bgp *bgp; + struct peer_group *group; + + bgp = vty->index; + + ret = str2sockunion (argv[0], &su); + if (ret < 0) + { + vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + group = peer_group_lookup (bgp, argv[1]); + if (! group) + { + vty_out (vty, "%% Configure the peer-group first%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (peer_address_self_check (&su)) + { + vty_out (vty, "%% Can not configure the local system as neighbor%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ret = peer_group_bind (bgp, &su, group, bgp_node_afi (vty), + bgp_node_safi (vty), &as); + + if (ret == BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT) + { + vty_out (vty, "%% Peer with AS %d cannot be in this peer-group, members must be all internal or all external%s", as, VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_vty_return (vty, ret); +} + +DEFUN (no_neighbor_set_peer_group, + no_neighbor_set_peer_group_cmd, + NO_NEIGHBOR_CMD "peer-group WORD", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Member of the peer-group\n" + "peer-group name\n") +{ + int ret; + struct bgp *bgp; + struct peer *peer; + struct peer_group *group; + + bgp = vty->index; + + peer = peer_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + group = peer_group_lookup (bgp, argv[1]); + if (! group) + { + vty_out (vty, "%% Configure the peer-group first%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = peer_group_unbind (bgp, peer, group, bgp_node_afi (vty), + bgp_node_safi (vty)); + + return bgp_vty_return (vty, ret); +} + +int +peer_flag_modify_vty (struct vty *vty, char *ip_str, u_int16_t flag, int set) +{ + int ret; + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + if (set) + ret = peer_flag_set (peer, flag); + else + ret = peer_flag_unset (peer, flag); + + return bgp_vty_return (vty, ret); +} + +int +peer_flag_set_vty (struct vty *vty, char *ip_str, u_int16_t flag) +{ + return peer_flag_modify_vty (vty, ip_str, flag, 1); +} + +int +peer_flag_unset_vty (struct vty *vty, char *ip_str, u_int16_t flag) +{ + return peer_flag_modify_vty (vty, ip_str, flag, 0); +} + +/* neighbor passive. */ +DEFUN (neighbor_passive, + neighbor_passive_cmd, + NEIGHBOR_CMD2 "passive", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Don't send open messages to this neighbor\n") +{ + return peer_flag_set_vty (vty, argv[0], PEER_FLAG_PASSIVE); +} + +DEFUN (no_neighbor_passive, + no_neighbor_passive_cmd, + NO_NEIGHBOR_CMD2 "passive", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Don't send open messages to this neighbor\n") +{ + return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_PASSIVE); +} + +/* neighbor shutdown. */ +DEFUN (neighbor_shutdown, + neighbor_shutdown_cmd, + NEIGHBOR_CMD2 "shutdown", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Administratively shut down this neighbor\n") +{ + return peer_flag_set_vty (vty, argv[0], PEER_FLAG_SHUTDOWN); +} + +DEFUN (no_neighbor_shutdown, + no_neighbor_shutdown_cmd, + NO_NEIGHBOR_CMD2 "shutdown", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Administratively shut down this neighbor\n") +{ + return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_SHUTDOWN); +} + +/* 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); +} + +/* neighbor capability dynamic. */ +DEFUN (neighbor_capability_dynamic, + neighbor_capability_dynamic_cmd, + NEIGHBOR_CMD2 "capability dynamic", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Advertise capability to the peer\n" + "Advertise dynamic capability to this neighbor\n") +{ + return peer_flag_set_vty (vty, argv[0], PEER_FLAG_DYNAMIC_CAPABILITY); +} + +DEFUN (no_neighbor_capability_dynamic, + no_neighbor_capability_dynamic_cmd, + NO_NEIGHBOR_CMD2 "capability dynamic", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Advertise capability to the peer\n" + "Advertise dynamic capability to this neighbor\n") +{ + return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DYNAMIC_CAPABILITY); +} + +/* neighbor dont-capability-negotiate */ +DEFUN (neighbor_dont_capability_negotiate, + neighbor_dont_capability_negotiate_cmd, + NEIGHBOR_CMD2 "dont-capability-negotiate", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Do not perform capability negotiation\n") +{ + return peer_flag_set_vty (vty, argv[0], PEER_FLAG_DONT_CAPABILITY); +} + +DEFUN (no_neighbor_dont_capability_negotiate, + no_neighbor_dont_capability_negotiate_cmd, + NO_NEIGHBOR_CMD2 "dont-capability-negotiate", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Do not perform capability negotiation\n") +{ + return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DONT_CAPABILITY); +} + +int +peer_af_flag_modify_vty (struct vty *vty, char *peer_str, afi_t afi, + safi_t safi, u_int16_t flag, int set) +{ + int ret; + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, peer_str); + if (! peer) + return CMD_WARNING; + + if (set) + ret = peer_af_flag_set (peer, afi, safi, flag); + else + ret = peer_af_flag_unset (peer, afi, safi, flag); + + return bgp_vty_return (vty, ret); +} + +int +peer_af_flag_set_vty (struct vty *vty, char *peer_str, afi_t afi, + safi_t safi, u_int16_t flag) +{ + return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 1); +} + +int +peer_af_flag_unset_vty (struct vty *vty, char *peer_str, afi_t afi, + safi_t safi, u_int16_t flag) +{ + return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 0); +} + +/* neighbor capability orf prefix-list. */ +DEFUN (neighbor_capability_orf_prefix, + neighbor_capability_orf_prefix_cmd, + NEIGHBOR_CMD2 "capability orf prefix-list (both|send|receive)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Advertise capability to the peer\n" + "Advertise ORF capability to the peer\n" + "Advertise prefixlist ORF capability to this neighbor\n" + "Capability to SEND and RECEIVE the ORF to/from this neighbor\n" + "Capability to RECEIVE the ORF from this neighbor\n" + "Capability to SEND the ORF to this neighbor\n") +{ + u_int16_t flag = 0; + + if (strncmp (argv[1], "s", 1) == 0) + flag = PEER_FLAG_ORF_PREFIX_SM; + else if (strncmp (argv[1], "r", 1) == 0) + flag = PEER_FLAG_ORF_PREFIX_RM; + else if (strncmp (argv[1], "b", 1) == 0) + flag = PEER_FLAG_ORF_PREFIX_SM|PEER_FLAG_ORF_PREFIX_RM; + else + return CMD_WARNING; + + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flag); +} + +DEFUN (no_neighbor_capability_orf_prefix, + no_neighbor_capability_orf_prefix_cmd, + NO_NEIGHBOR_CMD2 "capability orf prefix-list (both|send|receive)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Advertise capability to the peer\n" + "Advertise ORF capability to the peer\n" + "Advertise prefixlist ORF capability to this neighbor\n" + "Capability to SEND and RECEIVE the ORF to/from this neighbor\n" + "Capability to RECEIVE the ORF from this neighbor\n" + "Capability to SEND the ORF to this neighbor\n") +{ + u_int16_t flag = 0; + + if (strncmp (argv[1], "s", 1) == 0) + flag = PEER_FLAG_ORF_PREFIX_SM; + else if (strncmp (argv[1], "r", 1) == 0) + flag = PEER_FLAG_ORF_PREFIX_RM; + else if (strncmp (argv[1], "b", 1) == 0) + flag = PEER_FLAG_ORF_PREFIX_SM|PEER_FLAG_ORF_PREFIX_RM; + else + return CMD_WARNING; + + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flag); +} + +/* neighbor next-hop-self. */ +DEFUN (neighbor_nexthop_self, + neighbor_nexthop_self_cmd, + NEIGHBOR_CMD2 "next-hop-self", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Disable the next hop calculation for this neighbor\n") +{ + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF); +} + +DEFUN (no_neighbor_nexthop_self, + no_neighbor_nexthop_self_cmd, + NO_NEIGHBOR_CMD2 "next-hop-self", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Disable the next hop calculation for this neighbor\n") +{ + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF); +} + +/* neighbor remove-private-AS. */ +DEFUN (neighbor_remove_private_as, + neighbor_remove_private_as_cmd, + NEIGHBOR_CMD2 "remove-private-AS", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Remove private AS number from outbound updates\n") +{ + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_REMOVE_PRIVATE_AS); +} + +DEFUN (no_neighbor_remove_private_as, + no_neighbor_remove_private_as_cmd, + NO_NEIGHBOR_CMD2 "remove-private-AS", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Remove private AS number from outbound updates\n") +{ + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_REMOVE_PRIVATE_AS); +} + +/* neighbor send-community. */ +DEFUN (neighbor_send_community, + neighbor_send_community_cmd, + NEIGHBOR_CMD2 "send-community", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Send Community attribute to this neighbor\n") +{ + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_SEND_COMMUNITY); +} + +DEFUN (no_neighbor_send_community, + no_neighbor_send_community_cmd, + NO_NEIGHBOR_CMD2 "send-community", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Send Community attribute to this neighbor\n") +{ + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_SEND_COMMUNITY); +} + +/* neighbor send-community extended. */ +DEFUN (neighbor_send_community_type, + neighbor_send_community_type_cmd, + NEIGHBOR_CMD2 "send-community (both|extended|standard)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Send Community attribute to this neighbor\n" + "Send Standard and Extended Community attributes\n" + "Send Extended Community attributes\n" + "Send Standard Community attributes\n") +{ + if (strncmp (argv[1], "s", 1) == 0) + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_SEND_COMMUNITY); + if (strncmp (argv[1], "e", 1) == 0) + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_SEND_EXT_COMMUNITY); + + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + (PEER_FLAG_SEND_COMMUNITY| + PEER_FLAG_SEND_EXT_COMMUNITY)); +} + +DEFUN (no_neighbor_send_community_type, + no_neighbor_send_community_type_cmd, + NO_NEIGHBOR_CMD2 "send-community (both|extended|standard)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Send Community attribute to this neighbor\n" + "Send Standard and Extended Community attributes\n" + "Send Extended Community attributes\n" + "Send Standard Community attributes\n") +{ + if (strncmp (argv[1], "s", 1) == 0) + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_SEND_COMMUNITY); + if (strncmp (argv[1], "e", 1) == 0) + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_SEND_EXT_COMMUNITY); + + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + (PEER_FLAG_SEND_COMMUNITY | + PEER_FLAG_SEND_EXT_COMMUNITY)); +} + +/* neighbor soft-reconfig. */ +DEFUN (neighbor_soft_reconfiguration, + neighbor_soft_reconfiguration_cmd, + NEIGHBOR_CMD2 "soft-reconfiguration inbound", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Per neighbor soft reconfiguration\n" + "Allow inbound soft reconfiguration for this neighbor\n") +{ + return peer_af_flag_set_vty (vty, argv[0], + bgp_node_afi (vty), bgp_node_safi (vty), + PEER_FLAG_SOFT_RECONFIG); +} + +DEFUN (no_neighbor_soft_reconfiguration, + no_neighbor_soft_reconfiguration_cmd, + NO_NEIGHBOR_CMD2 "soft-reconfiguration inbound", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Per neighbor soft reconfiguration\n" + "Allow inbound soft reconfiguration for this neighbor\n") +{ + return peer_af_flag_unset_vty (vty, argv[0], + bgp_node_afi (vty), bgp_node_safi (vty), + PEER_FLAG_SOFT_RECONFIG); +} + +DEFUN (neighbor_route_reflector_client, + neighbor_route_reflector_client_cmd, + NEIGHBOR_CMD2 "route-reflector-client", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Configure a neighbor as Route Reflector client\n") +{ + struct peer *peer; + + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_REFLECTOR_CLIENT); +} + +DEFUN (no_neighbor_route_reflector_client, + no_neighbor_route_reflector_client_cmd, + NO_NEIGHBOR_CMD2 "route-reflector-client", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Configure a neighbor as Route Reflector client\n") +{ + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_REFLECTOR_CLIENT); +} + +/* neighbor route-server-client. */ +DEFUN (neighbor_route_server_client, + neighbor_route_server_client_cmd, + NEIGHBOR_CMD2 "route-server-client", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Configure a neighbor as Route Server client\n") +{ + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_RSERVER_CLIENT); +} + +DEFUN (no_neighbor_route_server_client, + no_neighbor_route_server_client_cmd, + NO_NEIGHBOR_CMD2 "route-server-client", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Configure a neighbor as Route Server client\n") +{ + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_RSERVER_CLIENT); +} + +DEFUN (neighbor_attr_unchanged, + neighbor_attr_unchanged_cmd, + NEIGHBOR_CMD2 "attribute-unchanged", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n") +{ + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + (PEER_FLAG_AS_PATH_UNCHANGED | + PEER_FLAG_NEXTHOP_UNCHANGED | + PEER_FLAG_MED_UNCHANGED)); +} + +DEFUN (neighbor_attr_unchanged1, + neighbor_attr_unchanged1_cmd, + NEIGHBOR_CMD2 "attribute-unchanged (as-path|next-hop|med)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Nexthop attribute\n" + "Med attribute\n") +{ + u_int16_t flags = 0; + + if (strncmp (argv[1], "as-path", 1) == 0) + SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); + else if (strncmp (argv[1], "next-hop", 1) == 0) + SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); + else if (strncmp (argv[1], "med", 1) == 0) + SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); + + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flags); +} + +DEFUN (neighbor_attr_unchanged2, + neighbor_attr_unchanged2_cmd, + NEIGHBOR_CMD2 "attribute-unchanged as-path (next-hop|med)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Nexthop attribute\n" + "Med attribute\n") +{ + u_int16_t flags = PEER_FLAG_AS_PATH_UNCHANGED; + + if (strncmp (argv[1], "next-hop", 1) == 0) + SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); + else if (strncmp (argv[1], "med", 1) == 0) + SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); + + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flags); + +} + +DEFUN (neighbor_attr_unchanged3, + neighbor_attr_unchanged3_cmd, + NEIGHBOR_CMD2 "attribute-unchanged next-hop (as-path|med)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Nexthop attribute\n" + "As-path attribute\n" + "Med attribute\n") +{ + u_int16_t flags = PEER_FLAG_NEXTHOP_UNCHANGED; + + if (strncmp (argv[1], "as-path", 1) == 0) + SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); + else if (strncmp (argv[1], "med", 1) == 0) + SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); + + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flags); +} + +DEFUN (neighbor_attr_unchanged4, + neighbor_attr_unchanged4_cmd, + NEIGHBOR_CMD2 "attribute-unchanged med (as-path|next-hop)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Med attribute\n" + "As-path attribute\n" + "Nexthop attribute\n") +{ + u_int16_t flags = PEER_FLAG_MED_UNCHANGED; + + if (strncmp (argv[1], "as-path", 1) == 0) + SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); + else if (strncmp (argv[1], "next-hop", 1) == 0) + SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); + + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flags); +} + +ALIAS (neighbor_attr_unchanged, + neighbor_attr_unchanged5_cmd, + NEIGHBOR_CMD2 "attribute-unchanged as-path next-hop med", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Nexthop attribute\n" + "Med attribute\n") + +ALIAS (neighbor_attr_unchanged, + neighbor_attr_unchanged6_cmd, + NEIGHBOR_CMD2 "attribute-unchanged as-path med next-hop", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Med attribute\n" + "Nexthop attribute\n") + +ALIAS (neighbor_attr_unchanged, + neighbor_attr_unchanged7_cmd, + NEIGHBOR_CMD2 "attribute-unchanged next-hop med as-path", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Nexthop attribute\n" + "Med attribute\n" + "As-path attribute\n") + +ALIAS (neighbor_attr_unchanged, + neighbor_attr_unchanged8_cmd, + NEIGHBOR_CMD2 "attribute-unchanged next-hop as-path med", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Nexthop attribute\n" + "As-path attribute\n" + "Med attribute\n") + +ALIAS (neighbor_attr_unchanged, + neighbor_attr_unchanged9_cmd, + NEIGHBOR_CMD2 "attribute-unchanged med next-hop as-path", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Med attribute\n" + "Nexthop attribute\n" + "As-path attribute\n") + +ALIAS (neighbor_attr_unchanged, + neighbor_attr_unchanged10_cmd, + NEIGHBOR_CMD2 "attribute-unchanged med as-path next-hop", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Med attribute\n" + "As-path attribute\n" + "Nexthop attribute\n") + +DEFUN (no_neighbor_attr_unchanged, + no_neighbor_attr_unchanged_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n") +{ + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + (PEER_FLAG_AS_PATH_UNCHANGED | + PEER_FLAG_NEXTHOP_UNCHANGED | + PEER_FLAG_MED_UNCHANGED)); +} + +DEFUN (no_neighbor_attr_unchanged1, + no_neighbor_attr_unchanged1_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged (as-path|next-hop|med)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Nexthop attribute\n" + "Med attribute\n") +{ + u_int16_t flags = 0; + + if (strncmp (argv[1], "as-path", 1) == 0) + SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); + else if (strncmp (argv[1], "next-hop", 1) == 0) + SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); + else if (strncmp (argv[1], "med", 1) == 0) + SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); + + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flags); +} + +DEFUN (no_neighbor_attr_unchanged2, + no_neighbor_attr_unchanged2_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged as-path (next-hop|med)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Nexthop attribute\n" + "Med attribute\n") +{ + u_int16_t flags = PEER_FLAG_AS_PATH_UNCHANGED; + + if (strncmp (argv[1], "next-hop", 1) == 0) + SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); + else if (strncmp (argv[1], "med", 1) == 0) + SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); + + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flags); +} + +DEFUN (no_neighbor_attr_unchanged3, + no_neighbor_attr_unchanged3_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged next-hop (as-path|med)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Nexthop attribute\n" + "As-path attribute\n" + "Med attribute\n") +{ + u_int16_t flags = PEER_FLAG_NEXTHOP_UNCHANGED; + + if (strncmp (argv[1], "as-path", 1) == 0) + SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); + else if (strncmp (argv[1], "med", 1) == 0) + SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); + + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flags); +} + +DEFUN (no_neighbor_attr_unchanged4, + no_neighbor_attr_unchanged4_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged med (as-path|next-hop)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Med attribute\n" + "As-path attribute\n" + "Nexthop attribute\n") +{ + u_int16_t flags = PEER_FLAG_MED_UNCHANGED; + + if (strncmp (argv[1], "as-path", 1) == 0) + SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); + else if (strncmp (argv[1], "next-hop", 1) == 0) + SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); + + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flags); +} + +ALIAS (no_neighbor_attr_unchanged, + no_neighbor_attr_unchanged5_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged as-path next-hop med", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Nexthop attribute\n" + "Med attribute\n") + +ALIAS (no_neighbor_attr_unchanged, + no_neighbor_attr_unchanged6_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged as-path med next-hop", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Med attribute\n" + "Nexthop attribute\n") + +ALIAS (no_neighbor_attr_unchanged, + no_neighbor_attr_unchanged7_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged next-hop med as-path", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Nexthop attribute\n" + "Med attribute\n" + "As-path attribute\n") + +ALIAS (no_neighbor_attr_unchanged, + no_neighbor_attr_unchanged8_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged next-hop as-path med", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Nexthop attribute\n" + "As-path attribute\n" + "Med attribute\n") + +ALIAS (no_neighbor_attr_unchanged, + no_neighbor_attr_unchanged9_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged med next-hop as-path", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Med attribute\n" + "Nexthop attribute\n" + "As-path attribute\n") + +ALIAS (no_neighbor_attr_unchanged, + no_neighbor_attr_unchanged10_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged med as-path next-hop", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Med attribute\n" + "As-path attribute\n" + "Nexthop attribute\n") + +/* 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); +} + +/* 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") + +/* 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); +} + +DEFUN (neighbor_description, + neighbor_description_cmd, + NEIGHBOR_CMD2 "description .LINE", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Neighbor specific description\n" + "Up to 80 characters describing this neighbor\n") +{ + struct peer *peer; + struct buffer *b; + char *str; + int i; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + if (argc == 1) + return CMD_SUCCESS; + + /* Make string from buffer. This function should be provided by + buffer.c. */ + b = buffer_new (1024); + for (i = 1; i < argc; i++) + { + buffer_putstr (b, (u_char *)argv[i]); + buffer_putc (b, ' '); + } + buffer_putc (b, '\0'); + str = buffer_getstr (b); + buffer_free (b); + + peer_description_set (peer, str); + + free (str); + + return CMD_SUCCESS; +} + +DEFUN (no_neighbor_description, + no_neighbor_description_cmd, + NO_NEIGHBOR_CMD2 "description", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Neighbor specific description\n") +{ + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + peer_description_unset (peer); + + return CMD_SUCCESS; +} + +ALIAS (no_neighbor_description, + no_neighbor_description_val_cmd, + NO_NEIGHBOR_CMD2 "description .LINE", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Neighbor specific description\n" + "Up to 80 characters describing this neighbor\n") + +/* Neighbor update-source. */ +int +peer_update_source_vty (struct vty *vty, char *peer_str, char *source_str) +{ + struct peer *peer; + union sockunion *su; + + peer = peer_and_group_lookup_vty (vty, peer_str); + if (! peer) + return CMD_WARNING; + + if (source_str) + { + su = sockunion_str2su (source_str); + if (su) + { + peer_update_source_addr_set (peer, su); + sockunion_free (su); + } + else + peer_update_source_if_set (peer, source_str); + } + else + peer_update_source_unset (peer); + + return CMD_SUCCESS; +} + +DEFUN (neighbor_update_source, + neighbor_update_source_cmd, + NEIGHBOR_CMD2 "update-source WORD", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Source of routing updates\n" + "Interface name\n") +{ + return peer_update_source_vty (vty, argv[0], argv[1]); +} + +DEFUN (no_neighbor_update_source, + no_neighbor_update_source_cmd, + NO_NEIGHBOR_CMD2 "update-source", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Source of routing updates\n" + "Interface name\n") +{ + return peer_update_source_vty (vty, argv[0], NULL); +} + +int +peer_default_originate_set_vty (struct vty *vty, char *peer_str, afi_t afi, + safi_t safi, char *rmap, int set) +{ + int ret; + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, peer_str); + if (! peer) + return CMD_WARNING; + + if (set) + ret = peer_default_originate_set (peer, afi, safi, rmap); + else + ret = peer_default_originate_unset (peer, afi, safi); + + return bgp_vty_return (vty, ret); +} + +/* neighbor default-originate. */ +DEFUN (neighbor_default_originate, + neighbor_default_originate_cmd, + NEIGHBOR_CMD2 "default-originate", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Originate default route to this neighbor\n") +{ + return peer_default_originate_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), NULL, 1); +} + +DEFUN (neighbor_default_originate_rmap, + neighbor_default_originate_rmap_cmd, + NEIGHBOR_CMD2 "default-originate route-map WORD", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Originate default route to this neighbor\n" + "Route-map to specify criteria to originate default\n" + "route-map name\n") +{ + return peer_default_originate_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[1], 1); +} + +DEFUN (no_neighbor_default_originate, + no_neighbor_default_originate_cmd, + NO_NEIGHBOR_CMD2 "default-originate", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Originate default route to this neighbor\n") +{ + return peer_default_originate_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), NULL, 0); +} + +ALIAS (no_neighbor_default_originate, + no_neighbor_default_originate_rmap_cmd, + NO_NEIGHBOR_CMD2 "default-originate route-map WORD", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Originate default route to this neighbor\n" + "Route-map to specify criteria to originate default\n" + "route-map name\n") + +/* Set neighbor's BGP port. */ +int +peer_port_vty (struct vty *vty, char *ip_str, int afi, char *port_str) +{ + struct peer *peer; + u_int16_t port; + struct servent *sp; + + peer = peer_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + if (! port_str) + { + sp = getservbyname ("bgp", "tcp"); + port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs (sp->s_port); + } + else + { + VTY_GET_INTEGER("port", port, port_str); + } + + peer_port_set (peer, port); + + return CMD_SUCCESS; +} + +/* Set specified peer's BGP 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") + +/* 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") + +/* Override capability negotiation. */ +DEFUN (neighbor_override_capability, + neighbor_override_capability_cmd, + NEIGHBOR_CMD2 "override-capability", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Override capability negotiation result\n") +{ + return peer_flag_set_vty (vty, argv[0], PEER_FLAG_OVERRIDE_CAPABILITY); +} + +DEFUN (no_neighbor_override_capability, + no_neighbor_override_capability_cmd, + NO_NEIGHBOR_CMD2 "override-capability", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Override capability negotiation result\n") +{ + return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_OVERRIDE_CAPABILITY); +} + +DEFUN (neighbor_strict_capability, + neighbor_strict_capability_cmd, + NEIGHBOR_CMD "strict-capability-match", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Strict capability negotiation match\n") +{ + return peer_flag_set_vty (vty, argv[0], PEER_FLAG_STRICT_CAP_MATCH); +} + +DEFUN (no_neighbor_strict_capability, + no_neighbor_strict_capability_cmd, + NO_NEIGHBOR_CMD "strict-capability-match", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Strict capability negotiation match\n") +{ + return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_STRICT_CAP_MATCH); +} + +int +peer_timers_set_vty (struct vty *vty, char *ip_str, char *keep_str, + char *hold_str) +{ + int ret; + struct peer *peer; + u_int32_t keepalive; + u_int32_t holdtime; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + VTY_GET_INTEGER_RANGE ("Keepalive", keepalive, keep_str, 0, 65535); + VTY_GET_INTEGER_RANGE ("Holdtime", holdtime, hold_str, 0, 65535); + + ret = peer_timers_set (peer, keepalive, holdtime); + + return bgp_vty_return (vty, ret); +} + +int +peer_timers_unset_vty (struct vty *vty, char *ip_str) +{ + int ret; + struct peer *peer; + + peer = peer_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + ret = peer_timers_unset (peer); + + return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_timers, + neighbor_timers_cmd, + NEIGHBOR_CMD2 "timers <0-65535> <0-65535>", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP per neighbor timers\n" + "Keepalive interval\n" + "Holdtime\n") +{ + return peer_timers_set_vty (vty, argv[0], argv[1], argv[2]); +} + +DEFUN (no_neighbor_timers, + no_neighbor_timers_cmd, + NO_NEIGHBOR_CMD2 "timers", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP per neighbor timers\n") +{ + return peer_timers_unset_vty (vty, argv[0]); +} + +int +peer_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") + +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") + +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); +} + +/* neighbor interface */ +int +peer_interface_vty (struct vty *vty, char *ip_str, char *str) +{ + int ret; + struct peer *peer; + + peer = peer_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + if (str) + ret = peer_interface_set (peer, str); + else + ret = peer_interface_unset (peer); + + return CMD_SUCCESS; +} + +DEFUN (neighbor_interface, + neighbor_interface_cmd, + NEIGHBOR_CMD "interface WORD", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Interface\n" + "Interface name\n") +{ + return peer_interface_vty (vty, argv[0], argv[1]); +} + +DEFUN (no_neighbor_interface, + no_neighbor_interface_cmd, + NO_NEIGHBOR_CMD "interface WORD", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Interface\n" + "Interface name\n") +{ + return peer_interface_vty (vty, argv[0], NULL); +} + +/* Set distribute list to the peer. */ +int +peer_distribute_set_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi, + char *name_str, char *direct_str) +{ + int ret; + struct peer *peer; + int direct = FILTER_IN; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + /* Check filter direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = FILTER_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = FILTER_OUT; + + ret = peer_distribute_set (peer, afi, safi, direct, name_str); + + return bgp_vty_return (vty, ret); +} + +int +peer_distribute_unset_vty (struct vty *vty, char *ip_str, afi_t afi, + safi_t safi, char *direct_str) +{ + int ret; + struct peer *peer; + int direct = FILTER_IN; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + /* Check filter direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = FILTER_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = FILTER_OUT; + + ret = peer_distribute_unset (peer, afi, safi, direct); + + return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_distribute_list, + neighbor_distribute_list_cmd, + NEIGHBOR_CMD2 "distribute-list (<1-199>|<1300-2699>|WORD) (in|out)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Filter updates to/from this neighbor\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n" + "Filter incoming updates\n" + "Filter outgoing updates\n") +{ + return peer_distribute_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[1], argv[2]); +} + +DEFUN (no_neighbor_distribute_list, + no_neighbor_distribute_list_cmd, + NO_NEIGHBOR_CMD2 "distribute-list (<1-199>|<1300-2699>|WORD) (in|out)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Filter updates to/from this neighbor\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n" + "Filter incoming updates\n" + "Filter outgoing updates\n") +{ + return peer_distribute_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[2]); +} + +/* Set prefix list to the peer. */ +int +peer_prefix_list_set_vty (struct vty *vty, char *ip_str, afi_t afi, + safi_t safi, char *name_str, char *direct_str) +{ + int ret; + struct peer *peer; + int direct = FILTER_IN; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + /* Check filter direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = FILTER_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = FILTER_OUT; + + ret = peer_prefix_list_set (peer, afi, safi, direct, name_str); + + return bgp_vty_return (vty, ret); +} + +int +peer_prefix_list_unset_vty (struct vty *vty, char *ip_str, afi_t afi, + safi_t safi, char *direct_str) +{ + int ret; + struct peer *peer; + int direct = FILTER_IN; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + /* Check filter direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = FILTER_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = FILTER_OUT; + + ret = peer_prefix_list_unset (peer, afi, safi, direct); + + return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_prefix_list, + neighbor_prefix_list_cmd, + NEIGHBOR_CMD2 "prefix-list WORD (in|out)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Filter updates to/from this neighbor\n" + "Name of a prefix list\n" + "Filter incoming updates\n" + "Filter outgoing updates\n") +{ + return peer_prefix_list_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[1], argv[2]); +} + +DEFUN (no_neighbor_prefix_list, + no_neighbor_prefix_list_cmd, + NO_NEIGHBOR_CMD2 "prefix-list WORD (in|out)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Filter updates to/from this neighbor\n" + "Name of a prefix list\n" + "Filter incoming updates\n" + "Filter outgoing updates\n") +{ + return peer_prefix_list_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[2]); +} + +int +peer_aslist_set_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi, + char *name_str, char *direct_str) +{ + int ret; + struct peer *peer; + int direct = FILTER_IN; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + /* Check filter direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = FILTER_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = FILTER_OUT; + + ret = peer_aslist_set (peer, afi, safi, direct, name_str); + + return bgp_vty_return (vty, ret); +} + +int +peer_aslist_unset_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi, + char *direct_str) +{ + int ret; + struct peer *peer; + int direct = FILTER_IN; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + /* Check filter direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = FILTER_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = FILTER_OUT; + + ret = peer_aslist_unset (peer, afi, safi, direct); + + return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_filter_list, + neighbor_filter_list_cmd, + NEIGHBOR_CMD2 "filter-list WORD (in|out)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Establish BGP filters\n" + "AS path access-list name\n" + "Filter incoming routes\n" + "Filter outgoing routes\n") +{ + return peer_aslist_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[1], argv[2]); +} + +DEFUN (no_neighbor_filter_list, + no_neighbor_filter_list_cmd, + NO_NEIGHBOR_CMD2 "filter-list WORD (in|out)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Establish BGP filters\n" + "AS path access-list name\n" + "Filter incoming routes\n" + "Filter outgoing routes\n") +{ + return peer_aslist_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[2]); +} + +/* Set route-map to the peer. */ +int +peer_route_map_set_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi, + char *name_str, char *direct_str) +{ + int ret; + struct peer *peer; + int direct = FILTER_IN; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + /* Check filter direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = FILTER_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = FILTER_OUT; + + ret = peer_route_map_set (peer, afi, safi, direct, name_str); + + return bgp_vty_return (vty, ret); +} + +int +peer_route_map_unset_vty (struct vty *vty, char *ip_str, afi_t afi, + safi_t safi, char *direct_str) +{ + int ret; + struct peer *peer; + int direct = FILTER_IN; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + /* Check filter direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = FILTER_IN; + else if (strncmp (direct_str, "o", 1) == 0) + + direct = FILTER_OUT; + + ret = peer_route_map_unset (peer, afi, safi, direct); + + return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_route_map, + neighbor_route_map_cmd, + NEIGHBOR_CMD2 "route-map WORD (in|out)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Apply route map to neighbor\n" + "Name of route map\n" + "Apply map to incoming routes\n" + "Apply map to outbound routes\n") +{ + return peer_route_map_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[1], argv[2]); +} + +DEFUN (no_neighbor_route_map, + no_neighbor_route_map_cmd, + NO_NEIGHBOR_CMD2 "route-map WORD (in|out)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Apply route map to neighbor\n" + "Name of route map\n" + "Apply map to incoming routes\n" + "Apply map to outbound routes\n") +{ + return peer_route_map_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[2]); +} + +/* Set unsuppress-map to the peer. */ +int +peer_unsuppress_map_set_vty (struct vty *vty, char *ip_str, afi_t afi, + safi_t safi, char *name_str) +{ + int ret; + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + ret = peer_unsuppress_map_set (peer, afi, safi, name_str); + + return bgp_vty_return (vty, ret); +} + +/* Unset route-map from the peer. */ +int +peer_unsuppress_map_unset_vty (struct vty *vty, char *ip_str, afi_t afi, + safi_t safi) +{ + int ret; + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + ret = peer_unsuppress_map_unset (peer, afi, safi); + + return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_unsuppress_map, + neighbor_unsuppress_map_cmd, + NEIGHBOR_CMD2 "unsuppress-map WORD", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Route-map to selectively unsuppress suppressed routes\n" + "Name of route map\n") +{ + return peer_unsuppress_map_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[1]); +} + +DEFUN (no_neighbor_unsuppress_map, + no_neighbor_unsuppress_map_cmd, + NO_NEIGHBOR_CMD2 "unsuppress-map WORD", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Route-map to selectively unsuppress suppressed routes\n" + "Name of route map\n") +{ + return peer_unsuppress_map_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty)); +} + +int +peer_maximum_prefix_set_vty (struct vty *vty, char *ip_str, afi_t afi, + safi_t safi, char *num_str, 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") + +/* "neighbor allowas-in" */ +DEFUN (neighbor_allowas_in, + neighbor_allowas_in_cmd, + NEIGHBOR_CMD2 "allowas-in", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Accept as-path with my AS present in it\n") +{ + int ret; + struct peer *peer; + int allow_num; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + if (argc == 1) + allow_num = 3; + else + VTY_GET_INTEGER_RANGE ("AS number", allow_num, argv[1], 1, 10); + + ret = peer_allowas_in_set (peer, bgp_node_afi (vty), bgp_node_safi (vty), + allow_num); + + return bgp_vty_return (vty, ret); +} + +ALIAS (neighbor_allowas_in, + neighbor_allowas_in_arg_cmd, + NEIGHBOR_CMD2 "allowas-in <1-10>", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Accept as-path with my AS present in it\n" + "Number of occurances of AS number\n") + +DEFUN (no_neighbor_allowas_in, + no_neighbor_allowas_in_cmd, + NO_NEIGHBOR_CMD2 "allowas-in", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "allow local ASN appears in aspath attribute\n") +{ + int ret; + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + ret = peer_allowas_in_unset (peer, bgp_node_afi (vty), bgp_node_safi (vty)); + + return bgp_vty_return (vty, ret); +} + +/* Address family configuration. */ +DEFUN (address_family_ipv4, + address_family_ipv4_cmd, + "address-family ipv4", + "Enter Address Family command mode\n" + "Address family\n") +{ + vty->node = BGP_IPV4_NODE; + return CMD_SUCCESS; +} + +DEFUN (address_family_ipv4_safi, + address_family_ipv4_safi_cmd, + "address-family ipv4 (unicast|multicast)", + "Enter Address Family command mode\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + vty->node = BGP_IPV4M_NODE; + else + vty->node = BGP_IPV4_NODE; + + return CMD_SUCCESS; +} + +DEFUN (address_family_ipv6_unicast, + address_family_ipv6_unicast_cmd, + "address-family ipv6 unicast", + "Enter Address Family command mode\n" + "Address family\n" + "unicast\n") +{ + vty->node = BGP_IPV6_NODE; + return CMD_SUCCESS; +} + +ALIAS (address_family_ipv6_unicast, + address_family_ipv6_cmd, + "address-family ipv6", + "Enter Address Family command mode\n" + "Address family\n") + +DEFUN (address_family_vpnv4, + address_family_vpnv4_cmd, + "address-family vpnv4", + "Enter Address Family command mode\n" + "Address family\n") +{ + vty->node = BGP_VPNV4_NODE; + return CMD_SUCCESS; +} + +ALIAS (address_family_vpnv4, + address_family_vpnv4_unicast_cmd, + "address-family vpnv4 unicast", + "Enter Address Family command mode\n" + "Address family\n" + "Address Family Modifier\n") + +DEFUN (exit_address_family, + exit_address_family_cmd, + "exit-address-family", + "Exit from Address Family configuration mode\n") +{ + if (vty->node == BGP_IPV4M_NODE + || vty->node == BGP_VPNV4_NODE + || vty->node == BGP_IPV6_NODE) + vty->node = BGP_NODE; + return CMD_SUCCESS; +} + +/* BGP clear sort. */ +enum clear_sort +{ + clear_all, + clear_peer, + clear_group, + clear_external, + clear_as +}; + +void +bgp_clear_vty_error (struct vty *vty, struct peer *peer, afi_t afi, + safi_t safi, int error) +{ + switch (error) + { + case BGP_ERR_AF_UNCONFIGURED: + vty_out (vty, + "%%BGP: Enable %s %s address family for the neighbor %s%s", + afi == AFI_IP6 ? "IPv6" : safi == SAFI_MPLS_VPN ? "VPNv4" : "IPv4", + safi == SAFI_MULTICAST ? "Multicast" : "Unicast", + peer->host, VTY_NEWLINE); + break; + case BGP_ERR_SOFT_RECONFIG_UNCONFIGURED: + vty_out (vty, "%%BGP: Inbound soft reconfig for %s not possible as it%s has neither refresh capability, nor inbound soft reconfig%s", peer->host, VTY_NEWLINE, VTY_NEWLINE); + break; + default: + break; + } +} + +/* `clear ip bgp' functions. */ +int +bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, + enum clear_sort sort,enum bgp_clear_type stype, char *arg) +{ + int ret; + struct peer *peer; + struct listnode *nn; + + /* Clear all neighbors. */ + if (sort == clear_all) + { + LIST_LOOP (bgp->peer, peer, nn) + { + if (stype == BGP_CLEAR_SOFT_NONE) + ret = peer_clear (peer); + else + ret = peer_clear_soft (peer, afi, safi, stype); + + if (ret < 0) + bgp_clear_vty_error (vty, peer, afi, safi, ret); + } + return 0; + } + + /* Clear specified neighbors. */ + if (sort == clear_peer) + { + union sockunion su; + int ret; + + /* Make sockunion for lookup. */ + ret = str2sockunion (arg, &su); + if (ret < 0) + { + vty_out (vty, "Malformed address: %s%s", arg, VTY_NEWLINE); + return -1; + } + peer = peer_lookup (bgp, &su); + if (! peer) + { + vty_out (vty, "%%BGP: Unknown neighbor - \"%s\"%s", arg, VTY_NEWLINE); + return -1; + } + + if (stype == BGP_CLEAR_SOFT_NONE) + ret = peer_clear (peer); + else + ret = peer_clear_soft (peer, afi, safi, stype); + + if (ret < 0) + bgp_clear_vty_error (vty, peer, afi, safi, ret); + + return 0; + } + + /* Clear all peer-group members. */ + if (sort == clear_group) + { + struct peer_group *group; + + group = peer_group_lookup (bgp, arg); + if (! group) + { + vty_out (vty, "%%BGP: No such peer-group %s%s", arg, VTY_NEWLINE); + return -1; + } + + LIST_LOOP (group->peer, peer, nn) + { + if (stype == BGP_CLEAR_SOFT_NONE) + { + ret = peer_clear (peer); + continue; + } + + 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") + +/* Outbound soft-reconfiguration */ +DEFUN (clear_ip_bgp_all_soft_out, + clear_ip_bgp_all_soft_out_cmd, + "clear ip bgp * soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + if (argc == 1) + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_ip_bgp_all_soft_out, + clear_ip_bgp_all_out_cmd, + "clear ip bgp * out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig outbound update\n") + +ALIAS (clear_ip_bgp_all_soft_out, + clear_ip_bgp_instance_all_soft_out_cmd, + "clear ip bgp view WORD * soft out", + CLEAR_STR + IP_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_all_ipv4_soft_out, + clear_ip_bgp_all_ipv4_soft_out_cmd, + "clear ip bgp * ipv4 (unicast|multicast) soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_ip_bgp_all_ipv4_soft_out, + clear_ip_bgp_all_ipv4_out_cmd, + "clear ip bgp * ipv4 (unicast|multicast) out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_instance_all_ipv4_soft_out, + clear_ip_bgp_instance_all_ipv4_soft_out_cmd, + "clear ip bgp view WORD * ipv4 (unicast|multicast) soft out", + CLEAR_STR + IP_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); + + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); +} + +DEFUN (clear_ip_bgp_all_vpnv4_soft_out, + clear_ip_bgp_all_vpnv4_soft_out_cmd, + "clear ip bgp * vpnv4 unicast soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_ip_bgp_all_vpnv4_soft_out, + clear_ip_bgp_all_vpnv4_out_cmd, + "clear ip bgp * vpnv4 unicast out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig outbound update\n") + +DEFUN (clear_bgp_all_soft_out, + clear_bgp_all_soft_out_cmd, + "clear bgp * soft out", + CLEAR_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + if (argc == 1) + return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_bgp_all_soft_out, + clear_bgp_instance_all_soft_out_cmd, + "clear bgp view WORD * soft out", + CLEAR_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_all_soft_out, + clear_bgp_all_out_cmd, + "clear bgp * out", + CLEAR_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_all_soft_out, + clear_bgp_ipv6_all_soft_out_cmd, + "clear bgp ipv6 * soft out", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_all_soft_out, + clear_bgp_ipv6_all_out_cmd, + "clear bgp ipv6 * out", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all peers\n" + "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_peer_soft_out, + clear_ip_bgp_peer_soft_out_cmd, + "clear ip bgp A.B.C.D soft out", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_soft_out, + clear_ip_bgp_peer_out_cmd, + "clear ip bgp A.B.C.D out", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_peer_ipv4_soft_out, + clear_ip_bgp_peer_ipv4_soft_out_cmd, + "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft out", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, + BGP_CLEAR_SOFT_OUT, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_ipv4_soft_out, + clear_ip_bgp_peer_ipv4_out_cmd, + "clear ip bgp A.B.C.D ipv4 (unicast|multicast) out", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_peer_vpnv4_soft_out, + clear_ip_bgp_peer_vpnv4_soft_out_cmd, + "clear ip bgp A.B.C.D vpnv4 unicast soft out", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_vpnv4_soft_out, + clear_ip_bgp_peer_vpnv4_out_cmd, + "clear ip bgp A.B.C.D vpnv4 unicast out", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig outbound update\n") + +DEFUN (clear_bgp_peer_soft_out, + clear_bgp_peer_soft_out_cmd, + "clear bgp (A.B.C.D|X:X::X:X) soft out", + CLEAR_STR + BGP_STR + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_bgp_peer_soft_out, + clear_bgp_ipv6_peer_soft_out_cmd, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft out", + CLEAR_STR + BGP_STR + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_peer_soft_out, + clear_bgp_peer_out_cmd, + "clear bgp (A.B.C.D|X:X::X:X) out", + CLEAR_STR + BGP_STR + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_peer_soft_out, + clear_bgp_ipv6_peer_out_cmd, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) out", + CLEAR_STR + BGP_STR + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_peer_group_soft_out, + clear_ip_bgp_peer_group_soft_out_cmd, + "clear ip bgp peer-group WORD soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_group_soft_out, + clear_ip_bgp_peer_group_out_cmd, + "clear ip bgp peer-group WORD out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_peer_group_ipv4_soft_out, + clear_ip_bgp_peer_group_ipv4_soft_out_cmd, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, + BGP_CLEAR_SOFT_OUT, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_group_ipv4_soft_out, + clear_ip_bgp_peer_group_ipv4_out_cmd, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n") + +DEFUN (clear_bgp_peer_group_soft_out, + clear_bgp_peer_group_soft_out_cmd, + "clear bgp peer-group WORD soft out", + CLEAR_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_bgp_peer_group_soft_out, + clear_bgp_ipv6_peer_group_soft_out_cmd, + "clear bgp ipv6 peer-group WORD soft out", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_peer_group_soft_out, + clear_bgp_peer_group_out_cmd, + "clear bgp peer-group WORD out", + CLEAR_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_peer_group_soft_out, + clear_bgp_ipv6_peer_group_out_cmd, + "clear bgp ipv6 peer-group WORD out", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_external_soft_out, + clear_ip_bgp_external_soft_out_cmd, + "clear ip bgp external soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_ip_bgp_external_soft_out, + clear_ip_bgp_external_out_cmd, + "clear ip bgp external out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_external_ipv4_soft_out, + clear_ip_bgp_external_ipv4_soft_out_cmd, + "clear ip bgp external ipv4 (unicast|multicast) soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, + BGP_CLEAR_SOFT_OUT, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_ip_bgp_external_ipv4_soft_out, + clear_ip_bgp_external_ipv4_out_cmd, + "clear ip bgp external ipv4 (unicast|multicast) out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n") + +DEFUN (clear_bgp_external_soft_out, + clear_bgp_external_soft_out_cmd, + "clear bgp external soft out", + CLEAR_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_bgp_external_soft_out, + clear_bgp_ipv6_external_soft_out_cmd, + "clear bgp ipv6 external soft out", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all external peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_external_soft_out, + clear_bgp_external_out_cmd, + "clear bgp external out", + CLEAR_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_external_soft_out, + clear_bgp_ipv6_external_out_cmd, + "clear bgp ipv6 external WORD out", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all external peers\n" + "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_as_soft_out, + clear_ip_bgp_as_soft_out_cmd, + "clear ip bgp <1-65535> soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_as_soft_out, + clear_ip_bgp_as_out_cmd, + "clear ip bgp <1-65535> out", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_as_ipv4_soft_out, + clear_ip_bgp_as_ipv4_soft_out_cmd, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, + BGP_CLEAR_SOFT_OUT, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_as_ipv4_soft_out, + clear_ip_bgp_as_ipv4_out_cmd, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) out", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_as_vpnv4_soft_out, + clear_ip_bgp_as_vpnv4_soft_out_cmd, + "clear ip bgp <1-65535> vpnv4 unicast soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_as_vpnv4_soft_out, + clear_ip_bgp_as_vpnv4_out_cmd, + "clear ip bgp <1-65535> vpnv4 unicast out", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n") + +DEFUN (clear_bgp_as_soft_out, + clear_bgp_as_soft_out_cmd, + "clear bgp <1-65535> soft out", + CLEAR_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_bgp_as_soft_out, + clear_bgp_ipv6_as_soft_out_cmd, + "clear bgp ipv6 <1-65535> soft out", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear peers with the AS number\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_as_soft_out, + clear_bgp_as_out_cmd, + "clear bgp <1-65535> out", + CLEAR_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_as_soft_out, + clear_bgp_ipv6_as_out_cmd, + "clear bgp ipv6 <1-65535> out", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear peers with the AS number\n" + "Soft reconfig outbound update\n") + +/* Inbound soft-reconfiguration */ +DEFUN (clear_ip_bgp_all_soft_in, + clear_ip_bgp_all_soft_in_cmd, + "clear ip bgp * soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + if (argc == 1) + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_ip_bgp_all_soft_in, + clear_ip_bgp_instance_all_soft_in_cmd, + "clear ip bgp view WORD * soft in", + CLEAR_STR + IP_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +ALIAS (clear_ip_bgp_all_soft_in, + clear_ip_bgp_all_in_cmd, + "clear ip bgp * in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_all_in_prefix_filter, + clear_ip_bgp_all_in_prefix_filter_cmd, + "clear ip bgp * in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + if (argc== 1) + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +ALIAS (clear_ip_bgp_all_in_prefix_filter, + clear_ip_bgp_instance_all_in_prefix_filter_cmd, + "clear ip bgp view WORD * in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + + +DEFUN (clear_ip_bgp_all_ipv4_soft_in, + clear_ip_bgp_all_ipv4_soft_in_cmd, + "clear ip bgp * ipv4 (unicast|multicast) soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, + BGP_CLEAR_SOFT_IN, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_ip_bgp_all_ipv4_soft_in, + clear_ip_bgp_all_ipv4_in_cmd, + "clear ip bgp * ipv4 (unicast|multicast) in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_instance_all_ipv4_soft_in, + clear_ip_bgp_instance_all_ipv4_soft_in_cmd, + "clear ip bgp view WORD * ipv4 (unicast|multicast) soft in", + CLEAR_STR + IP_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all, + BGP_CLEAR_SOFT_IN, NULL); + + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN, NULL); +} + +DEFUN (clear_ip_bgp_all_ipv4_in_prefix_filter, + clear_ip_bgp_all_ipv4_in_prefix_filter_cmd, + "clear ip bgp * ipv4 (unicast|multicast) in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +DEFUN (clear_ip_bgp_instance_all_ipv4_in_prefix_filter, + clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd, + "clear ip bgp view WORD * ipv4 (unicast|multicast) in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); + + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +DEFUN (clear_ip_bgp_all_vpnv4_soft_in, + clear_ip_bgp_all_vpnv4_soft_in_cmd, + "clear ip bgp * vpnv4 unicast soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, + BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_ip_bgp_all_vpnv4_soft_in, + clear_ip_bgp_all_vpnv4_in_cmd, + "clear ip bgp * vpnv4 unicast in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig inbound update\n") + +DEFUN (clear_bgp_all_soft_in, + clear_bgp_all_soft_in_cmd, + "clear bgp * soft in", + CLEAR_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + if (argc == 1) + return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_bgp_all_soft_in, + clear_bgp_instance_all_soft_in_cmd, + "clear bgp view WORD * soft in", + CLEAR_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_all_soft_in, + clear_bgp_ipv6_all_soft_in_cmd, + "clear bgp ipv6 * soft in", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_all_soft_in, + clear_bgp_all_in_cmd, + "clear bgp * in", + CLEAR_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_all_soft_in, + clear_bgp_ipv6_all_in_cmd, + "clear bgp ipv6 * in", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all peers\n" + "Soft reconfig inbound update\n") + +DEFUN (clear_bgp_all_in_prefix_filter, + clear_bgp_all_in_prefix_filter_cmd, + "clear bgp * in prefix-filter", + CLEAR_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +ALIAS (clear_bgp_all_in_prefix_filter, + clear_bgp_ipv6_all_in_prefix_filter_cmd, + "clear bgp ipv6 * in prefix-filter", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFUN (clear_ip_bgp_peer_soft_in, + clear_ip_bgp_peer_soft_in_cmd, + "clear ip bgp A.B.C.D soft in", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_soft_in, + clear_ip_bgp_peer_in_cmd, + "clear ip bgp A.B.C.D in", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_peer_in_prefix_filter, + clear_ip_bgp_peer_in_prefix_filter_cmd, + "clear ip bgp A.B.C.D in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Soft reconfig inbound update\n" + "Push out the existing ORF prefix-list\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +DEFUN (clear_ip_bgp_peer_ipv4_soft_in, + clear_ip_bgp_peer_ipv4_soft_in_cmd, + "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft in", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, + BGP_CLEAR_SOFT_IN, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_ipv4_soft_in, + clear_ip_bgp_peer_ipv4_in_cmd, + "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_peer_ipv4_in_prefix_filter, + clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd, + "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n" + "Push out the existing ORF prefix-list\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +DEFUN (clear_ip_bgp_peer_vpnv4_soft_in, + clear_ip_bgp_peer_vpnv4_soft_in_cmd, + "clear ip bgp A.B.C.D vpnv4 unicast soft in", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_vpnv4_soft_in, + clear_ip_bgp_peer_vpnv4_in_cmd, + "clear ip bgp A.B.C.D vpnv4 unicast in", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig inbound update\n") + +DEFUN (clear_bgp_peer_soft_in, + clear_bgp_peer_soft_in_cmd, + "clear bgp (A.B.C.D|X:X::X:X) soft in", + CLEAR_STR + BGP_STR + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_bgp_peer_soft_in, + clear_bgp_ipv6_peer_soft_in_cmd, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft in", + CLEAR_STR + BGP_STR + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_peer_soft_in, + clear_bgp_peer_in_cmd, + "clear bgp (A.B.C.D|X:X::X:X) in", + CLEAR_STR + BGP_STR + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_peer_soft_in, + clear_bgp_ipv6_peer_in_cmd, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) in", + CLEAR_STR + BGP_STR + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig inbound update\n") + +DEFUN (clear_bgp_peer_in_prefix_filter, + clear_bgp_peer_in_prefix_filter_cmd, + "clear bgp (A.B.C.D|X:X::X:X) in prefix-filter", + CLEAR_STR + BGP_STR + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig inbound update\n" + "Push out the existing ORF prefix-list\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +ALIAS (clear_bgp_peer_in_prefix_filter, + clear_bgp_ipv6_peer_in_prefix_filter_cmd, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) in prefix-filter", + CLEAR_STR + BGP_STR + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig inbound update\n" + "Push out the existing ORF prefix-list\n") + +DEFUN (clear_ip_bgp_peer_group_soft_in, + clear_ip_bgp_peer_group_soft_in_cmd, + "clear ip bgp peer-group WORD soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_group_soft_in, + clear_ip_bgp_peer_group_in_cmd, + "clear ip bgp peer-group WORD in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_peer_group_in_prefix_filter, + clear_ip_bgp_peer_group_in_prefix_filter_cmd, + "clear ip bgp peer-group WORD in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +DEFUN (clear_ip_bgp_peer_group_ipv4_soft_in, + clear_ip_bgp_peer_group_ipv4_soft_in_cmd, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, + BGP_CLEAR_SOFT_IN, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_group_ipv4_soft_in, + clear_ip_bgp_peer_group_ipv4_in_cmd, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_peer_group_ipv4_in_prefix_filter, + clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +DEFUN (clear_bgp_peer_group_soft_in, + clear_bgp_peer_group_soft_in_cmd, + "clear bgp peer-group WORD soft in", + CLEAR_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_bgp_peer_group_soft_in, + clear_bgp_ipv6_peer_group_soft_in_cmd, + "clear bgp ipv6 peer-group WORD soft in", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_peer_group_soft_in, + clear_bgp_peer_group_in_cmd, + "clear bgp peer-group WORD in", + CLEAR_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_peer_group_soft_in, + clear_bgp_ipv6_peer_group_in_cmd, + "clear bgp ipv6 peer-group WORD in", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig inbound update\n") + +DEFUN (clear_bgp_peer_group_in_prefix_filter, + clear_bgp_peer_group_in_prefix_filter_cmd, + "clear bgp peer-group WORD in prefix-filter", + CLEAR_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +ALIAS (clear_bgp_peer_group_in_prefix_filter, + clear_bgp_ipv6_peer_group_in_prefix_filter_cmd, + "clear bgp ipv6 peer-group WORD in prefix-filter", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFUN (clear_ip_bgp_external_soft_in, + clear_ip_bgp_external_soft_in_cmd, + "clear ip bgp external soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_ip_bgp_external_soft_in, + clear_ip_bgp_external_in_cmd, + "clear ip bgp external in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_external_in_prefix_filter, + clear_ip_bgp_external_in_prefix_filter_cmd, + "clear ip bgp external in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +DEFUN (clear_ip_bgp_external_ipv4_soft_in, + clear_ip_bgp_external_ipv4_soft_in_cmd, + "clear ip bgp external ipv4 (unicast|multicast) soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, + BGP_CLEAR_SOFT_IN, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_ip_bgp_external_ipv4_soft_in, + clear_ip_bgp_external_ipv4_in_cmd, + "clear ip bgp external ipv4 (unicast|multicast) in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_external_ipv4_in_prefix_filter, + clear_ip_bgp_external_ipv4_in_prefix_filter_cmd, + "clear ip bgp external ipv4 (unicast|multicast) in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +DEFUN (clear_bgp_external_soft_in, + clear_bgp_external_soft_in_cmd, + "clear bgp external soft in", + CLEAR_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_bgp_external_soft_in, + clear_bgp_ipv6_external_soft_in_cmd, + "clear bgp ipv6 external soft in", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all external peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_external_soft_in, + clear_bgp_external_in_cmd, + "clear bgp external in", + CLEAR_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_external_soft_in, + clear_bgp_ipv6_external_in_cmd, + "clear bgp ipv6 external WORD in", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all external peers\n" + "Soft reconfig inbound update\n") + +DEFUN (clear_bgp_external_in_prefix_filter, + clear_bgp_external_in_prefix_filter_cmd, + "clear bgp external in prefix-filter", + CLEAR_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +ALIAS (clear_bgp_external_in_prefix_filter, + clear_bgp_ipv6_external_in_prefix_filter_cmd, + "clear bgp ipv6 external in prefix-filter", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all external peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFUN (clear_ip_bgp_as_soft_in, + clear_ip_bgp_as_soft_in_cmd, + "clear ip bgp <1-65535> soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_as_soft_in, + clear_ip_bgp_as_in_cmd, + "clear ip bgp <1-65535> in", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_as_in_prefix_filter, + clear_ip_bgp_as_in_prefix_filter_cmd, + "clear ip bgp <1-65535> in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +DEFUN (clear_ip_bgp_as_ipv4_soft_in, + clear_ip_bgp_as_ipv4_soft_in_cmd, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, + BGP_CLEAR_SOFT_IN, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_as_ipv4_soft_in, + clear_ip_bgp_as_ipv4_in_cmd, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) in", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_as_ipv4_in_prefix_filter, + clear_ip_bgp_as_ipv4_in_prefix_filter_cmd, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +DEFUN (clear_ip_bgp_as_vpnv4_soft_in, + clear_ip_bgp_as_vpnv4_soft_in_cmd, + "clear ip bgp <1-65535> vpnv4 unicast soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_as_vpnv4_soft_in, + clear_ip_bgp_as_vpnv4_in_cmd, + "clear ip bgp <1-65535> vpnv4 unicast in", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n") + +DEFUN (clear_bgp_as_soft_in, + clear_bgp_as_soft_in_cmd, + "clear bgp <1-65535> soft in", + CLEAR_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_bgp_as_soft_in, + clear_bgp_ipv6_as_soft_in_cmd, + "clear bgp ipv6 <1-65535> soft in", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear peers with the AS number\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_as_soft_in, + clear_bgp_as_in_cmd, + "clear bgp <1-65535> in", + CLEAR_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_as_soft_in, + clear_bgp_ipv6_as_in_cmd, + "clear bgp ipv6 <1-65535> in", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear peers with the AS number\n" + "Soft reconfig inbound update\n") + +DEFUN (clear_bgp_as_in_prefix_filter, + clear_bgp_as_in_prefix_filter_cmd, + "clear bgp <1-65535> in prefix-filter", + CLEAR_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +ALIAS (clear_bgp_as_in_prefix_filter, + clear_bgp_ipv6_as_in_prefix_filter_cmd, + "clear bgp ipv6 <1-65535> in prefix-filter", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear peers with the AS number\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +/* Both soft-reconfiguration */ +DEFUN (clear_ip_bgp_all_soft, + clear_ip_bgp_all_soft_cmd, + "clear ip bgp * soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig\n") +{ + if (argc == 1) + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_BOTH, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_BOTH, NULL); +} + +ALIAS (clear_ip_bgp_all_soft, + clear_ip_bgp_instance_all_soft_cmd, + "clear ip bgp view WORD * soft", + CLEAR_STR + IP_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig\n") + + +DEFUN (clear_ip_bgp_all_ipv4_soft, + clear_ip_bgp_all_ipv4_soft_cmd, + "clear ip bgp * ipv4 (unicast|multicast) soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Soft reconfig\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, + BGP_CLEAR_SOFT_BOTH, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_BOTH, NULL); +} + +DEFUN (clear_ip_bgp_instance_all_ipv4_soft, + clear_ip_bgp_instance_all_ipv4_soft_cmd, + "clear ip bgp view WORD * ipv4 (unicast|multicast) soft", + CLEAR_STR + IP_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Soft reconfig\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, + BGP_CLEAR_SOFT_BOTH, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_BOTH, NULL); +} + +DEFUN (clear_ip_bgp_all_vpnv4_soft, + clear_ip_bgp_all_vpnv4_soft_cmd, + "clear ip bgp * vpnv4 unicast soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_bgp_all_soft, + clear_bgp_all_soft_cmd, + "clear bgp * soft", + CLEAR_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig\n") +{ + if (argc == 1) + return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_BOTH, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +ALIAS (clear_bgp_all_soft, + clear_bgp_instance_all_soft_cmd, + "clear bgp view WORD * soft", + CLEAR_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig\n") + +ALIAS (clear_bgp_all_soft, + clear_bgp_ipv6_all_soft_cmd, + "clear bgp ipv6 * soft", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all peers\n" + "Soft reconfig\n") + +DEFUN (clear_ip_bgp_peer_soft, + clear_ip_bgp_peer_soft_cmd, + "clear ip bgp A.B.C.D soft", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_ip_bgp_peer_ipv4_soft, + clear_ip_bgp_peer_ipv4_soft_cmd, + "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Soft reconfig\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, + BGP_CLEAR_SOFT_BOTH, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_ip_bgp_peer_vpnv4_soft, + clear_ip_bgp_peer_vpnv4_soft_cmd, + "clear ip bgp A.B.C.D vpnv4 unicast soft", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_bgp_peer_soft, + clear_bgp_peer_soft_cmd, + "clear bgp (A.B.C.D|X:X::X:X) soft", + CLEAR_STR + BGP_STR + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +ALIAS (clear_bgp_peer_soft, + clear_bgp_ipv6_peer_soft_cmd, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft", + CLEAR_STR + BGP_STR + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n") + +DEFUN (clear_ip_bgp_peer_group_soft, + clear_ip_bgp_peer_group_soft_cmd, + "clear ip bgp peer-group WORD soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_ip_bgp_peer_group_ipv4_soft, + clear_ip_bgp_peer_group_ipv4_soft_cmd, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, + BGP_CLEAR_SOFT_BOTH, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_bgp_peer_group_soft, + clear_bgp_peer_group_soft_cmd, + "clear bgp peer-group WORD soft", + CLEAR_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +ALIAS (clear_bgp_peer_group_soft, + clear_bgp_ipv6_peer_group_soft_cmd, + "clear bgp ipv6 peer-group WORD soft", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n") + +DEFUN (clear_ip_bgp_external_soft, + clear_ip_bgp_external_soft_cmd, + "clear ip bgp external soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_BOTH, NULL); +} + +DEFUN (clear_ip_bgp_external_ipv4_soft, + clear_ip_bgp_external_ipv4_soft_cmd, + "clear ip bgp external ipv4 (unicast|multicast) soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, + BGP_CLEAR_SOFT_BOTH, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_BOTH, NULL); +} + +DEFUN (clear_bgp_external_soft, + clear_bgp_external_soft_cmd, + "clear bgp external soft", + CLEAR_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_BOTH, NULL); +} + +ALIAS (clear_bgp_external_soft, + clear_bgp_ipv6_external_soft_cmd, + "clear bgp ipv6 external soft", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all external peers\n" + "Soft reconfig\n") + +DEFUN (clear_ip_bgp_as_soft, + clear_ip_bgp_as_soft_cmd, + "clear ip bgp <1-65535> soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_ip_bgp_as_ipv4_soft, + clear_ip_bgp_as_ipv4_soft_cmd, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Soft reconfig\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, + BGP_CLEAR_SOFT_BOTH, argv[0]); + + return bgp_clear_vty (vty, NULL,AFI_IP, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_ip_bgp_as_vpnv4_soft, + clear_ip_bgp_as_vpnv4_soft_cmd, + "clear ip bgp <1-65535> vpnv4 unicast soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_bgp_as_soft, + clear_bgp_as_soft_cmd, + "clear bgp <1-65535> soft", + CLEAR_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +ALIAS (clear_bgp_as_soft, + clear_bgp_ipv6_as_soft_cmd, + "clear bgp ipv6 <1-65535> soft", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear peers with the AS number\n" + "Soft reconfig\n") + +/* Show BGP peer's summary information. */ +int +bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi) +{ + struct peer *peer; + struct listnode *nn; + int count = 0; + char timebuf[BGP_UPTIME_LEN]; + int len; + + /* Header string for each address family. */ + static char header[] = "Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd"; + + LIST_LOOP (bgp->peer, peer, nn) + { + if (peer->afc[afi][safi]) + { + if (! count) + { + vty_out (vty, + "BGP router identifier %s, local AS number %d%s", + inet_ntoa (bgp->router_id), bgp->as, VTY_NEWLINE); + vty_out (vty, + "%ld BGP AS-PATH entries%s", aspath_count (), + VTY_NEWLINE); + vty_out (vty, + "%ld BGP community entries%s", community_count (), + VTY_NEWLINE); + + if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) + vty_out (vty, "Dampening enabled.%s", VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "%s%s", header, VTY_NEWLINE); + } + count++; + + len = vty_out (vty, "%s", peer->host); + len = 16 - len; + if (len < 1) + vty_out (vty, "%s%*s", VTY_NEWLINE, 16, " "); + else + vty_out (vty, "%*s", len, " "); + + 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 */ + +/* 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]); +} + +/* Show BGP's AS paths internal data. There are both `show ip bgp + paths' and `show ip mbgp paths'. Those functions results are the + same.*/ +DEFUN (show_ip_bgp_paths, + show_ip_bgp_paths_cmd, + "show ip bgp paths", + SHOW_STR + IP_STR + BGP_STR + "Path information\n") +{ + vty_out (vty, "Address Refcnt Path%s", VTY_NEWLINE); + aspath_print_all_vty (vty); + return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_ipv4_paths, + show_ip_bgp_ipv4_paths_cmd, + "show ip bgp ipv4 (unicast|multicast) paths", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Path information\n") +{ + vty_out (vty, "Address Refcnt Path\r\n"); + aspath_print_all_vty (vty); + + return CMD_SUCCESS; +} + +#include "hash.h" + +void +community_show_all_iterator (struct hash_backet *backet, struct vty *vty) +{ + struct community *com; + + com = (struct community *) backet->data; + vty_out (vty, "[%p] (%ld) %s%s", backet, com->refcnt, + community_str (com), VTY_NEWLINE); +} + +/* Show BGP's community internal data. */ +DEFUN (show_ip_bgp_community_info, + show_ip_bgp_community_info_cmd, + "show ip bgp community-info", + SHOW_STR + IP_STR + BGP_STR + "List all bgp community information\n") +{ + vty_out (vty, "Address Refcnt Community%s", VTY_NEWLINE); + + hash_iterate (community_hash (), + (void (*) (struct hash_backet *, void *)) + community_show_all_iterator, + vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_attr_info, + show_ip_bgp_attr_info_cmd, + "show ip bgp attribute-info", + SHOW_STR + IP_STR + BGP_STR + "List all bgp attribute information\n") +{ + attr_show_all (vty); + return CMD_SUCCESS; +} + +/* Redistribute VTY commands. */ + +/* Utility function to convert user input route type string to route + type. */ +static int +bgp_str2route_type (int afi, char *str) +{ + if (! str) + return 0; + + if (afi == AFI_IP) + { + if (strncmp (str, "k", 1) == 0) + return ZEBRA_ROUTE_KERNEL; + else if (strncmp (str, "c", 1) == 0) + return ZEBRA_ROUTE_CONNECT; + else if (strncmp (str, "s", 1) == 0) + return ZEBRA_ROUTE_STATIC; + else if (strncmp (str, "r", 1) == 0) + return ZEBRA_ROUTE_RIP; + else if (strncmp (str, "o", 1) == 0) + return ZEBRA_ROUTE_OSPF; + } + if (afi == AFI_IP6) + { + if (strncmp (str, "k", 1) == 0) + return ZEBRA_ROUTE_KERNEL; + else if (strncmp (str, "c", 1) == 0) + return ZEBRA_ROUTE_CONNECT; + else if (strncmp (str, "s", 1) == 0) + return ZEBRA_ROUTE_STATIC; + else if (strncmp (str, "r", 1) == 0) + return ZEBRA_ROUTE_RIPNG; + else if (strncmp (str, "o", 1) == 0) + return ZEBRA_ROUTE_OSPF6; + } + return 0; +} + +DEFUN (bgp_redistribute_ipv4, + bgp_redistribute_ipv4_cmd, + "redistribute (connected|kernel|ospf|rip|static)", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_redistribute_set (vty->index, AFI_IP, type); +} + +DEFUN (bgp_redistribute_ipv4_rmap, + bgp_redistribute_ipv4_rmap_cmd, + "redistribute (connected|kernel|ospf|rip|static) route-map WORD", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_redistribute_rmap_set (vty->index, AFI_IP, type, argv[1]); + return bgp_redistribute_set (vty->index, AFI_IP, type); +} + +DEFUN (bgp_redistribute_ipv4_metric, + bgp_redistribute_ipv4_metric_cmd, + "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n") +{ + int type; + u_int32_t metric; + + type = bgp_str2route_type (AFI_IP, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + VTY_GET_INTEGER ("metric", metric, argv[1]); + + bgp_redistribute_metric_set (vty->index, AFI_IP, type, metric); + return bgp_redistribute_set (vty->index, AFI_IP, type); +} + +DEFUN (bgp_redistribute_ipv4_rmap_metric, + bgp_redistribute_ipv4_rmap_metric_cmd, + "redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n" + "Metric for redistributed routes\n" + "Default metric\n") +{ + int type; + u_int32_t metric; + + type = bgp_str2route_type (AFI_IP, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + VTY_GET_INTEGER ("metric", metric, argv[2]); + + bgp_redistribute_rmap_set (vty->index, AFI_IP, type, argv[1]); + bgp_redistribute_metric_set (vty->index, AFI_IP, type, metric); + return bgp_redistribute_set (vty->index, AFI_IP, type); +} + +DEFUN (bgp_redistribute_ipv4_metric_rmap, + bgp_redistribute_ipv4_metric_rmap_cmd, + "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int type; + u_int32_t metric; + + type = bgp_str2route_type (AFI_IP, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + VTY_GET_INTEGER ("metric", metric, argv[1]); + + bgp_redistribute_metric_set (vty->index, AFI_IP, type, metric); + bgp_redistribute_rmap_set (vty->index, AFI_IP, type, argv[2]); + return bgp_redistribute_set (vty->index, AFI_IP, type); +} + +DEFUN (no_bgp_redistribute_ipv4, + no_bgp_redistribute_ipv4_cmd, + "no redistribute (connected|kernel|ospf|rip|static)", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_redistribute_unset (vty->index, AFI_IP, type); +} + +DEFUN (no_bgp_redistribute_ipv4_rmap, + no_bgp_redistribute_ipv4_rmap_cmd, + "no redistribute (connected|kernel|ospf|rip|static) route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_redistribute_routemap_unset (vty->index, AFI_IP, type); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_redistribute_ipv4_metric, + no_bgp_redistribute_ipv4_metric_cmd, + "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_redistribute_metric_unset (vty->index, AFI_IP, type); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_redistribute_ipv4_rmap_metric, + no_bgp_redistribute_ipv4_rmap_metric_cmd, + "no redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n" + "Metric for redistributed routes\n" + "Default metric\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_redistribute_metric_unset (vty->index, AFI_IP, type); + bgp_redistribute_routemap_unset (vty->index, AFI_IP, type); + return CMD_SUCCESS; +} + +ALIAS (no_bgp_redistribute_ipv4_rmap_metric, + no_bgp_redistribute_ipv4_metric_rmap_cmd, + "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +#ifdef HAVE_IPV6 +DEFUN (bgp_redistribute_ipv6, + bgp_redistribute_ipv6_cmd, + "redistribute (connected|kernel|ospf6|ripng|static)", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP6, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_redistribute_set (vty->index, AFI_IP6, type); +} + +DEFUN (bgp_redistribute_ipv6_rmap, + bgp_redistribute_ipv6_rmap_cmd, + "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP6, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_redistribute_rmap_set (vty->index, AFI_IP6, type, argv[1]); + return bgp_redistribute_set (vty->index, AFI_IP6, type); +} + +DEFUN (bgp_redistribute_ipv6_metric, + bgp_redistribute_ipv6_metric_cmd, + "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n") +{ + int type; + u_int32_t metric; + + type = bgp_str2route_type (AFI_IP6, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + VTY_GET_INTEGER ("metric", metric, argv[1]); + + bgp_redistribute_metric_set (vty->index, AFI_IP6, type, metric); + return bgp_redistribute_set (vty->index, AFI_IP6, type); +} + +DEFUN (bgp_redistribute_ipv6_rmap_metric, + bgp_redistribute_ipv6_rmap_metric_cmd, + "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n" + "Metric for redistributed routes\n" + "Default metric\n") +{ + int type; + u_int32_t metric; + + type = bgp_str2route_type (AFI_IP6, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + VTY_GET_INTEGER ("metric", metric, argv[2]); + + bgp_redistribute_rmap_set (vty->index, AFI_IP6, type, argv[1]); + bgp_redistribute_metric_set (vty->index, AFI_IP6, type, metric); + return bgp_redistribute_set (vty->index, AFI_IP6, type); +} + +DEFUN (bgp_redistribute_ipv6_metric_rmap, + bgp_redistribute_ipv6_metric_rmap_cmd, + "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int type; + u_int32_t metric; + + type = bgp_str2route_type (AFI_IP6, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + VTY_GET_INTEGER ("metric", metric, argv[1]); + + bgp_redistribute_metric_set (vty->index, AFI_IP6, type, metric); + bgp_redistribute_rmap_set (vty->index, AFI_IP6, type, argv[2]); + return bgp_redistribute_set (vty->index, AFI_IP6, type); +} + +DEFUN (no_bgp_redistribute_ipv6, + no_bgp_redistribute_ipv6_cmd, + "no redistribute (connected|kernel|ospf6|ripng|static)", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP6, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_redistribute_unset (vty->index, AFI_IP6, type); +} + +DEFUN (no_bgp_redistribute_ipv6_rmap, + no_bgp_redistribute_ipv6_rmap_cmd, + "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP6, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_redistribute_routemap_unset (vty->index, AFI_IP6, type); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_redistribute_ipv6_metric, + no_bgp_redistribute_ipv6_metric_cmd, + "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP6, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_redistribute_metric_unset (vty->index, AFI_IP6, type); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_redistribute_ipv6_rmap_metric, + no_bgp_redistribute_ipv6_rmap_metric_cmd, + "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n" + "Metric for redistributed routes\n" + "Default metric\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP6, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_redistribute_metric_unset (vty->index, AFI_IP6, type); + bgp_redistribute_routemap_unset (vty->index, AFI_IP6, type); + return CMD_SUCCESS; +} + +ALIAS (no_bgp_redistribute_ipv6_rmap_metric, + no_bgp_redistribute_ipv6_metric_rmap_cmd, + "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +#endif /* HAVE_IPV6 */ + +int +bgp_config_write_redistribute (struct vty *vty, struct bgp *bgp, afi_t afi, + safi_t safi, int *write) +{ + int i; + char *str[] = { "system", "kernel", "connected", "static", "rip", + "ripng", "ospf", "ospf6", "bgp"}; + + /* Unicast redistribution only. */ + if (safi != SAFI_UNICAST) + return 0; + + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + { + /* Redistribute BGP does not make sense. */ + if (bgp->redist[afi][i] && i != ZEBRA_ROUTE_BGP) + { + /* Display "address-family" when it is not yet diplayed. */ + bgp_config_write_family_header (vty, afi, safi, write); + + /* "redistribute" configuration. */ + vty_out (vty, " redistribute %s", str[i]); + + if (bgp->redist_metric_flag[afi][i]) + vty_out (vty, " metric %d", bgp->redist_metric[afi][i]); + + if (bgp->rmap[afi][i].name) + vty_out (vty, " route-map %s", bgp->rmap[afi][i].name); + + vty_out (vty, "%s", VTY_NEWLINE); + } + } + return *write; +} + +/* BGP node structure. */ +struct cmd_node bgp_node = +{ + BGP_NODE, + "%s(config-router)# ", + 1, +}; + +struct cmd_node bgp_ipv4_unicast_node = +{ + BGP_IPV4_NODE, + "%s(config-router-af)# ", + 1, +}; + +struct cmd_node bgp_ipv4_multicast_node = +{ + BGP_IPV4M_NODE, + "%s(config-router-af)# ", + 1, +}; + +struct cmd_node bgp_ipv6_unicast_node = +{ + BGP_IPV6_NODE, + "%s(config-router-af)# ", + 1, +}; + +struct cmd_node bgp_vpnv4_node = +{ + BGP_VPNV4_NODE, + "%s(config-router-af)# ", + 1 +}; + +void +bgp_vty_init () +{ + int bgp_config_write (struct vty *); + void community_list_vty (); + + /* Install bgp top node. */ + install_node (&bgp_node, bgp_config_write); + install_node (&bgp_ipv4_unicast_node, NULL); + install_node (&bgp_ipv4_multicast_node, NULL); + install_node (&bgp_ipv6_unicast_node, NULL); + install_node (&bgp_vpnv4_node, NULL); + + /* Install default VTY commands to new nodes. */ + install_default (BGP_NODE); + install_default (BGP_IPV4_NODE); + install_default (BGP_IPV4M_NODE); + install_default (BGP_IPV6_NODE); + install_default (BGP_VPNV4_NODE); + + /* "bgp multiple-instance" commands. */ + install_element (CONFIG_NODE, &bgp_multiple_instance_cmd); + install_element (CONFIG_NODE, &no_bgp_multiple_instance_cmd); + + /* "bgp config-type" commands. */ + install_element (CONFIG_NODE, &bgp_config_type_cmd); + install_element (CONFIG_NODE, &no_bgp_config_type_cmd); + + /* Dummy commands (Currently not supported) */ + install_element (BGP_NODE, &no_synchronization_cmd); + install_element (BGP_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 (); +} + +#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; +} + +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; +} + +/* 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 index 00000000..15ad5810 --- /dev/null +++ b/bgpd/bgp_vty.h @@ -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 index 00000000..3e5cdd2a --- /dev/null +++ b/bgpd/bgp_zebra.c @@ -0,0 +1,1001 @@ +/* zebra client + Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include + +#include "command.h" +#include "stream.h" +#include "network.h" +#include "prefix.h" +#include "log.h" +#include "sockunion.h" +#include "zclient.h" +#include "routemap.h" +#include "thread.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_nexthop.h" +#include "bgpd/bgp_zebra.h" +#include "bgpd/bgp_fsm.h" + +/* All information about zebra. */ +static struct zclient *zclient = NULL; + +/* Update default router id. */ +int +bgp_if_update (struct interface *ifp) +{ + struct bgp *bgp; + listnode cn; + struct listnode *nn; + struct listnode *nm; + struct peer *peer; + + for (cn = listhead (ifp->connected); cn; nextnode (cn)) + { + struct connected *co; + struct in_addr addr; + + co = getdata (cn); + + if (co->address->family == AF_INET) + { + addr = co->address->u.prefix4; + + /* Ignore NET127. */ + if (IPV4_NET127 (ntohl (addr.s_addr))) + continue; + + LIST_LOOP (bm->bgp, bgp, nn) + { + /* Respect configured router id */ + if (! (bgp->config & BGP_CONFIG_ROUTER_ID)) + if (ntohl (bgp->router_id.s_addr) < ntohl (addr.s_addr)) + { + bgp->router_id = addr; + LIST_LOOP (bgp->peer, peer, nm) + { + peer->local_id = addr; + } + } + } + } + } + return 0; +} + +int +bgp_if_update_all () +{ + listnode node; + struct interface *ifp; + + for (node = listhead (iflist); node; node = nextnode (node)) + { + ifp = getdata (node); + bgp_if_update (ifp); + } + return 0; +} + +/* Inteface addition message from zebra. */ +int +bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_add_read (zclient->ibuf); + bgp_if_update (ifp); + + return 0; +} + +int +bgp_interface_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct stream *s; + struct interface *ifp; + + s = zclient->ibuf; + ifp = zebra_interface_state_read (s); + + return 0; +} + +int +bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length) +{ + struct stream *s; + struct interface *ifp; + struct connected *c; + listnode node; + + s = zclient->ibuf; + ifp = zebra_interface_state_read (s); + + if (! ifp) + return 0; + + for (node = listhead (ifp->connected); node; nextnode (node)) + { + c = getdata (node); + bgp_connected_add (c); + } + + return 0; +} + +int +bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length) +{ + struct stream *s; + struct interface *ifp; + struct connected *c; + listnode node; + + s = zclient->ibuf; + ifp = zebra_interface_state_read (s); + if (! ifp) + return 0; + + for (node = listhead (ifp->connected); node; nextnode (node)) + { + c = getdata (node); + bgp_connected_delete (c); + } + + /* Fast external-failover (Currently IPv4 only) */ + { + struct listnode *nn, *nm; + struct bgp *bgp; + struct peer *peer; + struct interface *peer_if; + + LIST_LOOP (bm->bgp, bgp, nn) + { + if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) + continue; + + LIST_LOOP (bgp->peer, peer, nm) + { + if (peer->ttl != 1) + continue; + + if (peer->su.sa.sa_family == AF_INET) + peer_if = if_lookup_by_ipv4 (&peer->su.sin.sin_addr); + else + continue; + + if (ifp == peer_if) + BGP_EVENT_ADD (peer, BGP_Stop); + } + } + } + + return 0; +} + +int +bgp_interface_address_add (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *ifc; + + ifc = zebra_interface_address_add_read (zclient->ibuf); + + if (ifc == NULL) + return 0; + + bgp_if_update (ifc->ifp); + + if (if_is_up (ifc->ifp)) + bgp_connected_add (ifc); + + return 0; +} + +int +bgp_interface_address_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *ifc; + + ifc = zebra_interface_address_delete_read (zclient->ibuf); + + if (ifc == NULL) + return 0; + + bgp_if_update (ifc->ifp); + + if (if_is_up (ifc->ifp)) + bgp_connected_delete (ifc); + + connected_free (ifc); + + return 0; +} + +/* Zebra route add and delete treatment. */ +int +zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) +{ + struct stream *s; + struct zapi_ipv4 api; + unsigned long ifindex; + struct in_addr nexthop; + struct prefix_ipv4 p; + + s = zclient->ibuf; + ifindex = 0; + nexthop.s_addr = 0; + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.flags = stream_getc (s); + api.message = stream_getc (s); + + /* IPv4 prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = stream_getc (s); + stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + { + api.nexthop_num = stream_getc (s); + nexthop.s_addr = stream_get_ipv4 (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) + { + api.ifindex_num = stream_getc (s); + ifindex = stream_getl (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + else + api.metric = 0; + + if (command == ZEBRA_IPV4_ROUTE_ADD) + bgp_redistribute_add ((struct prefix *)&p, &nexthop, api.metric, api.type); + else + bgp_redistribute_delete ((struct prefix *)&p, api.type); + + return 0; +} + +#ifdef HAVE_IPV6 +/* Zebra route add and delete treatment. */ +int +zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) +{ + struct stream *s; + struct zapi_ipv6 api; + unsigned long ifindex; + struct in6_addr nexthop; + struct prefix_ipv6 p; + + s = zclient->ibuf; + ifindex = 0; + memset (&nexthop, 0, sizeof (struct in6_addr)); + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.flags = stream_getc (s); + api.message = stream_getc (s); + + /* IPv6 prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = stream_getc (s); + stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + { + api.nexthop_num = stream_getc (s); + stream_get (&nexthop, s, 16); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) + { + api.ifindex_num = stream_getc (s); + ifindex = stream_getl (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + else + api.distance = 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + else + api.metric = 0; + + /* Simply ignore link-local address. */ + if (IN6_IS_ADDR_LINKLOCAL (&p.prefix)) + return 0; + + if (command == ZEBRA_IPV6_ROUTE_ADD) + bgp_redistribute_add ((struct prefix *)&p, NULL, api.metric, api.type); + else + bgp_redistribute_delete ((struct prefix *) &p, api.type); + + return 0; +} +#endif /* HAVE_IPV6 */ + +struct interface * +if_lookup_by_ipv4 (struct in_addr *addr) +{ + listnode ifnode; + listnode cnode; + struct interface *ifp; + struct connected *connected; + struct prefix_ipv4 p; + struct prefix *cp; + + p.family = AF_INET; + p.prefix = *addr; + p.prefixlen = IPV4_MAX_BITLEN; + + for (ifnode = listhead (iflist); ifnode; nextnode (ifnode)) + { + ifp = getdata (ifnode); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + connected = getdata (cnode); + cp = connected->address; + + if (cp->family == AF_INET) + if (prefix_match (cp, (struct prefix *)&p)) + return ifp; + } + } + return NULL; +} + +struct interface * +if_lookup_by_ipv4_exact (struct in_addr *addr) +{ + listnode ifnode; + listnode cnode; + struct interface *ifp; + struct connected *connected; + struct prefix *cp; + + for (ifnode = listhead (iflist); ifnode; nextnode (ifnode)) + { + ifp = getdata (ifnode); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + connected = getdata (cnode); + cp = connected->address; + + if (cp->family == AF_INET) + if (IPV4_ADDR_SAME (&cp->u.prefix4, addr)) + return ifp; + } + } + return NULL; +} + +#ifdef HAVE_IPV6 +struct interface * +if_lookup_by_ipv6 (struct in6_addr *addr) +{ + listnode ifnode; + listnode cnode; + struct interface *ifp; + struct connected *connected; + struct prefix_ipv6 p; + struct prefix *cp; + + p.family = AF_INET6; + p.prefix = *addr; + p.prefixlen = IPV6_MAX_BITLEN; + + for (ifnode = listhead (iflist); ifnode; nextnode (ifnode)) + { + ifp = getdata (ifnode); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + connected = getdata (cnode); + cp = connected->address; + + if (cp->family == AF_INET6) + if (prefix_match (cp, (struct prefix *)&p)) + return ifp; + } + } + return NULL; +} + +struct interface * +if_lookup_by_ipv6_exact (struct in6_addr *addr) +{ + listnode ifnode; + listnode cnode; + struct interface *ifp; + struct connected *connected; + struct prefix *cp; + + for (ifnode = listhead (iflist); ifnode; nextnode (ifnode)) + { + ifp = getdata (ifnode); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + connected = getdata (cnode); + cp = connected->address; + + if (cp->family == AF_INET6) + if (IPV6_ADDR_SAME (&cp->u.prefix6, addr)) + return ifp; + } + } + return NULL; +} + +int +if_get_ipv6_global (struct interface *ifp, struct in6_addr *addr) +{ + listnode cnode; + struct connected *connected; + struct prefix *cp; + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + connected = getdata (cnode); + cp = connected->address; + + if (cp->family == AF_INET6) + if (! IN6_IS_ADDR_LINKLOCAL (&cp->u.prefix6)) + { + memcpy (addr, &cp->u.prefix6, IPV6_MAX_BYTELEN); + return 1; + } + } + return 0; +} + +int +if_get_ipv6_local (struct interface *ifp, struct in6_addr *addr) +{ + listnode cnode; + struct connected *connected; + struct prefix *cp; + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + connected = getdata (cnode); + cp = connected->address; + + if (cp->family == AF_INET6) + if (IN6_IS_ADDR_LINKLOCAL (&cp->u.prefix6)) + { + memcpy (addr, &cp->u.prefix6, IPV6_MAX_BYTELEN); + return 1; + } + } + return 0; +} +#endif /* HAVE_IPV6 */ + +int +bgp_nexthop_set (union sockunion *local, union sockunion *remote, + struct bgp_nexthop *nexthop, struct peer *peer) +{ + int ret = 0; + struct interface *ifp = NULL; + + memset (nexthop, 0, sizeof (struct bgp_nexthop)); + + if (!local) + return -1; + if (!remote) + return -1; + + if (local->sa.sa_family == AF_INET) + { + nexthop->v4 = local->sin.sin_addr; + ifp = if_lookup_by_ipv4 (&local->sin.sin_addr); + } +#ifdef HAVE_IPV6 + if (local->sa.sa_family == AF_INET6) + { + if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr)) + { + if (peer->ifname) + ifp = if_lookup_by_index (if_nametoindex (peer->ifname)); + } + else + ifp = if_lookup_by_ipv6 (&local->sin6.sin6_addr); + } +#endif /* HAVE_IPV6 */ + + if (!ifp) + return -1; + + nexthop->ifp = ifp; + + /* IPv4 connection. */ + if (local->sa.sa_family == AF_INET) + { +#ifdef HAVE_IPV6 + /* IPv6 nexthop*/ + ret = if_get_ipv6_global (ifp, &nexthop->v6_global); + + /* There is no global nexthop. */ + if (!ret) + if_get_ipv6_local (ifp, &nexthop->v6_global); + else + if_get_ipv6_local (ifp, &nexthop->v6_local); +#endif /* HAVE_IPV6 */ + } + +#ifdef HAVE_IPV6 + /* IPv6 connection. */ + if (local->sa.sa_family == AF_INET6) + { + struct interface *direct = NULL; + + /* IPv4 nexthop. I don't care about it. */ + if (peer->local_id.s_addr) + nexthop->v4 = peer->local_id; + + /* Global address*/ + if (! IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr)) + { + memcpy (&nexthop->v6_global, &local->sin6.sin6_addr, + IPV6_MAX_BYTELEN); + + /* If directory connected set link-local address. */ + direct = if_lookup_by_ipv6 (&remote->sin6.sin6_addr); + if (direct) + if_get_ipv6_local (ifp, &nexthop->v6_local); + } + else + /* Link-local address. */ + { + ret = if_get_ipv6_global (ifp, &nexthop->v6_global); + + /* If there is no global address. Set link-local address as + global. I know this break RFC specification... */ + if (!ret) + memcpy (&nexthop->v6_global, &local->sin6.sin6_addr, + IPV6_MAX_BYTELEN); + else + memcpy (&nexthop->v6_local, &local->sin6.sin6_addr, + IPV6_MAX_BYTELEN); + } + } + + if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr) || + if_lookup_by_ipv6 (&remote->sin6.sin6_addr)) + peer->shared_network = 1; + else + peer->shared_network = 0; + + /* KAME stack specific treatment. */ +#ifdef KAME + if (IN6_IS_ADDR_LINKLOCAL (&nexthop->v6_global) + && IN6_LINKLOCAL_IFINDEX (nexthop->v6_global)) + { + SET_IN6_LINKLOCAL_IFINDEX (nexthop->v6_global, 0); + } + if (IN6_IS_ADDR_LINKLOCAL (&nexthop->v6_local) + && IN6_LINKLOCAL_IFINDEX (nexthop->v6_local)) + { + SET_IN6_LINKLOCAL_IFINDEX (nexthop->v6_local, 0); + } +#endif /* KAME */ +#endif /* HAVE_IPV6 */ + return ret; +} + +#ifdef HAVE_IPV6 +unsigned int +bgp_ifindex_by_nexthop (struct in6_addr *addr) +{ + listnode ifnode; + listnode cnode; + struct interface *ifp; + struct connected *connected; + struct prefix_ipv6 p; + + p.family = AF_INET6; + p.prefix = *addr; + p.prefixlen = IPV6_MAX_BITLEN; + + for (ifnode = listhead (iflist); ifnode; nextnode (ifnode)) + { + ifp = getdata (ifnode); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + struct prefix *cp; + + connected = getdata (cnode); + cp = connected->address; + + if (cp->family == AF_INET6) + { + if (prefix_match (cp, (struct prefix *)&p)) + return ifp->ifindex; + } + } + } + return 0; +} +#endif /* HAVE_IPV6 */ + +void +bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp) +{ + int flags; + u_char distance; + struct peer *peer; + + if (zclient->sock < 0) + return; + + if (! zclient->redist[ZEBRA_ROUTE_BGP]) + return; + + flags = 0; + peer = info->peer; + + if (peer_sort (peer) == BGP_PEER_IBGP || peer_sort (peer) == BGP_PEER_CONFED) + { + SET_FLAG (flags, ZEBRA_FLAG_IBGP); + SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); + } + + if ((peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1) + || CHECK_FLAG (peer->flags, PEER_FLAG_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 */ +} + +/* Other routes redistribution into BGP. */ +int +bgp_redistribute_set (struct bgp *bgp, afi_t afi, int type) +{ + /* Set flag to BGP instance. */ + bgp->redist[afi][type] = 1; + + /* Return if already redistribute flag is set. */ + if (zclient->redist[type]) + return CMD_WARNING; + + zclient->redist[type] = 1; + + /* Return if zebra connection is not established. */ + if (zclient->sock < 0) + return CMD_WARNING; + + /* Send distribute add message to zebra. */ + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type); + + return CMD_SUCCESS; +} + +/* Redistribute with route-map specification. */ +int +bgp_redistribute_rmap_set (struct bgp *bgp, afi_t afi, int type, char *name) +{ + if (bgp->rmap[afi][type].name + && (strcmp (bgp->rmap[afi][type].name, name) == 0)) + return 0; + + if (bgp->rmap[afi][type].name) + free (bgp->rmap[afi][type].name); + bgp->rmap[afi][type].name = strdup (name); + bgp->rmap[afi][type].map = route_map_lookup_by_name (name); + + return 1; +} + +/* Redistribute with metric specification. */ +int +bgp_redistribute_metric_set (struct bgp *bgp, afi_t afi, int type, + u_int32_t metric) +{ + if (bgp->redist_metric_flag[afi][type] + && bgp->redist_metric[afi][type] == metric) + return 0; + + bgp->redist_metric_flag[afi][type] = 1; + bgp->redist_metric[afi][type] = metric; + + return 1; +} + +/* Unset redistribution. */ +int +bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type) +{ + /* Unset flag from BGP instance. */ + bgp->redist[afi][type] = 0; + + /* Unset route-map. */ + if (bgp->rmap[afi][type].name) + free (bgp->rmap[afi][type].name); + bgp->rmap[afi][type].name = NULL; + bgp->rmap[afi][type].map = NULL; + + /* Unset metric. */ + bgp->redist_metric_flag[afi][type] = 0; + bgp->redist_metric[afi][type] = 0; + + /* Return if zebra connection is disabled. */ + if (! zclient->redist[type]) + return CMD_WARNING; + zclient->redist[type] = 0; + + if (bgp->redist[AFI_IP][type] == 0 + && bgp->redist[AFI_IP6][type] == 0 + && zclient->sock >= 0) + /* Send distribute delete message to zebra. */ + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type); + + /* Withdraw redistributed routes from current BGP's routing table. */ + bgp_redistribute_withdraw (bgp, afi, type); + + return CMD_SUCCESS; +} + +/* Unset redistribution route-map configuration. */ +int +bgp_redistribute_routemap_unset (struct bgp *bgp, afi_t afi, int type) +{ + if (! bgp->rmap[afi][type].name) + return 0; + + /* Unset route-map. */ + free (bgp->rmap[afi][type].name); + bgp->rmap[afi][type].name = NULL; + bgp->rmap[afi][type].map = NULL; + + return 1; +} + +/* Unset redistribution metric configuration. */ +int +bgp_redistribute_metric_unset (struct bgp *bgp, afi_t afi, int type) +{ + if (! bgp->redist_metric_flag[afi][type]) + return 0; + + /* Unset metric. */ + bgp->redist_metric_flag[afi][type] = 0; + bgp->redist_metric[afi][type] = 0; + + return 1; +} + +void +bgp_zclient_reset () +{ + zclient_reset (zclient); +} + +void +bgp_zebra_init (int enable) +{ + /* Set default values. */ + zclient = zclient_new (); + zclient_init (zclient, ZEBRA_ROUTE_BGP); + zclient->interface_add = bgp_interface_add; + zclient->interface_delete = bgp_interface_delete; + zclient->interface_address_add = bgp_interface_address_add; + zclient->interface_address_delete = bgp_interface_address_delete; + zclient->ipv4_route_add = zebra_read_ipv4; + zclient->ipv4_route_delete = zebra_read_ipv4; + zclient->interface_up = bgp_interface_up; + zclient->interface_down = bgp_interface_down; +#ifdef HAVE_IPV6 + zclient->ipv6_route_add = zebra_read_ipv6; + zclient->ipv6_route_delete = zebra_read_ipv6; +#endif /* HAVE_IPV6 */ + + /* Interface related init. */ + if_init (); +} diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h new file mode 100644 index 00000000..1620c847 --- /dev/null +++ b/bgpd/bgp_zebra.h @@ -0,0 +1,39 @@ +/* zebra connection and redistribute fucntions. + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +int bgp_if_update_all (); +int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t, + int *); +void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *); +void bgp_zebra_withdraw (struct prefix *, struct bgp_info *); + +int bgp_redistribute_set (struct bgp *, afi_t, int); +int bgp_redistribute_rmap_set (struct bgp *, afi_t, int, char *); +int bgp_redistribute_metric_set (struct bgp *, afi_t, int, u_int32_t); +int bgp_redistribute_unset (struct bgp *, afi_t, int); +int bgp_redistribute_routemap_unset (struct bgp *, afi_t, int); +int bgp_redistribute_metric_unset (struct bgp *, afi_t, int); + +struct interface *if_lookup_by_ipv4 (struct in_addr *); +struct interface *if_lookup_by_ipv4_exact (struct in_addr *); +#ifdef HAVE_IPV6 +struct interface *if_lookup_by_ipv6 (struct in6_addr *); +struct interface *if_lookup_by_ipv6_exact (struct in6_addr *); +#endif /* HAVE_IPV6 */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c new file mode 100644 index 00000000..f116a0cf --- /dev/null +++ b/bgpd/bgpd.c @@ -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 + +#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 */ + +/* BGP process wide configuration. */ +static struct bgp_master bgp_master; + +/* BGP process wide configuration pointer to export. */ +struct bgp_master *bm; + +/* BGP community-list. */ +struct community_list_handler *bgp_clist; + +/* BGP global flag manipulation. */ +int +bgp_option_set (int flag) +{ + switch (flag) + { + case BGP_OPT_NO_FIB: + case BGP_OPT_MULTIPLE_INSTANCE: + case BGP_OPT_CONFIG_CISCO: + SET_FLAG (bm->options, flag); + break; + default: + return BGP_ERR_INVALID_FLAG; + break; + } + return 0; +} + +int +bgp_option_unset (int flag) +{ + switch (flag) + { + case BGP_OPT_MULTIPLE_INSTANCE: + if (listcount (bm->bgp) > 1) + return BGP_ERR_MULTIPLE_INSTANCE_USED; + /* Fall through. */ + case BGP_OPT_NO_FIB: + case BGP_OPT_CONFIG_CISCO: + UNSET_FLAG (bm->options, flag); + break; + default: + return BGP_ERR_INVALID_FLAG; + break; + } + return 0; +} + +int +bgp_option_check (int flag) +{ + return CHECK_FLAG (bm->options, flag); +} + +/* BGP flag manipulation. */ +int +bgp_flag_set (struct bgp *bgp, int flag) +{ + SET_FLAG (bgp->flags, flag); + return 0; +} + +int +bgp_flag_unset (struct bgp *bgp, int flag) +{ + UNSET_FLAG (bgp->flags, flag); + return 0; +} + +int +bgp_flag_check (struct bgp *bgp, int flag) +{ + return CHECK_FLAG (bgp->flags, flag); +} + +/* Internal function to set BGP structure configureation flag. */ +static void +bgp_config_set (struct bgp *bgp, int config) +{ + SET_FLAG (bgp->config, config); +} + +static void +bgp_config_unset (struct bgp *bgp, int config) +{ + UNSET_FLAG (bgp->config, config); +} + +static int +bgp_config_check (struct bgp *bgp, int config) +{ + return CHECK_FLAG (bgp->config, config); +} + +/* Set BGP router identifier. */ +int +bgp_router_id_set (struct bgp *bgp, struct in_addr *id) +{ + struct peer *peer; + struct listnode *nn; + + if (bgp_config_check (bgp, BGP_CONFIG_ROUTER_ID) + && IPV4_ADDR_SAME (&bgp->router_id, id)) + return 0; + + IPV4_ADDR_COPY (&bgp->router_id, id); + bgp_config_set (bgp, BGP_CONFIG_ROUTER_ID); + + /* Set all peer's local identifier with this value. */ + LIST_LOOP (bgp->peer, peer, nn) + { + IPV4_ADDR_COPY (&peer->local_id, id); + + if (peer->status == Established) + 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; +} + +/* 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; +} + +/* BGP timer configuration. */ +int +bgp_timers_set (struct bgp *bgp, u_int32_t keepalive, u_int32_t holdtime) +{ + bgp->default_keepalive = (keepalive < holdtime / 3 + ? keepalive : holdtime / 3); + bgp->default_holdtime = holdtime; + + return 0; +} + +int +bgp_timers_unset (struct bgp *bgp) +{ + bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE; + bgp->default_holdtime = BGP_DEFAULT_HOLDTIME; + + return 0; +} + +/* BGP confederation configuration. */ +int +bgp_confederation_id_set (struct bgp *bgp, as_t as) +{ + struct peer *peer; + struct listnode *nn; + int already_confed; + + if (as == 0) + return BGP_ERR_INVALID_AS; + + /* Remember - were we doing confederation before? */ + already_confed = bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION); + bgp->confed_id = as; + bgp_config_set (bgp, BGP_CONFIG_CONFEDERATION); + + /* If we were doing confederation already, this is just an external + AS change. Just Reset EBGP sessions, not CONFED sessions. If we + were not doing confederation before, reset all EBGP sessions. */ + LIST_LOOP (bgp->peer, peer, nn) + { + /* We're looking for peers who's AS is not local or part of our + confederation. */ + if (already_confed) + { + if (peer_sort (peer) == BGP_PEER_EBGP) + { + peer->local_as = as; + if (peer->status == Established) + 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; +} + +/* 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; +} + +/* 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; +} + +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; +} + +/* 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; +} + +struct peer * +peer_lookup (struct bgp *bgp, union sockunion *su) +{ + struct peer *peer; + struct listnode *nn; + + if (! bgp) + bgp = bgp_get_default (); + + if (! bgp) + return NULL; + + LIST_LOOP (bgp->peer, peer, nn) + { + if (sockunion_same (&peer->su, su) + && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + return peer; + } + return NULL; +} + +struct peer * +peer_lookup_with_open (union sockunion *su, as_t remote_as, + struct in_addr *remote_id, int *as) +{ + struct peer *peer; + struct listnode *nn; + struct bgp *bgp; + + bgp = bgp_get_default (); + if (! bgp) + return NULL; + + LIST_LOOP (bgp->peer, peer, nn) + { + if (sockunion_same (&peer->su, su) + && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + { + if (peer->as == remote_as + && peer->remote_id.s_addr == remote_id->s_addr) + return peer; + if (peer->as == remote_as) + *as = 1; + } + } + LIST_LOOP (bgp->peer, peer, nn) + { + if (sockunion_same (&peer->su, su) + && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + { + if (peer->as == remote_as + && peer->remote_id.s_addr == 0) + return peer; + if (peer->as == remote_as) + *as = 1; + } + } + return NULL; +} + +/* If peer is configured at least one address family return 1. */ +int +peer_active (struct peer *peer) +{ + if (peer->afc[AFI_IP][SAFI_UNICAST] + || peer->afc[AFI_IP][SAFI_MULTICAST] + || peer->afc[AFI_IP][SAFI_MPLS_VPN] + || peer->afc[AFI_IP6][SAFI_UNICAST] + || peer->afc[AFI_IP6][SAFI_MULTICAST]) + return 1; + return 0; +} + +/* If peer is negotiated at least one address family return 1. */ +int +peer_active_nego (struct peer *peer) +{ + if (peer->afc_nego[AFI_IP][SAFI_UNICAST] + || peer->afc_nego[AFI_IP][SAFI_MULTICAST] + || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] + || peer->afc_nego[AFI_IP6][SAFI_UNICAST] + || peer->afc_nego[AFI_IP6][SAFI_MULTICAST]) + return 1; + return 0; +} + +/* peer_flag_change_type. */ +enum peer_change_type +{ + peer_change_none, + peer_change_reset, + peer_change_reset_in, + peer_change_reset_out, +}; + +void +peer_change_action (struct peer *peer, afi_t afi, safi_t safi, + enum peer_change_type type) +{ + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return; + + if (type == peer_change_reset) + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + else if (type == peer_change_reset_in) + { + if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV) + || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV)) + bgp_route_refresh_send (peer, afi, safi, 0, 0, 0); + else + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else if (type == peer_change_reset_out) + bgp_announce_route (peer, afi, safi); +} + +struct peer_flag_action +{ + /* Peer's flag. */ + u_int32_t flag; + + /* This flag can be set for peer-group member. */ + u_char not_for_member; + + /* Action when the flag is changed. */ + enum peer_change_type type; +}; + +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); +} + +/* 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; +} + +/* Neighbor description. */ +int +peer_description_set (struct peer *peer, char *desc) +{ + if (peer->desc) + XFREE (MTYPE_PEER_DESC, peer->desc); + + peer->desc = XSTRDUP (MTYPE_PEER_DESC, desc); + + return 0; +} + +int +peer_description_unset (struct peer *peer) +{ + if (peer->desc) + XFREE (MTYPE_PEER_DESC, peer->desc); + + peer->desc = NULL; + + return 0; +} + +/* Neighbor update-source. */ +int +peer_update_source_if_set (struct peer *peer, char *ifname) +{ + struct peer_group *group; + struct listnode *nn; + + if (peer->update_if) + { + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) + && strcmp (peer->update_if, ifname) == 0) + return 0; + + XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); + peer->update_if = NULL; + } + + if (peer->update_source) + { + sockunion_free (peer->update_source); + peer->update_source = NULL; + } + + peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, ifname); + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer->status == Established) + 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; +} + +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; +} + +int +peer_port_set (struct peer *peer, u_int16_t port) +{ + peer->port = port; + return 0; +} + +int +peer_port_unset (struct peer *peer) +{ + peer->port = BGP_PORT_DEFAULT; + return 0; +} + +/* neighbor weight. */ +int +peer_weight_set (struct peer *peer, u_int16_t weight) +{ + struct peer_group *group; + struct listnode *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; +} + +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; +} + +int +peer_timers_connect_set (struct peer *peer, u_int32_t connect) +{ + if (peer_group_active (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + if (connect > 65535) + return BGP_ERR_INVALID_VALUE; + + /* Set value to the configuration. */ + SET_FLAG (peer->config, PEER_CONFIG_CONNECT); + peer->connect = connect; + + /* Set value to timer setting. */ + peer->v_connect = connect; + + return 0; +} + +int +peer_timers_connect_unset (struct peer *peer) +{ + if (peer_group_active (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + /* Clear configuration. */ + UNSET_FLAG (peer->config, PEER_CONFIG_CONNECT); + peer->connect = 0; + + /* Set timer setting to default value. */ + peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; + + return 0; +} + +int +peer_advertise_interval_set (struct peer *peer, u_int32_t routeadv) +{ + if (peer_group_active (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + if (routeadv > 600) + return BGP_ERR_INVALID_VALUE; + + SET_FLAG (peer->config, PEER_CONFIG_ROUTEADV); + peer->routeadv = routeadv; + peer->v_routeadv = routeadv; + + return 0; +} + +int +peer_advertise_interval_unset (struct peer *peer) +{ + if (peer_group_active (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + UNSET_FLAG (peer->config, PEER_CONFIG_ROUTEADV); + peer->routeadv = 0; + + if (peer_sort (peer) == BGP_PEER_IBGP) + peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + else + peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + + return 0; +} + +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; +} + +/* neighbor interface */ +int +peer_interface_set (struct peer *peer, char *str) +{ + if (peer->ifname) + free (peer->ifname); + peer->ifname = strdup (str); + + return 0; +} + +int +peer_interface_unset (struct peer *peer) +{ + if (peer->ifname) + free (peer->ifname); + peer->ifname = NULL; + + return 0; +} + +/* Allow-as in. */ +int +peer_allowas_in_set (struct peer *peer, afi_t afi, safi_t safi, int allow_num) +{ + struct peer_group *group; + struct listnode *nn; + + if (allow_num < 1 || allow_num > 10) + return BGP_ERR_INVALID_VALUE; + + if (peer->allowas_in[afi][safi] != allow_num) + { + peer->allowas_in[afi][safi] = allow_num; + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN); + peer_change_action (peer, afi, safi, peer_change_reset_in); + } + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 0; + + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + if (peer->allowas_in[afi][safi] != allow_num) + { + peer->allowas_in[afi][safi] = allow_num; + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN); + peer_change_action (peer, afi, safi, peer_change_reset_in); + } + + } + return 0; +} + +int +peer_allowas_in_unset (struct peer *peer, afi_t afi, safi_t safi) +{ + struct peer_group *group; + struct listnode *nn; + + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN)) + { + peer->allowas_in[afi][safi] = 0; + peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN); + } + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 0; + + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN)) + { + peer->allowas_in[afi][safi] = 0; + peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN); + } + } + return 0; +} + +int +peer_local_as_set (struct peer *peer, as_t as, int no_prepend) +{ + struct bgp *bgp = peer->bgp; + struct peer_group *group; + struct listnode *nn; + + if (peer_sort (peer) != BGP_PEER_EBGP + && peer_sort (peer) != BGP_PEER_INTERNAL) + return BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP; + + if (bgp->as == as) + return BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS; + + if (peer_group_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; +} + +/* 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; + } + } + } + } +} + +/* 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; + } + } + } + } +} + +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; + } + } + } + } +} + +/* 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; +} + +/* 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; +} + +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; +} + +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; +} + +/* Display peer uptime. */ +char * +peer_uptime (time_t uptime2, char *buf, size_t len) +{ + time_t uptime1; + struct tm *tm; + + /* Check buffer length. */ + if (len < BGP_UPTIME_LEN) + { + zlog_warn ("peer_uptime (): buffer shortage %d", len); + return ""; + } + + /* If there is no connection has been done before print `never'. */ + if (uptime2 == 0) + { + snprintf (buf, len, "never "); + return buf; + } + + /* Get current time. */ + uptime1 = time (NULL); + uptime1 -= uptime2; + tm = gmtime (&uptime1); + + /* Making formatted timer strings. */ +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + + if (uptime1 < ONE_DAY_SECOND) + snprintf (buf, len, "%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (uptime1 < ONE_WEEK_SECOND) + snprintf (buf, len, "%dd%02dh%02dm", + tm->tm_yday, tm->tm_hour, tm->tm_min); + else + snprintf (buf, len, "%02dw%dd%02dh", + tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + return buf; +} + +void +bgp_config_write_filter (struct vty *vty, struct peer *peer, + afi_t afi, safi_t safi) +{ + struct bgp_filter *filter; + struct bgp_filter *gfilter = NULL; + char *addr; + int in = FILTER_IN; + int out = FILTER_OUT; + + addr = peer->host; + filter = &peer->filter[afi][safi]; + if (peer->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); +} + +void +bgp_init () +{ + void bgp_zebra_init (); + void bgp_route_map_init (); + void bgp_filter_init (); + + /* BGP VTY commands installation. */ + bgp_vty_init (); + + /* Create BGP server socket. */ + bgp_socket (NULL, bm->port); + + /* Init zebra. */ + bgp_zebra_init (); + + /* BGP inits. */ + bgp_attr_init (); + bgp_debug_init (); + bgp_dump_init (); + bgp_route_init (); + bgp_route_map_init (); + bgp_scan_init (); + bgp_mplsvpn_init (); + + /* Access list initialize. */ + access_list_init (); + access_list_add_hook (peer_distribute_update); + access_list_delete_hook (peer_distribute_update); + + /* Filter list initialize. */ + bgp_filter_init (); + as_list_add_hook (peer_aslist_update); + as_list_delete_hook (peer_aslist_update); + + /* Prefix list initialize.*/ + prefix_list_init (); + prefix_list_add_hook (peer_prefix_list_update); + prefix_list_delete_hook (peer_prefix_list_update); + + /* Community list initialize. */ + bgp_clist = community_list_init (); + +#ifdef HAVE_SNMP + bgp_snmp_init (); +#endif /* HAVE_SNMP */ +} diff --git a/bgpd/bgpd.conf.sample b/bgpd/bgpd.conf.sample new file mode 100644 index 00000000..b6a8b6f1 --- /dev/null +++ b/bgpd/bgpd.conf.sample @@ -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 index 00000000..d376ad25 --- /dev/null +++ b/bgpd/bgpd.conf.sample2 @@ -0,0 +1,77 @@ +! +! Zebra configuration saved from vty +! 2002/07/01 03:16:33 +! +hostname bgpd +password zebra +log file bgpd.log +log stdout +! +router bgp 7675 + no bgp default ipv4-unicast + neighbor 3ffe:506:1000::2 remote-as 7675 + neighbor fe80::200:c0ff:fe30:9be3 remote-as 9377 + neighbor fe80::200:c0ff:fe30:9be3 interface sit3 + neighbor fe80::210:5aff:fe6b:3cee remote-as 7675 + neighbor fe80::210:5aff:fe6b:3cee interface eth0 + neighbor fe80::290:27ff:fe51:84c7 remote-as 4691 + neighbor fe80::290:27ff:fe51:84c7 description DTI + neighbor fe80::290:27ff:fe51:84c7 interface sit7 + neighbor fe80::2a0:c9ff:fec8:82ec remote-as 7530 + neighbor fe80::2a0:c9ff:fec8:82ec description IRI + neighbor fe80::2a0:c9ff:fec8:82ec interface sit8 + neighbor fe80::2e0:18ff:fe98:2725 remote-as 2500 + neighbor fe80::2e0:18ff:fe98:2725 description WIDE + neighbor fe80::2e0:18ff:fe98:2725 interface sit5 + neighbor fe80::2e0:18ff:fea8:bf5 remote-as 65000 + neighbor fe80::2e0:18ff:fea8:bf5 interface sit6 +! + address-family ipv6 + network 3ffe:506::/33 + network 3ffe:1800:e800::/40 + aggregate-address 3ffe:506::/32 + redistribute connected + neighbor 3ffe:506:1000::2 activate + neighbor fe80::200:c0ff:fe30:9be3 activate + neighbor fe80::200:c0ff:fe30:9be3 route-map set-nexthop out + neighbor fe80::210:5aff:fe6b:3cee activate + neighbor fe80::290:27ff:fe51:84c7 activate + neighbor fe80::290:27ff:fe51:84c7 route-map set-nexthop out + neighbor fe80::2a0:c9ff:fec8:82ec activate + neighbor fe80::2a0:c9ff:fec8:82ec route-map set-nexthop out + neighbor fe80::2e0:18ff:fe98:2725 activate + neighbor fe80::2e0:18ff:fe98:2725 distribute-list nla1 out + neighbor fe80::2e0:18ff:fe98:2725 route-map set-nexthop out + neighbor fe80::2e0:18ff:fea8:bf5 activate + neighbor fe80::2e0:18ff:fea8:bf5 route-map set-nexthop out + exit-address-family +! +ipv6 access-list all permit any +ipv6 access-list nla1 deny 3ffe:506::/33 +ipv6 access-list nla1 permit 3ffe:506::/32 +ipv6 access-list nla1 deny any +ipv6 access-list ntt-nla1 permit 3ffe:1800:0:ffff::c/127 +ipv6 access-list ntt-nla1 deny 3ffe:1800:e800::/41 +ipv6 access-list ntt-nla1 permit 3ffe:1800:e800::/40 +ipv6 access-list ntt-nla1 deny any +! +ipv6 prefix-list 6bone-filter seq 5 permit 3ffe::/17 ge 24 le 24 +ipv6 prefix-list 6bone-filter seq 10 permit 3ffe:8000::/17 ge 28 le 28 +ipv6 prefix-list 6bone-filter seq 12 deny 3ffe::/16 +ipv6 prefix-list 6bone-filter seq 15 permit 2000::/3 ge 16 le 16 +ipv6 prefix-list 6bone-filter seq 20 permit 2001::/16 ge 35 le 35 +! +route-map set-nexthop permit 10 + match ipv6 address all + set ipv6 next-hop global 3ffe:506::1 + set ipv6 next-hop local fe80::cbb5:591a + set ip next-hop 203.181.89.26 + set community 7675:0 +! +route-map set-link-local permit 10 + match ipv6 address all + set ipv6 next-hop local fe80::cbb5:591a + set ipv6 next-hop global 3ffe:1800:0:ffff::d +! +line vty +! diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h new file mode 100644 index 00000000..01d47212 --- /dev/null +++ b/bgpd/bgpd.h @@ -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 *); + +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 index 00000000..a7983e69 --- /dev/null +++ b/config.guess @@ -0,0 +1,1321 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 +# Free Software Foundation, Inc. + +version='2000-11-10' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Written by Per Bothner . +# Please send patches to . +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit system type (host/target name). +# +# Only a few systems have been added to this list; please add others +# (but try to keep the structure clean). +# + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of this system. + +Operation modes: + -h, --help print this help, then exit + -V, --version print version number, then exit" + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case "$1" in + --version | --vers* | -V ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + exec >&2 + echo "$me: invalid option $1" + echo "$help" + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + + +dummy=dummy-$$ +trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15 + +# Use $HOST_CC if defined. $CC may point to a cross-compiler +if test x"$CC_FOR_BUILD" = x; then + if test x"$HOST_CC" != x; then + CC_FOR_BUILD="$HOST_CC" + else + if test x"$CC" != x; then + CC_FOR_BUILD="$CC" + else + echo 'int dummy(){}' >$dummy.c + for c in cc c89 gcc; do + ($c $dummy.c -c) >/dev/null 2>&1 + if test $? = 0; then + CC_FOR_BUILD="$c"; break + fi + done + rm -f $dummy.c $dummy.o + if test x"$CC_FOR_BUILD" = x; then + CC_FOR_BUILD=no_compiler_found + fi + fi + fi +fi + + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 8/24/94.) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # Netbsd (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # Determine the machine/vendor (is the vendor relevant). + case "${UNAME_MACHINE}" in + amiga) machine=m68k-unknown ;; + arm32) machine=arm-unknown ;; + atari*) machine=m68k-atari ;; + sun3*) machine=m68k-sun ;; + mac68k) machine=m68k-apple ;; + macppc) machine=powerpc-apple ;; + hp3[0-9][05]) machine=m68k-hp ;; + ibmrt|romp-ibm) machine=romp-ibm ;; + *) machine=${UNAME_MACHINE}-unknown ;; + esac + # The Operating System including object format. + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + # The OS release + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit 0 ;; + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + cat <$dummy.s + .data +\$Lformat: + .byte 37,100,45,37,120,10,0 # "%d-%x\n" + + .text + .globl main + .align 4 + .ent main +main: + .frame \$30,16,\$26,0 + ldgp \$29,0(\$27) + .prologue 1 + .long 0x47e03d80 # implver \$0 + lda \$2,-1 + .long 0x47e20c21 # amask \$2,\$1 + lda \$16,\$Lformat + mov \$0,\$17 + not \$1,\$18 + jsr \$26,printf + ldgp \$29,0(\$26) + mov 0,\$16 + jsr \$26,exit + .end main +EOF + $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null + if test "$?" = 0 ; then + case `./$dummy` in + 0-0) + UNAME_MACHINE="alpha" + ;; + 1-0) + UNAME_MACHINE="alphaev5" + ;; + 1-1) + UNAME_MACHINE="alphaev56" + ;; + 1-101) + UNAME_MACHINE="alphapca56" + ;; + 2-303) + UNAME_MACHINE="alphaev6" + ;; + 2-307) + UNAME_MACHINE="alphaev67" + ;; + esac + fi + rm -f $dummy.s $dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit 0 ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit 0;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + SR2?01:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit 0 ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit 0 ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD $dummy.c -o $dummy \ + && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i?86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:4) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` + if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=4.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[34678]??:HP-UX:*:*) + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy` + if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi + rm -f $dummy.c $dummy + esac + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + *9??*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i?86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + hppa*:OpenBSD:*:*) + echo hppa-unknown-openbsd + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3E:*:*:*) + echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F300:UNIX_System_V:*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + F301:UNIX_System_V:*:*) + echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + i?86:BSD/386:*:* | i?86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit 0 ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i386-pc-interix + exit 0 ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit 0 ;; + *:Linux:*:*) + + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + ld_supported_emulations=`cd /; ld --help 2>&1 \ + | sed -ne '/supported emulations:/!d + s/[ ][ ]*/ /g + s/.*supported emulations: *// + s/ .*// + p'` + case "$ld_supported_emulations" in + *ia64) + echo "${UNAME_MACHINE}-unknown-linux" + exit 0 + ;; + i?86linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit 0 + ;; + elf_i?86) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + i?86coff) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit 0 + ;; + sparclinux) + echo "${UNAME_MACHINE}-unknown-linux-gnuaout" + exit 0 + ;; + elf32_sparc) + echo "${UNAME_MACHINE}-unknown-linux-gnu" + exit 0 + ;; + armlinux) + echo "${UNAME_MACHINE}-unknown-linux-gnuaout" + exit 0 + ;; + elf32arm*) + echo "${UNAME_MACHINE}-unknown-linux-gnuoldld" + exit 0 + ;; + armelf_linux*) + echo "${UNAME_MACHINE}-unknown-linux-gnu" + exit 0 + ;; + m68klinux) + echo "${UNAME_MACHINE}-unknown-linux-gnuaout" + exit 0 + ;; + elf32ppc | elf32ppclinux) + # Determine Lib Version + cat >$dummy.c < +#if defined(__GLIBC__) +extern char __libc_version[]; +extern char __libc_release[]; +#endif +main(argc, argv) + int argc; + char *argv[]; +{ +#if defined(__GLIBC__) + printf("%s %s\n", __libc_version, __libc_release); +#else + printf("unkown\n"); +#endif + return 0; +} +EOF + LIBC="" + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null + if test "$?" = 0 ; then + ./$dummy | grep 1\.99 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f $dummy.c $dummy + echo powerpc-unknown-linux-gnu${LIBC} + exit 0 + ;; + shelf_linux) + echo "${UNAME_MACHINE}-unknown-linux-gnu" + exit 0 + ;; + esac + + if test "${UNAME_MACHINE}" = "alpha" ; then + cat <$dummy.s + .data + \$Lformat: + .byte 37,100,45,37,120,10,0 # "%d-%x\n" + + .text + .globl main + .align 4 + .ent main + main: + .frame \$30,16,\$26,0 + ldgp \$29,0(\$27) + .prologue 1 + .long 0x47e03d80 # implver \$0 + lda \$2,-1 + .long 0x47e20c21 # amask \$2,\$1 + lda \$16,\$Lformat + mov \$0,\$17 + not \$1,\$18 + jsr \$26,printf + ldgp \$29,0(\$26) + mov 0,\$16 + jsr \$26,exit + .end main +EOF + LIBC="" + $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null + if test "$?" = 0 ; then + case `./$dummy` in + 0-0) + UNAME_MACHINE="alpha" + ;; + 1-0) + UNAME_MACHINE="alphaev5" + ;; + 1-1) + UNAME_MACHINE="alphaev56" + ;; + 1-101) + UNAME_MACHINE="alphapca56" + ;; + 2-303) + UNAME_MACHINE="alphaev6" + ;; + 2-307) + UNAME_MACHINE="alphaev67" + ;; + esac + + objdump --private-headers $dummy | \ + grep ld.so.1 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f $dummy.s $dummy + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 + elif test "${UNAME_MACHINE}" = "mips" ; then + cat >$dummy.c < /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif +#ifdef __MIPSEB__ + printf ("%s-unknown-linux-gnu\n", argv[1]); +#endif +#ifdef __MIPSEL__ + printf ("%sel-unknown-linux-gnu\n", argv[1]); +#endif + return 0; +} +EOF + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + elif test "${UNAME_MACHINE}" = "s390"; then + echo s390-ibm-linux && exit 0 + elif test "${UNAME_MACHINE}" = "x86_64"; then + echo x86_64-unknown-linux-gnu && exit 0 + elif test "${UNAME_MACHINE}" = "parisc" -o "${UNAME_MACHINE}" = "hppa"; then + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) + echo hppa1.1-unknown-linux-gnu + ;; + PA8*) + echo hppa2.0-unknown-linux-gnu + ;; + *) + echo hppa-unknown-linux-gnu + ;; + esac + exit 0 + else + # Either a pre-BFD a.out linker (linux-gnuoldld) + # or one that does not give us useful --help. + # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. + # If ld does not provide *any* "supported emulations:" + # that means it is gnuoldld. + test -z "$ld_supported_emulations" \ + && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 + + case "${UNAME_MACHINE}" in + i?86) + VENDOR=pc; + ;; + *) + VENDOR=unknown; + ;; + esac + # Determine whether the default compiler is a.out or elf + cat >$dummy.c < +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +#else + printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); +#endif + return 0; +} +EOF + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 + fi ;; +# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions +# are messed up and put the nodename in both sysname and nodename. + i?86:DYNIX/ptx:4*:*) + echo i386-sequent-sysv4 + exit 0 ;; + i?86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit 0 ;; + i?86:*:5:7*) + # Fixed at (any) Pentium or better + UNAME_MACHINE=i586 + if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then + echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} + fi + exit 0 ;; + i?86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + i?86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit 0 ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit 0 ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit 0 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Darwin:*:*) + echo `uname -p`-apple-darwin${UNAME_RELEASE} + exit 0 ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + if test "${UNAME_MACHINE}" = "x86pc"; then + UNAME_MACHINE=pc + fi + echo `uname -p`-${UNAME_MACHINE}-nto-qnx + exit 0 ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit 0 ;; + NSR-[KW]:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit 0 ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit 0 ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit 0 ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit 0 ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +#if !defined (ultrix) + printf ("vax-dec-bsd\n"); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0 +rm -f $dummy.c $dummy + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess version = $version + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "version='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.h.in b/config.h.in new file mode 100644 index 00000000..4c5dbea8 --- /dev/null +++ b/config.h.in @@ -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 */ + +/* 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 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 header file. */ +#undef HAVE_INET_ND_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_KVM_H + +/* Define to 1 if you have the `crypt' library (-lcrypt). */ +#undef HAVE_LIBCRYPT + +/* Define to 1 if you have the `kvm' library (-lkvm). */ +#undef HAVE_LIBKVM + +/* Define to 1 if you have the `m' library (-lm). */ +#undef HAVE_LIBM + +/* Define to 1 if you have the `ncurses' library (-lncurses). */ +#undef HAVE_LIBNCURSES + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +#undef HAVE_LIBNSL + +/* Define to 1 if you have the `readline' library (-lreadline). */ +#undef HAVE_LIBREADLINE + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +#undef HAVE_LIBRESOLV + +/* Define to 1 if you have the `socket' library (-lsocket). */ +#undef HAVE_LIBSOCKET + +/* Define to 1 if you have the `tinfo' library (-ltinfo). */ +#undef HAVE_LIBTINFO + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBUTIL_H + +/* Define to 1 if you have the `xnet' library (-lxnet). */ +#undef HAVE_LIBXNET + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_VERSION_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET6_ND6_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_ICMP6_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN6_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN6_VAR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_VAR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_IF_DL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_IF_VAR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_NETOPT_H + +/* 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 header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strlcat' function. */ +#undef HAVE_STRLCAT + +/* Define to 1 if you have the `strlcpy' function. */ +#undef HAVE_STRLCPY + +/* Define to 1 if you have the header file. */ +#undef HAVE_STROPTS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_CONF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_KSYM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SYSCTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIMES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vsnprintf' function. */ +#undef HAVE_VSNPRINTF + +/* 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 index 00000000..004c7deb --- /dev/null +++ b/config.sub @@ -0,0 +1,1332 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 +# Free Software Foundation, Inc. + +version='2000-11-10' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -V, --version print version number, then exit" + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case "$1" in + --version | --vers* | -V ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + exec >&2 + echo "$me: invalid option $1" + echo "$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit 0;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | storm-chaos*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | armv[2345] | armv[345][lb] | pyramid | mn10200 | mn10300 | tron | a29k \ + | 580 | i960 | h8300 \ + | x86 | ppcbe | mipsbe | mipsle | shbe | shle | armbe | armle \ + | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \ + | hppa64 \ + | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \ + | alphaev6[78] \ + | we32k | ns16k | clipper | i370 | sh | sh[34] \ + | powerpc | powerpcle \ + | 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \ + | mips64orion | mips64orionel | mipstx39 | mipstx39el \ + | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \ + | mips64vr5000 | miprs64vr5000el | mcore \ + | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \ + | thumb | d10v | d30v | fr30 | avr) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65 | pj | pjl) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i[234567]86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + # FIXME: clean up the formatting here. + vax-* | tahoe-* | i[234567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \ + | xmp-* | ymp-* \ + | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* | armbe-* | armle-* \ + | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \ + | hppa2.0n-* | hppa64-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \ + | alphaev6[78]-* \ + | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \ + | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \ + | mipstx39-* | mipstx39el-* | mcore-* \ + | f301-* | armv*-* | s390-* | sv1-* | t3e-* \ + | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \ + | thumb-* | v850-* | d30v-* | tic30-* | c30-* | fr30-* \ + | bs2000-* | tic54x-* | c54x-* | x86_64-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [ctj]90-cray) + basic_machine=c90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i[34567]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i[34567]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i[34567]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i[34567]86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + i386-go32 | go32) + basic_machine=i386-unknown + os=-go32 + ;; + i386-mingw32 | mingw32) + basic_machine=i386-unknown + os=-mingw32 + ;; + i[34567]86-pw32 | pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + msdos) + basic_machine=i386-unknown + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexgen) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon) + basic_machine=i686-pc + ;; + pentiumii | pentium2) + basic_machine=i686-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sparclite-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=t3e-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh3 | sh4) + basic_machine=sh-unknown + ;; + sparc | sparcv9) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + c4x*) + basic_machine=c4x-none + os=-coff + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* | -storm-chaos*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i[34567]86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto*) + os=-nto-qnx + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -*MiNT) + os=-mint + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f301-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -*MiNT) + vendor=atari + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "version='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100755 index 00000000..b1b32130 --- /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 +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA 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 if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac +# 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 &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +#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 +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} +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 ' \ + '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 +$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 + 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 +_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 + 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 +_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 +#include +#include +#include + +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + 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 + +_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 + +_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 +#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 +#include +#ifdef signal +# undef signal +#endif +#ifdef __cplusplus +extern "C" void (*signal (int, void (*)(int)))(int); +#else +void (*signal ()) (); +#endif + +int +main () +{ +int i; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&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 +_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 +_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 +/* 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 +/* 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 +#include +#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 +#include +#include + +main () +{ + int ac_sock; + + ac_sock = socket (AF_ROUTE, SOCK_RAW, 0); + if (ac_sock < 0 && errno == EINVAL) + exit (1); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + 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 +/* 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 + /* 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 +#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 +/* 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 +/* 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 +/* 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 +#include + +int +main () +{ +static struct sockaddr ac_i;int ac_j = sizeof (ac_i.sa_len); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&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 +#include + +int +main () +{ +static struct sockaddr_in ac_i;int ac_j = sizeof (ac_i.sin_len); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&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 +#include + +int +main () +{ +static struct sockaddr_un ac_i;int ac_j = sizeof (ac_i.sun_len); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&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 +#include + +int +main () +{ +static struct sockaddr_in6 ac_i;int ac_j = sizeof (ac_i.sin6_scope_id); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&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 +#include +#include + +int +main () +{ +socklen_t ac_x; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&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 + +_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 + +_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 + +_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 + +_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 + +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 + +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 +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +int +main () +{ +htonl (0); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&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 ." +_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 <>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # grep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if 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 index 00000000..bee8296a --- /dev/null +++ b/configure.in @@ -0,0 +1,873 @@ +## +## Configure template file for Zebra. +## autoconf will generate configure script. +## +## Copyright (c) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro +## +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 +#include ], [ +#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 +#include ], [ +#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 +#include +#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 +#include +#include + +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 + /* 2.1.128 or later */ + #if LINUX_VERSION_CODE >= 0x020180 + yes + #endif], + [zebra_cv_ipv6=yes; zebra_cv_linux_ipv6=yes;AC_MSG_RESULT(Linux IPv6)]) +else + if test x`ls /proc/net/ipv6_route 2>/dev/null` = x"/proc/net/ipv6_route" + then + zebra_cv_ipv6=yes + zebra_cv_linux_ipv6=yes + AC_MSG_RESULT(Linux IPv6) + fi +fi + +if test "$zebra_cv_linux_ipv6" = "yes";then + AC_DEFINE(HAVE_IPV6) + AC_MSG_CHECKING(for GNU libc 2.1) + AC_EGREP_CPP(yes, [ +#include +#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 + yes +#endif], [glibc=yes; AC_MSG_RESULT(yes)], AC_MSG_RESULT(no)) + AC_DEFINE(LINUX_IPV6) + 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 +#include +],[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 +#include +],[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 +#include +],[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 +#include +],[static struct sockaddr_in6 ac_i;int ac_j = sizeof (ac_i.sin6_scope_id);], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SIN6_SCOPE_ID)], + AC_MSG_RESULT(no)) +fi + +dnl ---------------------------- +dnl check socklen_t exist or not +dnl ---------------------------- +AC_MSG_CHECKING(whther socklen_t is defined) +AC_TRY_COMPILE([#include +#include +#include +],[socklen_t ac_x;], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SOCKLEN_T)], + 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 +],[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 +],[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 +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif], +[htonl (0);], +ac_cv_htonl_works=yes, +ac_cv_htonl_works=no)]) +AC_MSG_RESULT($ac_cv_htonl_works) + +AC_OUTPUT(Makefile lib/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile ospf6d/Makefile vtysh/Makefile doc/Makefile) + +echo " +zebra configuration +------------------- +zebra version : ${VERSION} +host operationg system : ${host_os} +source code location : ${srcdir} +compiler : ${CC} +compiler flags : ${CFLAGS} +directory for pid files : ${ac_piddir} +" diff --git a/depcomp b/depcomp new file mode 100755 index 00000000..807b991f --- /dev/null +++ b/depcomp @@ -0,0 +1,423 @@ +#! /bin/sh + +# depcomp - compile a program generating dependencies as side-effects +# Copyright 1999, 2000 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi +# `libtool' can also be set to `yes' or `no'. + +if test -z "$depfile"; then + base=`echo "$object" | sed -e 's,^.*/,,' -e 's,\.\([^.]*\)$,.P\1,'` + dir=`echo "$object" | sed 's,/.*$,/,'` + if test "$dir" = "$object"; then + dir= + fi + # FIXME: should be _deps on DOS. + depfile="$dir.deps/$base" +fi + +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. This file always lives in the current directory. + # Also, the AIX compiler puts `$object:' at the start of each line; + # $object doesn't have directory information. + stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + outname="$stripped.o" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + tmpdepfile1="$dir.libs/$base.lo.d" + tmpdepfile2="$dir.libs/$base.d" + "$@" -Wc,-MD + else + tmpdepfile1="$dir$base.o.d" + tmpdepfile2="$dir$base.d" + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + if test -f "$tmpdepfile1"; then + tmpdepfile="$tmpdepfile1" + else + tmpdepfile="$tmpdepfile2" + fi + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a space and a tab in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. We will use -o /dev/null later, + # however we can't do the remplacement now because + # `-o $object' might simply not be used + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + "$@" -o /dev/null $dashmflag | sed 's:^[^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + -*) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 diff --git a/doc/.cvsignore b/doc/.cvsignore new file mode 100644 index 00000000..2916b2f7 --- /dev/null +++ b/doc/.cvsignore @@ -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 index 00000000..0904e19f --- /dev/null +++ b/doc/BGP-TypeCode @@ -0,0 +1,24 @@ + + BGP-4[+] UPDATE Attribute TypeCode list + + Value Attribute References +========================================================================= + 1 ORIGIN [RFC 1771] + 2 AS_PATH [RFC 1771] + 3 NEXT_HOP [RFC 1771] + 4 MULTI_EXIT_DISC [RFC 1771] + 5 LOCAL_PREF [RFC 1771] + 6 ATOMIC_AGGREGATE [RFC 1771] + 7 AGGREGATOR [RFC 1771] + 8 COMMUNITIES [RFC 1997] + 9 ORIGINATOR_ID [RFC 1966] + 10 CLUSTER_LIST [RFC 1966] + 11 DPA [draft-ietf-idr-bgp-dpa-05.txt(expired)] + 12 ADVERTISER [Changed from RFC 1863 bgp@ans.net ML?] + 13 RCID_PATH [Changed from RFC 1863 bgp@ans.net ML?] + 14 MP_REACH_NLRI [RFC 2283] + 15 MP_UNREACH_NLRI [RFC 2283] + 16 EXT_COMMUNITIES [draft-ramachandra-bgp-ext-communities-09.txt] + 254 RCID_PATH [RFC 1863] + 255 ADVERTISER [RFC 1863] +========================================================================= diff --git a/doc/ChangeLog b/doc/ChangeLog new file mode 100644 index 00000000..cfe6e0e2 --- /dev/null +++ b/doc/ChangeLog @@ -0,0 +1,90 @@ +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2001-02-07 Pekka Savola + + * Correct bad English ;-). + +2001-02-01 Kunihiro Ishiguro + + * zebra-0.91 released. + +2001-01-09 Kunihiro Ishiguro + + * zebra-0.90 released. + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 released. + +2000-10-02 Horms + + * Makefile.am: Fix texinfo file installation problem. + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 released. + + * ospfd.texi (Redistribute routes to OSPF): distance <1-255> + @var{source} command is temporary disabled. So it is removed from + document. + +2000-07-04 Kunihiro Ishiguro + + * vtysh.1: Add man entry for vtysh. + + * bgpd.1: Change section to 8. + * ospfd.1: Likewise. + * ospf6d.1: Likewise. + * ripd.1: Likewise. + * ripngd.1: Likewise. + * zebra.1: Likewise. + +1999-09-01 "A.Waddington" + + * zebra.texi: Replace @command with @code until it gets ready. + Remove @macro. + +1999-08-26 Andrew Waddington + + * bgpd.1: Add man page. + ospf6d.1: Likewise. + ospfd.1: Likewise. + ripd.1: Likewise. + ripngd.1: Likewise. + zebra.1: Likewise. + +1999-08-14 Andrew Waddington + + * zebra.texi: Many typo is fixed. Some grammatical rectifications + is made. + +1999-07-27 Gerhard Poul + + * zebra.texi: Update zebra.texi. + +1999-07-02 Gerhard Poul + + * draft-zebra-00.ms: New file added. This is groff version of + draft-zebra-00.txt. This is a master file of draft-zebra-00.txt. + + * draft-zebra-00.txt: Generated from draft-zebra-00.txt. + +1999-05-07 Kunihiro Ishiguro + + * zebra.texi (Top): Add ospf6d chapter. + +1999-03-31 Jeroen Ruigrok/Asmodai + + * zebra.texi: Improve some sections. + +1999-03-04 Kunihiro Ishiguro + + * archfig.tex, zebra.sty, zebra.tex: Temporary removed due to the + description is out of date. + +1999-02-24 Kunihiro Ishiguro + + * texinfo.tex: New file added. Automake complains the absence of + texinfo.tex. diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 00000000..ee49cbd6 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,14 @@ +## Process this file with automake to produce Makefile.in. + +info_TEXINFOS = zebra.texi + +zebra_TEXINFOS = appendix.texi basic.texi bgpd.texi filter.texi install.texi \ + ipv6.texi kernel.texi main.texi ospf6d.texi ospfd.texi overview.texi \ + protocol.texi ripd.texi ripngd.texi routemap.texi snmp.texi vtysh.texi + +man_MANS = vtysh.1 bgpd.8 ospf6d.8 ospfd.8 ripd.8 ripngd.8 zebra.8 + +EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt $(man_MANS) + +draft-zebra-00.txt: + groff -T ascii -ms draft-zebra-00.ms > draft-zebra-00.txt diff --git a/doc/Makefile.in b/doc/Makefile.in new file mode 100644 index 00000000..66e35ec3 --- /dev/null +++ b/doc/Makefile.in @@ -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 index 00000000..7a052bcd --- /dev/null +++ b/doc/appendix.texi @@ -0,0 +1,238 @@ +@node Packet Binary Dump Format, , Zebra Protocol, Top +@comment node-name, next, previous, up +@appendix Packet Binary Dump Format + + Zebra can dump routing protocol packet into file with a binary format +(@pxref{Dump BGP packets and table}). + + It seems to be better that we share the MRT's header format for +backward compatibility with MRT's dump logs. We should also define the +binary format excluding the header, because we must support both IP +v4 and v6 addresses as socket addresses and / or routing entries. + + In the last meeting, we discussed to have a version field in the +header. But Masaki told us that we can define new `type' value rather +than having a `version' field, and it seems to be better because we +don't need to change header format. + + Here is the common header format. This is same as that of MRT. + +@example +@group +0 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Time | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Type | Subtype | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Length | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example + + If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_STATE_CHANGE, and +Address Family == IP (version 4) + +@example +@group + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source AS number | Destination AS number | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Interface Index | Address Family | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Old State | New State | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example + +Where State is the value defined in RFC1771. + +If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_STATE_CHANGE, +and Address Family == IP version 6 + +@example +@group + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source AS number | Destination AS number | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Interface Index | Address Family | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Old State | New State | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example + +If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_MESSAGE, +and Address Family == IP (version 4) + +@example +@group + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source AS number | Destination AS number | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Interface Index | Address Family | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| BGP Message Packet | +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example + +Where BGP Message Packet is the whole contents of the +BGP4 message including header portion. + +If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_MESSAGE, +and Address Family == IP version 6 + +@example +@group + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source AS number | Destination AS number | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Interface Index | Address Family | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| BGP Message Packet | +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example + +If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_ENTRY, +and Address Family == IP (version 4) + +@example +@group + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| View # | Status | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Time Last Change | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Address Family | SAFI | Next-Hop-Len | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Next Hop Address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Prefix Length | Address Prefix [variable] | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Attribute Length | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| BGP Attribute [variable length] | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example + +If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_ENTRY, +and Address Family == IP version 6 + +@example +@group + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| View # | Status | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Time Last Change | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Address Family | SAFI | Next-Hop-Len | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Next Hop Address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Next Hop Address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Next Hop Address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Next Hop Address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Prefix Length | Address Prefix [variable] | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Address Prefix (cont'd) [variable] | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Attribute Length | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| BGP Attribute [variable length] | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example + + BGP4 Attribute must not contain MP_UNREACH_NLRI. + If BGP Attribute has MP_REACH_NLRI field, it must has + zero length NLRI, e.g., MP_REACH_NLRI has only Address + Family, SAFI and next-hop values. + +If `type' is PROTOCOL_BGP4MP and `subtype' is BGP4MP_SNAPSHOT, + +@example +@group + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| View # | File Name [variable] | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example + + The file specified in "File Name" contains all routing entries, + which are in the format of ``subtype == BGP4MP_ENTRY''. + +@example +@group +Constants: + /* type value */ + #define MSG_PROTOCOL_BGP4MP 16 + /* subtype value */ + #define BGP4MP_STATE_CHANGE 0 + #define BGP4MP_MESSAGE 1 + #define BGP4MP_ENTRY 2 + #define BGP4MP_SNAPSHOT 3 +@end group +@end example diff --git a/doc/basic.texi b/doc/basic.texi new file mode 100644 index 00000000..8812b78c --- /dev/null +++ b/doc/basic.texi @@ -0,0 +1,510 @@ +@node Basic commands +@comment node-name, next, previous, up +@chapter Basic commands + +There are five routing daemons in use, and there is one manager daemon. +These daemons may be located on separate machines from the manager +daemon. Each of these daemons will listen on a particular port for +incoming VTY connections. The routing daemons are: + +@itemize @bullet +@item @command{ripd}, @command{ripngd}, @command{ospfd}, @command{ospf6d}, @command{bgpd} +@item @command{zebra} +@end itemize + +The following sections discuss commands common to all the routing +daemons. + +@menu +* Config Commands:: Commands used in config files +* Common Invocation Options:: Starting the daemons +* Virtual Terminal Interfaces:: Interacting with the daemons +@end menu + + + +@node Config Commands, Common Invocation Options, Basic commands, Basic commands +@comment node-name, next, previous, up +@section Config Commands + +@cindex Configuration files for running the software +@c A -not configuration files for installing the software +@cindex Files for running configurations +@cindex Modifying the herd's behavior +@cindex Getting the herd running + + +@menu +* Basic Config Commands:: Some of the generic config commands +* Sample Config File:: An example config file +@end menu + + +In a config file, you can write the debugging options, a vty's password, +routing daemon configurations, a log file name, and so forth. This +information forms the initial command set for a routing beast as it is +starting. + +Config files are generally found in: + +@itemize @asis +@item @file{@value{INSTALL_PREFIX_ETC}/*.conf} +@end itemize + +Each of the daemons has its own +config file. For example, zebra's default config file name is: + +@itemize @asis +@item @file{@value{INSTALL_PREFIX_ETC}/zebra.conf} +@end itemize + +The daemon name plus @file{.conf} is the default config file name. You +can specify a config file using the @kbd{-f} or @kbd{--config-file} +options when starting the daemon. + + + +@node Basic Config Commands, Sample Config File, Config Commands, Config Commands +@comment node-name, next, previous, up +@subsection Basic Config Commands + +@deffn Command {hostname @var{hostname}} {} +Set hostname of the router. +@end deffn + +@deffn Command {password @var{password}} {} +Set password for vty interface. If there is no password, a vty won't +accept connections. +@end deffn + +@deffn Command {enable password @var{password}} {} +Set enable password. +@end deffn + +@deffn Command {log stdout} {} +@deffnx Command {no log stdout} {} +Set logging output to stdout. +@end deffn + +@deffn Command {log file @var{filename}} {} +If you want to log into a file please specify @code{filename} as +follows. +@example +log file /usr/local/etc/bgpd.log +@end example +@end deffn + +@deffn Command {log syslog} {} +@deffnx Command {no log syslog} {} +Set logging output to syslog. +@end deffn + +@deffn Command {write terminal} {} +Displays the current configuration to the vty interface. +@end deffn + +@deffn Command {write file} {} +Write current configuration to configuration file. +@end deffn + +@deffn Command {configure terminal} {} +Change to configuration mode. This command is the first step to +configuration. +@end deffn + +@deffn Command {terminal length @var{<0-512>}} {} +Set terminal display length to @var{<0-512>}. If length is 0, no +display control is performed. +@end deffn + +@deffn Command {who} {} +@end deffn + +@deffn Command {list} {} +List commands. +@end deffn + +@deffn Command {service password-encryption} {} +Encrypt password. +@end deffn + +@deffn Command {service advanced-vty} {} +Enable advanced mode VTY. +@end deffn + +@deffn Command {service terminal-length @var{<0-512>}} {} +Set system wide line configuration. This configuration command applies +to all VTY interfaces. +@end deffn + +@deffn Command {show version} {} +Show the current version of the Zebra and its build host information. +@end deffn + +@deffn Command {line vty} {} +Enter vty configuration mode. +@end deffn + +@deffn Command {banner motd default} {} +Set default motd string. +@end deffn + +@deffn Command {no banner motd} {} +No motd banner string will be printed. +@end deffn + +@deffn {Line Command} {exec-timeout @var{minute}} {} +@deffnx {Line Command} {exec-timeout @var{minute} @var{second}} {} +Set VTY connection timeout value. When only one argument is specified +it is used for timeout value in minutes. Optional second argument is +used for timeout value in seconds. Default timeout value is 10 minutes. +When timeout value is zero, it means no timeout. +@end deffn + +@deffn {Line Command} {no exec-timeout} {} +Do not perform timeout at all. This command is as same as +@command{exec-timeout 0 0}. +@end deffn + +@deffn {Line Command} {access-class @var{access-list}} {} +Restrict vty connections with an access list. +@end deffn + + + +@node Sample Config File, , Basic Config Commands, Config Commands +@comment node-name, next, previous, up +@subsection Sample Config File + + +Below is a sample configuration file for the zebra daemon. + +@example +@group +! +! Zebra configuration file +! +hostname Router +password zebra +enable password zebra +! +log stdout +! +! +@end group +@end example + +'!' and '#' are comment characters. If the first character of the word +is one of the comment characters then from the rest of the line forward +will be ignored as a comment. + +@example +password zebra!password +@end example + +If a comment character is not the first character of the word, it's a +normal character. So in the above example '!' will not be regarded as a +comment and the password is set to 'zebra!password'. + + + +@node Common Invocation Options, Virtual Terminal Interfaces, Config Commands, Basic commands +@comment node-name, next, previous, up +@section Common Invocation Options +@c COMMON_OPTIONS +@c OPTIONS section of the man page + +These options apply to all Zebra daemons. + +@table @samp + +@item -d +@itemx --daemon +Runs in daemon mode. + +@item -f @var{file} +@itemx --config_file=@var{file} +Set configuration file name. + +@item -h +@itemx --help +Display this help and exit. + +@item -i @var{file} +@itemx --pid_file=@var{file} + +Upon startup the process identifier of the daemon is written to a file, +typically in @file{/var/run}. This file can be used by the init system +to implement commands such as @command{@dots{}/init.d/zebra status}, +@command{@dots{}/init.d/zebra restart} or @command{@dots{}/init.d/zebra +stop}. + +The file name is an run-time option rather than a configure-time option +so that multiple routing daemons can be run simultaneously. This is +useful when using Zebra to implement a routing looking glass. One +machine can be used to collect differing routing views from differing +points in the network. + +@item -P @var{port} +@itemx --vty_port=@var{port} +Set the VTY port number. + +@item -v +@itemx --version +Print program version. + +@end table + + + +@node Virtual Terminal Interfaces, , Common Invocation Options, Basic commands +@comment node-name, next, previous, up +@section Virtual Terminal Interfaces + +VTY -- Virtual Terminal [aka TeletYpe] Interface is a command line +interface (CLI) for user interaction with the routing daemon. + +@menu +* VTY Overview:: Basics about VTYs +* VTY Modes:: View, Enable, and Other VTY modes +* VTY CLI Commands:: Commands for movement, edition, and management +@end menu + + + +@node VTY Overview, VTY Modes, Virtual Terminal Interfaces, Virtual Terminal Interfaces +@comment node-name, next, previous, up +@subsection VTY Overview + + +VTY stands for Virtual TeletYpe interface. It means you can connect to +the daemon via the telnet protocol. + +To enable a VTY interface, you have to setup a VTY password. If there +is no VTY password, one cannot connect to the VTY interface at all. + +@example +@group +% telnet localhost 2601 +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + +Hello, this is zebra (version @value{VERSION}) +Copyright 1997-2000 Kunihiro Ishiguro + + +User Access Verification + +Password: XXXXX +Router> ? + enable Turn on privileged commands + exit Exit current mode and down to previous mode + help Description of the interactive help system + list Print command list + show Show running system information + who Display who is on a vty +Router> enable +Password: XXXXX +Router# configure terminal +Router(config)# interface eth0 +Router(config-if)# ip address 10.0.0.1/8 +Router(config-if)# ^Z +Router# +@end group +@end example + +'?' is very useful for looking up commands. + + + +@node VTY Modes, VTY CLI Commands, VTY Overview, Virtual Terminal Interfaces +@comment node-name, next, previous, up +@subsection VTY Modes + + +There are three basic VTY modes: + +@menu +* VTY View Mode:: Mode for read-only interaction +* VTY Enable Mode:: Mode for read-write interaction +* VTY Other Modes:: Special modes (tftp, etc) +@end menu + +There are commands that may be restricted to specific VTY modes. + + + +@node VTY View Mode, VTY Enable Mode, VTY Modes, VTY Modes +@comment node-name, next, previous, up +@subsubsection VTY View Mode +@c to be written (gpoul) + + +This mode is for read-only access to the CLI. One may exit the mode by +leaving the system, or by entering @code{enable} mode. + + + +@node VTY Enable Mode, VTY Other Modes, VTY View Mode, VTY Modes +@comment node-name, next, previous, up +@subsubsection VTY Enable Mode + + +@c to be written (gpoul) +This mode is for read-write access to the CLI. One may exit the mode by +leaving the system, or by escaping to view mode. + + + +@node VTY Other Modes, , VTY Enable Mode, VTY Modes +@comment node-name, next, previous, up +@subsubsection VTY Other Modes + + +@c to be written (gpoul) +This page is for describing other modes. + +@node VTY CLI Commands, , VTY Modes, Virtual Terminal Interfaces +@comment node-name, next, previous, up +@subsection VTY CLI Commands + + +Commands that you may use at the command-line are described in the following three subsubsections. + +@menu +* CLI Movement Commands:: Commands for moving the cursor about +* CLI Editing Commands:: Commands for changing text +* CLI Advanced Commands:: Other commands, session management and so on +@end menu + + + +@node CLI Movement Commands, CLI Editing Commands, VTY CLI Commands, VTY CLI Commands +@comment node-name, next, previous, up +@subsubsection CLI Movement Commands + + +These commands are used for moving the CLI cursor. The @key{C} character +means press the Control Key. + +@table @kbd + +@item C-f +@itemx @key{RIGHT} +@kindex C-f +@kindex @key{RIGHT} +Move forward one character. + +@item C-b +@itemx @key{LEFT} +@kindex C-b +@kindex @key{LEFT} +Move backward one character. + +@item M-f +@kindex M-f +Move forward one word. + +@item M-b +@kindex M-b +Move backward one word. + +@item C-a +@kindex C-a +Move to the beginning of the line. + +@item C-e +@kindex C-e +Move to the end of the line. + +@end table + + + +@node CLI Editing Commands, CLI Advanced Commands, CLI Movement Commands, VTY CLI Commands +@comment node-name, next, previous, up +@subsubsection CLI Editing Commands + + +These commands are used for editing text on a line. The @key{C} +character means press the Control Key. + +@table @kbd + +@item C-h +@itemx @key{DEL} +@kindex C-h +@kindex @key{DEL} +Delete the character before point. + +@item C-d +@kindex C-d +Delete the character after point. + +@item M-d +@kindex M-d +Forward kill word. + +@item C-w +@kindex C-w +Backward kill word. + +@item C-k +@kindex C-k +Kill to the end of the line. + +@item C-u +@kindex C-u +Kill line from the beginning, erasing input. + +@item C-t +@kindex C-t +Transpose character. + +@end table + + + +@node CLI Advanced Commands, , CLI Editing Commands, VTY CLI Commands +@comment node-name, next, previous, up +@subsubsection CLI Advanced Commands + + +There are several additional CLI commands for command line completions, +insta-help, and VTY session management. + +@table @kbd + +@item C-c +@kindex C-c +Interrupt current input and moves to the next line. + +@item C-z +@kindex C-z +End current configuration session and move to top node. + + +@item C-n +@itemx @key{DOWN} +@kindex C-n +@kindex @key{DOWN} +Move down to next line in the history buffer. + +@item C-p +@itemx @key{UP} +@kindex C-p +@kindex @key{UP} +Move up to previous line in the history buffer. + +@item TAB +@kindex @key{TAB} +Use command line completion by typing @key{TAB}. + +@item +@kindex ? +You can use command line help by typing @code{help} at the beginning of +the line. Typing @kbd{?} at any point in the line will show possible +completions. + +@end table diff --git a/doc/bgpd.8 b/doc/bgpd.8 new file mode 100644 index 00000000..cba3bdac --- /dev/null +++ b/doc/bgpd.8 @@ -0,0 +1,169 @@ +.TH BGPD 8 "July 2000" "Zebra Beast - BGPD" "Version 0.88" + +.SH NAME +bgpd \- a BGPv4, BGPv4+, BGPv4- routing engine for use with Zebra + +.SH SYNOPSIS +.B bgpd +[ +.B \-dhpPv +] +[ +.B \-f config-file +] +[ +.B \-i pid-file +] +[ +.B \-p bgp-port-number +] +[ +.B \--bgp_port=port-number +] +[ +.B \-P vty-port-number +] + +.SH DESCRIPTION +.B bgpd +is a routing component that works with the +.B zebra +routing engine. + + +.SH OPTIONS + +.TP +\fB\-d\fR, \fB\-\-daemon\fR +Runs in daemon mode, forking and exiting from tty. + +.TP +\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR +Specifies the config file to use for startup. If not specified this +option will likely default to \fB\fI/usr/local/etc/bgpd.conf\fR. + +.TP +\fB\-h\fR, \fB\-\-help\fR +A brief message. + +.TP +\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR +When bgpd starts its process idenifier is written to +\fB\fIpid-file\fR. The init system uses the recorded PID to stop or +restart bgpd. The likely default is \fB\fI/var/run/bgpd.pid\fR. + +.TP +\fB\-p\fR, \fB\-\-bgp_port=\fR\fIport\fR +Set the port that bgpd will listen to for bgp data. + +.TP +\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR +Specify the port that the bgpd VTY will listen on. This defaults to +2605, as specified in \fI/etc/services\fR. + +.TP +\fB\-r\fR, \fB\-\-retain\fR +When the program terminates, retain routes added by \fBbgpd\fR. + +.TP +\fB\-v\fR, \fB\-\-version\fR +Print the version and exit. + + +.SH COMMANDS + +\fB router zebra \fR -- (Move routes into kernel table) +\fB router bgp [AS-NUMBER] \fR + +\fB bgp router-id [BGP-ROUTER-ID] \fR + +\fB network [NETWORK] area [BGP-AREA-ID] \fR +\fB no network [NETWORK] \fR + +\fB aggregate-address [NETWORK] \fR + +\fB neighbor [PEER-IP-ADDRESS] remote-as [REMOTE-AS] \fR +\fB neighbor [PEER-IP-ADDRESS] version [ 4 | 4+ | 4- ] \fR + +\fB neighbor [PEER-IP-ADDRESS] description \fR +\fB no neighbor [PEER-IP-ADDRESS] description \fR + +\fB neighbor [PEER-IP-ADDRESS] route-map [in | out] \fR +\fB neighbor [PEER-IP-ADDRESS] distribute-list [in | out] \fR +\fB neighbor [PEER-IP-ADDRESS] next-hop-self \fR +\fB neighbor [PEER-IP-ADDRESS] weight [WEIGHT] \fR +\fB neighbor [PEER-IP-ADDRESS] default-originate \fR +\fB neighbor [PEER-IP-ADDRESS] ebgp-multihop \fR + +\fB neighbor [PEER-IP-ADDRESS] shutdown \fR +\fB no neighbor [PEER-IP-ADDRESS] shutdown \fR + +\fB clear ip bgp [PEER-IP-ADDRESS] \fR + +\fB show ip bgp [NETWORK] \fR +\fB show ip bgp reg-exp [AS-REGEXP] \fR +\fB show ip bgp summary \fR +\fB show ip bgp neighbor [PEER-IP-ADDRESS] \fR +\fB show ip bgp route \fR + +\fB show debug \fR + +\fB debug bgp \fR +\fB debug event \fR +\fB debug update \fR +\fB debug keepalive \fR + +\fB no debug event \fR +\fB no debug update \fR +\fB no debug keepalive \fR + + +.SH FILES + +.TP +.BI /usr/local/sbin/bgpd +The default location of the +.B bgpd +binary. + +.TP +.BI /usr/local/etc/bgpd.conf +The default location of the +.B bgpd +config file. + +.TP +.BI $(PWD)/bgpd.log +If the +.B bgpd +process is config'd to output logs to a file, then you will find this +file in the directory where you started \fBbgpd\fR. + + +.SH WARNING +This man page is intended as a quick reference for command line +options, and for config file commands. The definitive document is the +Info file \fBzebra\fR. + + +.SH DIAGNOSTICS +The bgpd process may log to standard output, to a VTY, to a log +file, or through syslog to the system logs. \fBbgpd\fR supports many +debugging options, see the Info file, or the source for details. + + +.SH "SEE ALSO" +References to other related man pages: + +ripd(8), ripngd(8), ospfd(8), ospf6d(8), zebra(8), vtysh(1) + + +.SH BUGS +.B bgpd +eats bugs for breakfast. If you have food for the maintainers try +.BI + + +.SH AUTHOR[S] +See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors. + diff --git a/doc/bgpd.texi b/doc/bgpd.texi new file mode 100644 index 00000000..c10fba96 --- /dev/null +++ b/doc/bgpd.texi @@ -0,0 +1,1288 @@ +@c -*-texinfo-*- +@c This is part of the GNU Zebra Manual. +@c Copyright (C) 1999, 2000, 2001 2002 Kunihiro Ishiguro +@c See file zebra.texi for copying conditions. +@node BGP +@comment node-name, next, previous, up +@chapter BGP + + BGP stands for a Border Gateway Protocol. The lastest BGP version +is 4. It is referred as BGP-4. BGP-4 is one of the Exterior Gateway +Protocols and de-fact standard of Inter Domain routing protocol. +BGP-4 is described in @code{RFC1771} - @cite{A Border Gateway Protocol +4 (BGP-4)}. + + Many extentions are added to @code{RFC1771}. @code{RFC2858} - +@cite{Multiprotocol Extensions for BGP-4} provide multiprotocol +support to BGP-4. + +@menu +* Starting BGP:: +* BGP router:: +* BGP network:: +* BGP Peer:: +* BGP Peer Group:: +* BGP Address Family:: +* Autonomous System:: +* BGP Communities Attribute:: +* BGP Extended Communities Attribute:: +* Displaying BGP routes:: +* Capability Negotiation:: +* Route Reflector:: +* Route Server:: +* How to set up a 6-Bone connection:: +* Dump BGP packets and table:: +@end menu + +@node Starting BGP, BGP router, BGP, BGP +@comment node-name, next, previous, up +@section Starting BGP + +Default configuration file of @command{bgpd} is @file{bgpd.conf}. +@command{bgpd} searches the current directory first then +@value{INSTALL_PREFIX_ETC}/bgpd.conf. All of bgpd's command must be +configured in @file{bgpd.conf}. + +@command{bgpd} specific invocation options are described below. Common +options may also be specified (@pxref{Common Invocation Options}). + +@table @samp +@item -p @var{PORT} +@itemx --bgp_port=@var{PORT} +Set the bgp protocol's port number. + +@item -r +@itemx --retain +When program terminates, retain BGP routes added by zebra. +@end table + +@node BGP router, BGP network, Starting BGP, BGP +@comment node-name, next, previous, up +@section BGP router + + First of all you must configure BGP router with @command{router bgp} +command. To configure BGP router, you need AS number. AS number is an +identification of autonomous system. BGP protocol uses the AS number +for detecting whether the BGP connection is internal one or external one. + +@deffn Command {router bgp @var{asn}} {} +Enable a BGP protocol process with the specified @var{asn}. After +this statement you can input any @code{BGP Commands}. You can not +create different BGP process under different @var{asn} without +specifying @code{multiple-instance} (@pxref{Multiple instance}). +@end deffn + +@deffn Command {no router bgp @var{asn}} {} +Destroy a BGP protocol process with the specified @var{asn}. +@end deffn + +@deffn {BGP} {bgp router-id @var{A.B.C.D}} {} +This command specifies the router-ID. If @command{bgpd} connects to @command{zebra} it gets +interface and address information. In that case default router ID value +is selected as the largest IP Address of the interfaces. When +@code{router zebra} is not enabled @command{bgpd} can't get interface information +so @code{router-id} is set to 0.0.0.0. So please set router-id by hand. +@end deffn + +@menu +* BGP distance:: +* BGP decision process:: +@end menu + +@node BGP distance, BGP decision process, BGP router, BGP router +@comment node-name, next, previous, up +@subsection BGP distance + +@deffn {BGP} {distance bgp <1-255> <1-255> <1-255>} {} +This command change distance value of BGP. Each argument is distance +value for external routes, internal routes and local routes. +@end deffn + +@deffn {BGP} {distance <1-255> @var{A.B.C.D/M}} {} +@deffnx {BGP} {distance <1-255> @var{A.B.C.D/M} @var{word}} {} +This command set distance value to +@end deffn + +@node BGP decision process, , BGP distance, BGP router +@comment node-name, next, previous, up +@subsection BGP decision process + +@table @asis +@item 1. Weight check + +@item 2. Local preference check. + +@item 3. Local route check. + +@item 4. AS path length check. + +@item 5. Origin check. + +@item 6. MED check. +@end table + +@node BGP network, BGP Peer, BGP router, BGP +@comment node-name, next, previous, up +@section BGP network + +@menu +* BGP route:: +* Route Aggregation:: +* Redistribute to BGP:: +@end menu + +@node BGP route, Route Aggregation, BGP network, BGP network +@comment node-name, next, previous, up +@subsection BGP route + +@deffn {BGP} {network @var{A.B.C.D/M}} {} +This command adds the announcement network. +@example +@group +router bgp 1 + network 10.0.0.0/8 +@end group +@end example +This configuration example says that network 10.0.0.0/8 will be +announced to all neighbors. Some vendors' routers don't advertise +routes if they aren't present in their IGP routing tables; @code{bgp} +doesn't care about IGP routes when announcing its routes. +@end deffn + +@deffn {BGP} {no network @var{A.B.C.D/M}} {} +@end deffn + +@node Route Aggregation, Redistribute to BGP, BGP route, BGP network +@comment node-name, next, previous, up +@subsection Route Aggregation + +@deffn {BGP} {aggregate-address @var{A.B.C.D/M}} {} +This command specifies an aggregate address. +@end deffn + +@deffn {BGP} {aggregate-address @var{A.B.C.D/M} as-set} {} +This command specifies an aggregate address. Resulting routes inlucde +AS set. +@end deffn + +@deffn {BGP} {aggregate-address @var{A.B.C.D/M} summary-only} {} +This command specifies an aggregate address. Aggreated routes will +not be announce. +@end deffn + +@deffn {BGP} {no aggregate-address @var{A.B.C.D/M}} {} +@end deffn + +@node Redistribute to BGP, , Route Aggregation, BGP network +@comment node-name, next, previous, up +@subsection Redistribute to BGP + +@deffn {BGP} {redistribute kernel} {} +Redistribute kernel route to BGP process. +@end deffn + +@deffn {BGP} {redistribute static} {} +Redistribute static route to BGP process. +@end deffn + +@deffn {BGP} {redistribute connected} {} +Redistribute connected route to BGP process. +@end deffn + +@deffn {BGP} {redistribute rip} {} +Redistribute RIP route to BGP process. +@end deffn + +@deffn {BGP} {redistribute ospf} {} +Redistribute OSPF route to BGP process. +@end deffn + +@node BGP Peer, BGP Peer Group, BGP network, BGP +@comment node-name, next, previous, up +@section BGP Peer + +@menu +* Defining Peer:: +* BGP Peer commands:: +* Peer filtering:: +@end menu + +@node Defining Peer, BGP Peer commands, BGP Peer, BGP Peer +@comment node-name, next, previous, up +@subsection Defining Peer + +@deffn {BGP} {neighbor @var{peer} remote-as @var{asn}} {} +Creates a new neighbor whose remote-as is @var{asn}. @var{peer} +can be an IPv4 address or an IPv6 address. +@example +@group +router bgp 1 + neighbor 10.0.0.1 remote-as 2 +@end group +@end example +In this case my router, in AS-1, is trying to peer with AS-2 at +10.0.0.1. + +This command must be the first command used when configuring a neighbor. +If the remote-as is not specified, @command{bgpd} will complain like this: +@example +can't find neighbor 10.0.0.1 +@end example +@end deffn + +@node BGP Peer commands, Peer filtering, Defining Peer, BGP Peer +@comment node-name, next, previous, up +@subsection BGP Peer commands + +In a @code{router bgp} clause there are neighbor specific configurations +required. + +@deffn {BGP} {neighbor @var{peer} shutdown} {} +@deffnx {BGP} {no neighbor @var{peer} shutdown} {} +Shutdown the peer. We can delete the neighbor's configuration by +@code{no neighbor @var{peer} remote-as @var{as-number}} but all +configuration of the neighbor will be deleted. When you want to +preserve the configuration, but want to drop the BGP peer, use this +syntax. +@end deffn + +@deffn {BGP} {neighbor @var{peer} ebgp-multihop} {} +@deffnx {BGP} {no neighbor @var{peer} ebgp-multihop} {} +@end deffn + +@deffn {BGP} {neighbor @var{peer} description ...} {} +@deffnx {BGP} {no neighbor @var{peer} description ...} {} +Set description of the peer. +@end deffn + +@deffn {BGP} {neighbor @var{peer} version @var{version}} {} +Set up the neighbor's BGP version. @var{version} can be @var{4}, +@var{4+} or @var{4-}. BGP version @var{4} is the default value used for +BGP peering. BGP version @var{4+} means that the neighbor supports +Multiprotocol Extensions for BGP-4. BGP version @var{4-} is similar but +the neighbor speaks the old Internet-Draft revision 00's Multiprotocol +Extensions for BGP-4. Some routing software is still using this +version. +@end deffn + +@deffn {BGP} {neighbor @var{peer} interface @var{ifname}} {} +@deffnx {BGP} {no neighbor @var{peer} interface @var{ifname}} {} +When you connect to a BGP peer over an IPv6 link-local address, you have +to specify the @var{ifname} of the interface used for the connection. +@end deffn + +@deffn {BGP} {neighbor @var{peer} next-hop-self} {} +@deffnx {BGP} {no neighbor @var{peer} next-hop-self} {} +This command specifies an announced route's nexthop as being equivalent +to the address of the bgp router. +@end deffn + +@deffn {BGP} {neighbor @var{peer} update-source} {} +@deffnx {BGP} {no neighbor @var{peer} update-source} {} +@end deffn + +@deffn {BGP} {neighbor @var{peer} default-originate} {} +@deffnx {BGP} {no neighbor @var{peer} default-originate} {} +@command{bgpd}'s default is to not announce the default route (0.0.0.0/0) even it +is in routing table. When you want to announce default routes to the +peer, use this command. +@end deffn + +@deffn {BGP} {neighbor @var{peer} port @var{port}} {} +@deffnx {BGP} {neighbor @var{peer} port @var{port}} {} +@end deffn + +@deffn {BGP} {neighbor @var{peer} send-community} {} +@deffnx {BGP} {neighbor @var{peer} send-community} {} +@end deffn + +@deffn {BGP} {neighbor @var{peer} weight @var{weight}} {} +@deffnx {BGP} {no neighbor @var{peer} weight @var{weight}} {} +This command specifies a default @var{weight} value for the neighbor's +routes. +@end deffn + +@deffn {BGP} {neighbor @var{peer} maximum-prefix @var{number}} {} +@deffnx {BGP} {no neighbor @var{peer} maximum-prefix @var{number}} {} +@end deffn + +@node Peer filtering, , BGP Peer commands, BGP Peer +@comment node-name, next, previous, up +@subsection Peer filtering + +@deffn {BGP} {neighbor @var{peer} distribute-list @var{name} [in|out]} {} +This command specifies a distribute-list for the peer. @var{direct} is +@samp{in} or @samp{out}. +@end deffn + +@deffn {BGP command} {neighbor @var{peer} prefix-list @var{name} [in|out]} {} +@end deffn + +@deffn {BGP command} {neighbor @var{peer} filter-list @var{name} [in|out]} {} +@end deffn + +@deffn {BGP} {neighbor @var{peer} route-map @var{name} [in|out]} {} +Apply a route-map on the neighbor. @var{direct} must be @code{in} or +@code{out}. +@end deffn + +@c ----------------------------------------------------------------------- +@node BGP Peer Group, BGP Address Family, BGP Peer, BGP +@comment node-name, next, previous, up +@section BGP Peer Group + +@deffn {BGP} {neighbor @var{word} peer-group} {} +This command defines a new peer group. +@end deffn + +@deffn {BGP} {neighbor @var{peer} peer-group @var{word}} {} +This command bind specific peer to peer group @var{word}. +@end deffn + +@node BGP Address Family, Autonomous System, BGP Peer Group, BGP +@comment node-name, next, previous, up +@section BGP Address Family + + + +@page +@c ----------------------------------------------------------------------- +@node Autonomous System, BGP Communities Attribute, BGP Address Family, BGP +@comment node-name, next, previous, up +@section Autonomous System + + AS (Autonomous System) is one of the essential element of BGP. BGP +is a distance vector routing protocol. AS framework provides distance +vector metric and loop detection to BGP. @code{RFC1930} - +@cite{Guidelines for creation, selection, and registration of an +Autonomous System (AS)} describes how to use AS. + + AS number is tow octet digita value. So the value range is from 1 +to 65535. AS numbers 64512 through 65535 are defined as private AS +numbers. Private AS numbers must not to be advertised in the global +Internet. + +@menu +* AS Path Regular Expression:: +* Display BGP Routes by AS Path:: +* AS Path Access List:: +* Using AS Path in Route Map:: +* Private AS Numbers:: +@end menu + +@node AS Path Regular Expression, Display BGP Routes by AS Path, Autonomous System, Autonomous System +@comment node-name, next, previous, up +@subsection AS Path Regular Expression + + AS path regular expression can be used for displaying BGP routes and +AS path access list. AS path regular expression is based on +@code{POSIX 1003.2} regular expressions. Following description is +just a subset of @code{POSIX} regular expression. User can use full +@code{POSIX} regular expression. Adding to that special character '_' +is added for AS path regular expression. + +@table @code +@item . +Matches any single character. +@item * +Matches 0 or more occurrences of pattern. +@item + +Matches 1 or more occurrences of pattern. +@item ? +Match 0 or 1 occurrences of pattern. +@item ^ +Matches the beginning of the line. +@item $ +Matches the end of the line. +@item _ +Character @code{_} has special meanings in AS path regular expression. +It matches to space and comma , and AS set delimiter @{ and @} and AS +confederation delimiter @code{(} and @code{)}. And it also matches to +the beginning of the line and the end of the line. So @code{_} can be +used for AS value boundaries match. @code{show ip bgp regexp _7675_} +matches to all of BGP routes which as AS number include @var{7675}. +@end table + +@node Display BGP Routes by AS Path, AS Path Access List, AS Path Regular Expression, Autonomous System +@comment node-name, next, previous, up +@subsection Display BGP Routes by AS Path + + To show BGP routes which has specific AS path information @code{show +ip bgp} command can be used. + +@deffn Command {show ip bgp regexp @var{line}} {} +This commands display BGP routes that matches AS path regular +expression @var{line}. +@end deffn + +@node AS Path Access List, Using AS Path in Route Map, Display BGP Routes by AS Path, Autonomous System +@comment node-name, next, previous, up +@subsection AS Path Access List + + AS path access list is user defined AS path. + +@deffn {Command} {ip as-path access-list @var{word} @{permit|deny@} @var{line}} {} +This command defines a new AS path access list. +@end deffn + +@deffn {Command} {no ip as-path access-list @var{word}} {} +@deffnx {Command} {no ip as-path access-list @var{word} @{permit|deny@} @var{line}} {} +@end deffn + +@node Using AS Path in Route Map, Private AS Numbers, AS Path Access List, Autonomous System +@comment node-name, next, previous, up +@subsection Using AS Path in Route Map + +@deffn {Route Map} {match as-path @var{word}} {} +@end deffn + +@deffn {Route Map} {set as-path prepend @var{as-path}} {} +@end deffn + +@node Private AS Numbers, , Using AS Path in Route Map, Autonomous System +@comment node-name, next, previous, up +@subsection Private AS Numbers + +@page +@c ----------------------------------------------------------------------- +@node BGP Communities Attribute, BGP Extended Communities Attribute, Autonomous System, BGP +@comment node-name, next, previous, up +@section BGP Communities Attribute + + BGP communities attribute is widely used for implementing policy +routing. Network operators can manipulate BGP communities attribute +based on their network policy. BGP communities attribute is defined +in @code{RFC1997} - @cite{BGP Communities Attribute} and +@code{RFC1998} - @cite{An Application of the BGP Community Attribute +in Multi-home Routing}. It is an optional transitive attribute, +therefore local policy can travel through different autonomous system. + + Communities attribute is a set of communities values. Each +communities value is 4 octet long. The following format is used to +define communities value. + +@table @code +@item AS:VAL +This format represents 4 octet communities value. @code{AS} is high +order 2 octet in digit format. @code{VAL} is low order 2 octet in +digit format. This format is useful to define AS oriented policy +value. For example, @code{7675:80} can be used when AS 7675 wants to +pass local policy value 80 to neighboring peer. +@item internet +@code{internet} represents well-known communities value 0. +@item no-export +@code{no-export} represents well-known communities value @code{NO_EXPORT}@* +@r{(0xFFFFFF01)}. All routes carry this value must not be advertised +to outside a BGP confederation boundary. If neighboring BGP peer is +part of BGP confederation, the peer is considered as inside a BGP +confederation boundary, so the route will be announced to the peer. +@item no-advertise +@code{no-advertise} represents well-known communities value +@code{NO_ADVERTISE}@*@r{(0xFFFFFF02)}. All routes carry this value +must not be advertise to other BGP peers. +@item local-AS +@code{local-AS} represents well-known communities value +@code{NO_EXPORT_SUBCONFED} @r{(0xFFFFFF03)}. All routes carry this +value must not be advertised to external BGP peers. Even if the +neighboring router is part of confederation, it is considered as +external BGP peer, so the route will not be announced to the peer. +@end table + + When BGP communities attribute is received, duplicated communities +value in the communities attribute is ignored and each communities +values are sorted in numerical order. + +@menu +* BGP Community Lists:: +* Numbered BGP Community Lists:: +* BGP Community in Route Map:: +* Display BGP Routes by Community:: +* Using BGP Communities Attribute:: +@end menu + +@node BGP Community Lists, Numbered BGP Community Lists, BGP Communities Attribute, BGP Communities Attribute +@comment node-name, next, previous, up +@subsection BGP Community Lists + + BGP community list is a user defined BGP communites attribute list. +BGP community list can be used for matching or manipulating BGP +communities attribute in updates. + + There are two types of community list. One is standard community +list and another is expanded community list. Standard community list +defines communities attribute. Expanded community list defines +communities attribute string with regular expression. Standard +community list is compiled into binary format when user define it. +Standard community list will be directly compared to BGP communities +attribute in BGP updates. Therefore the comparison is faster than +expanded community list. + +@deffn Command {ip community-list standard @var{name} @{permit|deny@} @var{community}} {} +This command defines a new standard community list. @var{community} +is communities value. The @var{community} is compiled into community +structure. We can define multiple community list under same name. In +that case match will happen user defined order. Once the +community list matches to communities attribute in BGP updates it +return permit or deny by the community list definition. When there is +no matched entry, deny will be returned. When @var{community} is +empty it matches to any routes. +@end deffn + +@deffn Command {ip community-list expanded @var{name} @{permit|deny@} @var{line}} {} +This command defines a new expanded community list. @var{line} is a +string expression of communities attribute. @var{line} can include +regular expression to match communities attribute in BGP updates. +@end deffn + +@deffn Command {no ip community-list @var{name}} {} +@deffnx Command {no ip community-list standard @var{name}} {} +@deffnx Command {no ip community-list expanded @var{name}} {} +These commands delete community lists specified by @var{name}. All of +community lists shares a single name space. So community lists can be +removed simpley specifying community lists name. +@end deffn + +@deffn {Command} {show ip community-list} {} +@deffnx {Command} {show ip community-list @var{name}} {} +This command display current community list information. When +@var{name} is specified the specified community list's information is +shown. + +@example +# show ip community-list +Named Community standard list CLIST + permit 7675:80 7675:100 no-export + deny internet +Named Community expanded list EXPAND + permit : + +# show ip community-list CLIST +Named Community standard list CLIST + permit 7675:80 7675:100 no-export + deny internet +@end example +@end deffn + +@node Numbered BGP Community Lists, BGP Community in Route Map, BGP Community Lists, BGP Communities Attribute +@comment node-name, next, previous, up +@subsection Numbered BGP Community Lists + + When number is used for BGP community list name, the number has +special meanings. Community list number in the range from 1 and 99 is +standard community list. Community list number in the range from 100 +to 199 is expanded community list. These community lists are called +as numbered community lists. On the other hand normal community lists +is called as named community lists. + +@deffn Command {ip community-list <1-99> @{permit|deny@} @var{community}} {} +This command defines a new community list. <1-99> is standard +community list number. Community list name within this range defines +standard community list. When @var{community} is empty it matches to +any routes. +@end deffn + +@deffn Command {ip community-list <100-199> @{permit|deny@} @var{community}} {} +This command defines a new community list. <100-199> is expanded +community list number. Community list name within this range defines +expanded community list. +@end deffn + +@deffn Command {ip community-list @var{name} @{permit|deny@} @var{community}} {} +When community list type is not specifed, the community list type is +automatically detected. If @var{community} can be compiled into +communities attribute, the community list is defined as a standard +community list. Otherwise it is defined as an expanded community +list. This feature is left for backward compability. Use of this +feature is not recommended. +@end deffn + +@node BGP Community in Route Map, Display BGP Routes by Community, Numbered BGP Community Lists, BGP Communities Attribute +@comment node-name, next, previous, up +@subsection BGP Community in Route Map + + In Route Map (@pxref{Route Map}), we can match or set BGP +communities attribute. Using this feature network operator can +implement their network policy based on BGP communities attribute. + + Following commands can be used in Route Map. + +@deffn {Route Map} {match community @var{word}} {} +@deffnx {Route Map} {match community @var{word} exact-match} {} +This command perform match to BGP updates using community list +@var{word}. When the one of BGP communities value match to the one of +communities value in community list, it is match. When +@code{exact-match} keyword is spcified, match happen only when BGP +updates have completely same communities value specified in the +community list. +@end deffn + +@deffn {Route Map} {set community none} {} +@deffnx {Route Map} {set community @var{community}} {} +@deffnx {Route Map} {set community @var{community} additive} {} +This command manipulate communities value in BGP updates. When +@code{none} is specified as communities value, it removes entire +communities attribute from BGP updates. When @var{community} is not +@code{none}, specified communities value is set to BGP updates. If +BGP updates already has BGP communities value, the existing BGP +communities value is replaced with specified @var{community} value. +When @code{additive} keyword is specified, @var{community} is appended +to the existing communities value. +@end deffn + +@deffn {Route Map} {set comm-list @var{word} delete} {} +This command remove communities value from BGP communities attribute. +The @var{word} is community list name. When BGP route's communities +value matches to the community list @var{word}, the communities value +is removed. When all of communities value is removed eventually, the +BGP update's communities attribute is completely removed. +@end deffn + +@node Display BGP Routes by Community, Using BGP Communities Attribute, BGP Community in Route Map, BGP Communities Attribute +@comment node-name, next, previous, up +@subsection Display BGP Routes by Community + + To show BGP routes which has specific BGP communities attribute, +@code{show ip bgp} command can be used. The @var{community} value and +community list can be used for @code{show ip bgp} command. + +@deffn Command {show ip bgp community} {} +@deffnx Command {show ip bgp community @var{community}} {} +@deffnx Command {show ip bgp community @var{community} exact-match} {} +@code{show ip bgp community} displays BGP routes which has communities +attribute. When @var{community} is specified, BGP routes that matches +@var{community} value is displayed. For this command, @code{internet} +keyword can't be used for @var{community} value. When +@code{exact-match} is specified, it display only routes that have an +exact match. +@end deffn + +@deffn Command {show ip bgp community-list @var{word}} {} +@deffnx Command {show ip bgp community-list @var{word} exact-match} {} +This commands display BGP routes that matches community list +@var{word}. When @code{exact-match} is specified, display only routes +that have an exact match. +@end deffn + +@node Using BGP Communities Attribute, , Display BGP Routes by Community, BGP Communities Attribute +@comment node-name, next, previous, up +@subsection Using BGP Communities Attribute + + Following configuration is the most typical usage of BGP communities +attribute. AS 7675 provides upstream Internet connection to AS 100. +When following configuration exists in AS 7675, AS 100 networks +operator can set local preference in AS 7675 network by setting BGP +communities attribute to the updates. + +@example +router bgp 7675 + neighbor 192.168.0.1 remote-as 100 + neighbor 192.168.0.1 route-map RMAP in +! +ip community-list 70 permit 7675:70 +ip community-list 70 deny +ip community-list 80 permit 7675:80 +ip community-list 80 deny +ip community-list 90 permit 7675:90 +ip community-list 90 deny +! +route-map RMAP permit 10 + match community 70 + set local-preference 70 +! +route-map RMAP permit 20 + match community 80 + set local-preference 80 +! +route-map RMAP permit 30 + match community 90 + set local-preference 90 +@end example + + Following configuration announce 10.0.0.0/8 from AS 100 to AS 7675. +The route has communities value 7675:80 so when above configuration +exists in AS 7675, announced route's local preference will be set to +value 80. + +@example +router bgp 100 + network 10.0.0.0/8 + neighbor 192.168.0.2 remote-as 7675 + neighbor 192.168.0.2 route-map RMAP out +! +ip prefix-list PLIST permit 10.0.0.0/8 +! +route-map RMAP permit 10 + match ip address prefix-list PLIST + set community 7675:80 +@end example + + Following configuration is an example of BGP route filtering using +communities attribute. This configuration only permit BGP routes +which has BGP communities value 0:80 or 0:90. Network operator can +put special internal communities value at BGP border router, then +limit the BGP routes announcement into the internal network. + +@example +router bgp 7675 + neighbor 192.168.0.1 remote-as 100 + neighbor 192.168.0.1 route-map RMAP in +! +ip community-list 1 permit 0:80 0:90 +! +route-map RMAP permit in + match community 1 +@end example + + Following exmaple filter BGP routes which has communities value 1:1. +When there is no match community-list returns deny. To avoid +filtering all of routes, we need to define permit any at last. + +@example +router bgp 7675 + neighbor 192.168.0.1 remote-as 100 + neighbor 192.168.0.1 route-map RMAP in +! +ip community-list standard FILTER deny 1:1 +ip community-list standard FILTER permit +! +route-map RMAP permit 10 + match community FILTER +@end example + + Communities value keyword @code{internet} has special meanings in +standard community lists. In below example @code{internet} act as +match any. It matches all of BGP routes even if the route does not +have communities attribute at all. So community list @code{INTERNET} +is same as above example's @code{FILTER}. + +@example +ip community-list standard INTERNET deny 1:1 +ip community-list standard INTERNET permit internet +@end example + + Following configuration is an example of communities value deletion. +With this configuration communities value 100:1 and 100:2 is removed +from BGP updates. For communities value deletion, only @code{permit} +community-list is used. @code{deny} community-list is ignored. + +@example +router bgp 7675 + neighbor 192.168.0.1 remote-as 100 + neighbor 192.168.0.1 route-map RMAP in +! +ip community-list standard DEL permit 100:1 100:2 +! +route-map RMAP permit 10 + set comm-list DEL delete +@end example + +@c ----------------------------------------------------------------------- +@node BGP Extended Communities Attribute, Displaying BGP routes, BGP Communities Attribute, BGP +@comment node-name, next, previous, up +@section BGP Extended Communities Attribute + + BGP extended communities attribute is introduced with MPLS VPN/BGP +technology. MPLS VPN/BGP expands capability of network infrastructure +to provide VPN functionality. At the same time it requires a new +framework for policy routing. With BGP Extended Communities Attribute +we can use Route Target or Site of Origin for implementing network +policy for MPLS VPN/BGP. + + BGP Extended Communities Attribute is similar to BGP Communities +Attribute. It is an optional transitive attribute. BGP Extended +Communities Attribute can carry multiple Extended Community value. +Each Extended Community value is eight octet length. + + BGP Extended Communities Attribute provides an extended range +compared with BGP Communities Attribute. Adding to that there is a +type field in each value to provides community space structure. + + There are two format to define Extended Community value. One is AS +based format the other is IP address based format. + +@table @code +@item AS:VAL +This is a format to define AS based Extended Community value. +@code{AS} part is 2 octets Global Administrator subfield in Extended +Community value. @code{VAL} part is 4 octets Local Administrator +subfield. @code{7675:100} represents AS 7675 policy value 100. +@item IP-Address:VAL +This is a format to define IP address based Extended Community value. +@code{IP-Address} part is 4 octets Global Administrator subfield. +@code{VAL} part is 2 octets Local Administrator subfield. +@code{10.0.0.1:100} represents +@end table + +@menu +* BGP Extended Community Lists:: +* BGP Extended Communities in Route Map:: +@end menu + +@node BGP Extended Community Lists, BGP Extended Communities in Route Map, BGP Extended Communities Attribute, BGP Extended Communities Attribute +@comment node-name, next, previous, up +@subsection BGP Extended Community Lists + + Expanded Community Lists is a user defined BGP Expanded Community +Lists. + +@deffn Command {ip extcommunity-list standard @var{name} @{permit|deny@} @var{extcommunity}} {} +This command defines a new standard extcommunity-list. +@var{extcommunity} is extended communities value. The +@var{extcommunity} is compiled into extended community structure. We +can define multiple extcommunity-list under same name. In that case +match will happen user defined order. Once the extcommunity-list +matches to extended communities attribute in BGP updates it return +permit or deny based upon the extcommunity-list definition. When +there is no matched entry, deny will be returned. When +@var{extcommunity} is empty it matches to any routes. +@end deffn + +@deffn Command {ip extcommunity-list expanded @var{name} @{permit|deny@} @var{line}} {} +This command defines a new expanded extcommunity-list. @var{line} is +a string expression of extended communities attribute. @var{line} can +include regular expression to match extended communities attribute in +BGP updates. +@end deffn + +@deffn Command {no ip extcommunity-list @var{name}} {} +@deffnx Command {no ip extcommunity-list standard @var{name}} {} +@deffnx Command {no ip extcommunity-list expanded @var{name}} {} +These commands delete extended community lists specified by +@var{name}. All of extended community lists shares a single name +space. So extended community lists can be removed simpley specifying +the name. +@end deffn + +@deffn {Command} {show ip extcommunity-list} {} +@deffnx {Command} {show ip extcommunity-list @var{name}} {} +This command display current extcommunity-list information. When +@var{name} is specified the community list's information is shown. + +@example +# show ip extcommunity-list +@end example +@end deffn + +@node BGP Extended Communities in Route Map, , BGP Extended Community Lists, BGP Extended Communities Attribute +@comment node-name, next, previous, up +@subsection BGP Extended Communities in Route Map + +@deffn {Route Map} {match extcommunity @var{word}} {} +@end deffn + +@deffn {Route Map} {set extcommunity rt @var{extcommunity}} {} +This command set Route Target value. +@end deffn + +@deffn {Route Map} {set extcommunity soo @var{extcommunity}} {} +This command set Site of Origin value. +@end deffn + +@c ----------------------------------------------------------------------- +@node Displaying BGP routes, Capability Negotiation, BGP Extended Communities Attribute, BGP +@comment node-name, next, previous, up +@section Displaying BGP Routes + +@menu +* Show IP BGP:: +* More Show IP BGP:: +@end menu + +@node Show IP BGP, More Show IP BGP, Displaying BGP routes, Displaying BGP routes +@comment node-name, next, previous, up +@subsection Show IP BGP + +@deffn {Command} {show ip bgp} {} +@deffnx {Command} {show ip bgp @var{A.B.C.D}} {} +@deffnx {Command} {show ip bgp @var{X:X::X:X}} {} +This command displays BGP routes. When no route is specified it +display all of IPv4 BGP routes. +@end deffn + +@example +BGP table version is 0, local router ID is 10.1.1.1 +Status codes: s suppressed, d damped, h history, * valid, > best, i - internal +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +*> 1.1.1.1/32 0.0.0.0 0 32768 i + +Total number of prefixes 1 +@end example + +@node More Show IP BGP, , Show IP BGP, Displaying BGP routes +@comment node-name, next, previous, up +@subsection More Show IP BGP + +@deffn {Command} {show ip bgp regexp @var{line}} {} +This command display BGP routes using AS path regular expression (@pxref{Display BGP Routes by AS Path}). +@end deffn + +@deffn Command {show ip bgp community @var{community}} {} +@deffnx Command {show ip bgp community @var{community} exact-match} {} +This command display BGP routes using @var{community} (@pxref{Display +BGP Routes by Community}). +@end deffn + +@deffn Command {show ip bgp community-list @var{word}} {} +@deffnx Command {show ip bgp community-list @var{word} exact-match} {} +This command display BGP routes using community list (@pxref{Display +BGP Routes by Community}). +@end deffn + +@deffn {Command} {show ip bgp summary} {} +@end deffn + +@deffn {Command} {show ip bgp neighbor [@var{peer}]} {} +@end deffn + +@deffn {Command} {clear ip bgp @var{peer}} {} +Clear peers which have addresses of X.X.X.X +@end deffn + +@deffn {Command} {clear ip bgp @var{peer} soft in} {} +Clear peer using soft reconfiguration. +@end deffn + +@deffn {Command} {show debug} {} +@end deffn + +@deffn {Command} {debug event} {} +@end deffn + +@deffn {Command} {debug update} {} +@end deffn + +@deffn {Command} {debug keepalive} {} +@end deffn + +@deffn {Command} {no debug event} {} +@end deffn + +@deffn {Command} {no debug update} {} +@end deffn + +@deffn {Command} {no debug keepalive} {} +@end deffn + +@node Capability Negotiation, Route Reflector, Displaying BGP routes, BGP +@comment node-name, next, previous, up +@section Capability Negotiation + + When adding IPv6 routing information exchange feature to BGP. There +were some proposals. @acronym{IETF} @acronym{IDR} working group finally +take a proposal called Multiprotocol Extension for BGP. The +specification is described in RFC2283. The protocol does not define new +protocols. It defines new attributes to existing BGP. When it is used +exchanging IPv6 routing information it is called BGP-4+. When it is +used for exchanging multicast routing information it is called MBGP. + + @command{bgpd} supports Multiprotocol Extension for BGP. So if remote peer +supports the protocol, @command{bgpd} can exchange IPv6 and/or multicast routing +information. + + Traditional BGP does not have the feature to detect remote peer's +capability whether it can handle other than IPv4 unicast routes. This +is a big problem using Multiprotocol Extension for BGP to operational +network. @cite{draft-ietf-idr-bgp4-cap-neg-04.txt} is proposing a +feature called Capability Negotiation. @command{bgpd} use this Capability +Negotiation to detect remote peer's capabilities. If the peer is only +configured as IPv4 unicast neighbor, @command{bgpd} does not send these Capability +Negotiation packets. + + By default, Zebra will bring up peering with minimal common capability +for the both sides. For example, local router has unicast and multicast +capabilitie and remote router has unicast capability. In this case, +the local router will establish the connection with unicast only capability. +When there are no common capabilities, Zebra sends Unsupported Capability +error and then resets the connection. + + If you want to completely match capabilities with remote peer. Please +use @command{strict-capability-match} command. + +@deffn {BGP} {neighbor @var{peer} strict-capability-match} {} +@deffnx {BGP} {no neighbor @var{peer} strict-capability-match} {} +Strictly compares remote capabilities and local capabilities. If capabilities +are different, send Unsupported Capability error then reset connection. +@end deffn + + You may want to disable sending Capability Negotiation OPEN message +optional parameter to the peer when remote peer does not implement +Capability Negotiation. Please use @command{dont-capability-negotiate} +command to disable the feature. + +@deffn {BGP} {neighbor @var{peer} dont-capability-negotiate} {} +@deffnx {BGP} {no neighbor @var{peer} dont-capability-negotiate} {} +Suppress sending Capability Negotiation as OPEN message optional +parameter to the peer. This command only affects the peer is configured +other than IPv4 unicast configuration. +@end deffn + + When remote peer does not have capability negotiation feature, remote +peer will not send any capabilities at all. In that case, bgp configures +the peer with configured capabilities. + + You may prefer locally configured capabilities more than the negotiated +capabilities even though remote peer sends capabilities. If the peer is +configured by @command{override-capability}, @command{bgpd} ignores received +capabilities then override negotiated capabilities with configured values. + +@deffn {BGP} {neighbor @var{peer} override-capability} {} +@deffnx {BGP} {no neighbor @var{peer} override-capability} {} +Override the result of Capability Negotiation with local configuration. +Ignore remote peer's capability value. +@end deffn + +@node Route Reflector, Route Server, Capability Negotiation, BGP +@comment node-name, next, previous, up +@section Route Reflector + +@deffn {BGP} {bgp cluster-id @var{a.b.c.d}} {} +@end deffn + +@deffn {BGP} {neighbor @var{peer} route-reflector-client} {} +@deffnx {BGP} {no neighbor @var{peer} route-reflector-client} {} +@end deffn + +@node Route Server, How to set up a 6-Bone connection, Route Reflector, BGP +@comment node-name, next, previous, up +@section Route Server + +At an Internet Exchange point, many ISPs are connected to each other by +external BGP peering. Normally these external BGP connection are done by +@code{full mesh} method. As with internal BGP full mesh formation, +this method has a scaling problem. + +This scaling problem is well known. Route Server is a method to resolve +the problem. Each ISP's BGP router only peers to Route Server. Route +Server serves as BGP information exchange to other BGP routers. By +applying this method, numbers of BGP connections is reduced from +O(n*(n-1)/2) to O(n). + +Unlike normal BGP router, Route Server must have several routing tables +for managing different routing policies for each BGP speaker. We call the +routing tables as different @code{view}s. @command{bgpd} can work as +normal BGP router or Route Server or both at the same time. + +@menu +* Multiple instance:: +* BGP instance and view:: +* Routing policy:: +* Viewing the view:: +@end menu + +@node Multiple instance, BGP instance and view, Route Server, Route Server +@comment node-name, next, previous, up +@subsection Multiple instance + +To enable multiple view function of @code{bgpd}, you must turn on +multiple instance feature beforehand. + +@deffn {Command} {bgp multiple-instance} {} +Enable BGP multiple instance feature. After this feature is enabled, +you can make multiple BGP instances or multiple BGP views. +@end deffn + +@deffn {Command} {no bgp multiple-instance} {} +Disable BGP multiple instance feature. You can not disable this feature +when BGP multiple instances or views exist. +@end deffn + +When you want to make configuration more Cisco like one, + +@deffn {Command} {bgp config-type cisco} {} +Cisco compatible BGP configuration output. +@end deffn + +When bgp config-type cisco is specified, + +``no synchronization'' is displayed. +``no auto-summary'' is desplayed. + +``network'' and ``aggregate-address'' argument is displayed as +``A.B.C.D M.M.M.M'' + +Zebra: network 10.0.0.0/8 +Cisco: network 10.0.0.0 + +Zebra: aggregate-address 192.168.0.0/24 +Cisco: aggregate-address 192.168.0.0 255.255.255.0 + +Community attribute handling is also different. If there is no +configuration is specified community attribute and extended community +attribute are sent to neighbor. When user manually disable the +feature community attribute is not sent to the neighbor. In case of +``bgp config-type cisco'' is specified, community attribute is not +sent to the neighbor by default. To send community attribute user has +to specify ``neighbor A.B.C.D send-community'' command. + +! +router bgp 1 + neighbor 10.0.0.1 remote-as 1 + no neighbor 10.0.0.1 send-community +! + +! +router bgp 1 + neighbor 10.0.0.1 remote-as 1 + neighbor 10.0.0.1 send-community +! + +@deffn {Command} {bgp config-type zebra} {} +Zebra style BGP configuration. This is default. +@end deffn + +@node BGP instance and view, Routing policy, Multiple instance, Route Server +@comment node-name, next, previous, up +@subsection BGP instance and view + +BGP instance is a normal BGP process. The result of route selection +goes to the kernel routing table. You can setup different AS at the +same time when BGP multiple instance feature is enabled. + +@deffn {Command} {router bgp @var{as-number}} {} +Make a new BGP instance. You can use arbitrary word for the @var{name}. +@end deffn + +@example +@group +bgp multiple-instance +! +router bgp 1 + neighbor 10.0.0.1 remote-as 2 + neighbor 10.0.0.2 remote-as 3 +! +router bgp 2 + neighbor 10.0.0.3 remote-as 4 + neighbor 10.0.0.4 remote-as 5 +@end group +@end example + +BGP view is almost same as normal BGP process. The result of +route selection does not go to the kernel routing table. BGP view is +only for exchanging BGP routing information. + +@deffn {Command} {router bgp @var{as-number} view @var{name}} {} +Make a new BGP view. You can use arbitrary word for the @var{name}. This +view's route selection result does not go to the kernel routing table. +@end deffn + +With this command, you can setup Route Server like below. + +@example +@group +bgp multiple-instance +! +router bgp 1 view 1 + neighbor 10.0.0.1 remote-as 2 + neighbor 10.0.0.2 remote-as 3 +! +router bgp 2 view 2 + neighbor 10.0.0.3 remote-as 4 + neighbor 10.0.0.4 remote-as 5 +@end group +@end example + +@node Routing policy, Viewing the view, BGP instance and view, Route Server +@comment node-name, next, previous, up +@subsection Routing policy + +You can set different routing policy for a peer. For example, you can +set different filter for a peer. + +@example +@group +bgp multiple-instance +! +router bgp 1 view 1 + neighbor 10.0.0.1 remote-as 2 + neighbor 10.0.0.1 distribute-list 1 in +! +router bgp 1 view 2 + neighbor 10.0.0.1 remote-as 2 + neighbor 10.0.0.1 distribute-list 2 in +@end group +@end example + +This means BGP update from a peer 10.0.0.1 goes to both BGP view 1 and view +2. When the update is inserted into view 1, distribute-list 1 is +applied. On the other hand, when the update is inserted into view 2, +distribute-list 2 is applied. + +@node Viewing the view, , Routing policy, Route Server +@comment node-name, next, previous, up +@subsection Viewing the view + +To display routing table of BGP view, you must specify view name. + +@deffn {Command} {show ip bgp view @var{name}} {} +Display routing table of BGP view @var{name}. +@end deffn + +@node How to set up a 6-Bone connection, Dump BGP packets and table, Route Server, BGP +@comment node-name, next, previous, up +@section How to set up a 6-Bone connection + +@example +@group +zebra configuration +=================== +! +! Actually there is no need to configure zebra +! + +bgpd configuration +================== +! +! This means that routes go through zebra and into the kernel. +! +router zebra +! +! MP-BGP configuration +! +router bgp 7675 + bgp router-id 10.0.0.1 + neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 remote-as @var{as-number} +! + address-family ipv6 + network 3ffe:506::/32 + neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 activate + neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 route-map set-nexthop out + neighbor 3ffe:1cfa:0:2:2c0:4fff:fe68:a231 remote-as @var{as-number} + neighbor 3ffe:1cfa:0:2:2c0:4fff:fe68:a231 route-map set-nexthop out + exit-address-family +! +ipv6 access-list all permit any +! +! Set output nexthop address. +! +route-map set-nexthop permit 10 + match ipv6 address all + set ipv6 nexthop global 3ffe:1cfa:0:2:2c0:4fff:fe68:a225 + set ipv6 nexthop local fe80::2c0:4fff:fe68:a225 +! +! logfile FILENAME is obsolete. Please use log file FILENAME +! +log file bgpd.log +! +@end group +@end example + +@node Dump BGP packets and table, , How to set up a 6-Bone connection, BGP +@comment node-name, next, previous, up +@section Dump BGP packets and table + +@deffn Command {dump bgp all @var{path}} {} +@deffnx Command {dump bgp all @var{path} @var{interval}} {} +Dump all BGP packet and events to @var{path} file. +@end deffn + +@deffn Command {dump bgp updates @var{path}} {} +@deffnx Command {dump bgp updates @var{path} @var{interval}} {} +Dump BGP updates to @var{path} file. +@end deffn + +@deffn Command {dump bgp routes @var{path}} {} +@deffnx Command {dump bgp routes @var{path}} {} +Dump whole BGP routing table to @var{path}. This is heavy process. +@end deffn diff --git a/doc/draft-zebra-00.ms b/doc/draft-zebra-00.ms new file mode 100644 index 00000000..25994727 --- /dev/null +++ b/doc/draft-zebra-00.ms @@ -0,0 +1,209 @@ +.pl 10.0i +.po 0 +.ll 7.2i +.lt 7.2i +.nr LL 7.2i +.nr LT 7.2i +.ds LF Ishiguro +.ds RF FORMFEED[Page %] +.ds CF +.ds LH RFC DRAFT +.ds RH March 1998 +.ds CH +.hy 0 +.ad l +Network Working Group K. Ishiguro +Request for Comments: DRAFT Digital Magic Labs, Inc. + March 1998 +.sp 2 +.ce +Zebra Protocol Draft +.sp 2 +.fi +.ne 4 +Status of this Memo +.sp +.in 3 +This draft is very eary beta version. +.sp +.in 0 +.ne 4 +Introduction +.sp +.in 3 +The zebra protocol is a communication protocol between kernel +routing table manager and routing protocol daemon. It is built over +TCP/IP protocol suite. +.sp +.in 0 +.ne 4 +Request message formats +.sp +.in 3 +zebra is TCP-based protocol. +.sp +Below is request packet format. +.sp +.in 0 +.DS +0 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Length (2) | Command (1) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +.DE +.sp +.in 3 +Length is total packet length. +.sp +Here is summary of command list. +.sp +.in 0 +.DS +1 - ZEBRA_IPV4_ROUTE_ADD +2 - ZEBRA_IPV4_ROUTE_DELETE +3 - ZEBRA_IPV6_ROUTE_ADD +4 - ZEBRA_IPV6_ROUTE_DELETE +5 - ZEBRA_GET_ONE_INTERFACE +6 - ZEBRA_GET_ALL_INTERFACE +7 - ZEBRA_GET_HOSTINFO +.DE +.sp +.in 0 +.ne 4 +IPv4 reply message formats +.sp +.in 0 +.DS +0 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+ +| Type (1) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Gateway (4) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +.DE +.sp +.in 3 +Type field specify route's origin type. +.sp +.in 0 +.DS +1 - ZEBRA_ROUTE_RESERVE +2 - ZEBRA_ROUTE_CONNECT +3 - ZEBRA_ROUTE_STATIC +4 - ZEBRA_ROUTE_RIP +5 - ZEBRA_ROUTE_RIPNG +6 - ZEBRA_ROUTE_BGP +7 - ZEBRA_ROUTE_RADIX +.DE +.sp +.in 3 +After above message there can be variale length IPv4 prefix data. +Each IPv4 prefix is encoded as a two tuple of the form +.sp +.in 0 +.DS ++----------------------+ +|Subnet mask (1 octet) | ++----------------------+ +|IPv4 prefix (variable)| ++----------------------+ +.DE +.sp +.in 0 +.ne 4 +IPv6 reply message formats +.sp +.in 0 +.DS +0 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+ +| Type (1) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Gateway (16) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +.DE +.sp +.in 3 +Type field specify route's origin type. +.sp +.in 0 +.DS +1 - ZEBRA_ROUTE_RESERVE +2 - ZEBRA_ROUTE_CONNECT +3 - ZEBRA_ROUTE_STATIC +4 - ZEBRA_ROUTE_RIP +5 - ZEBRA_ROUTE_RIPNG +6 - ZEBRA_ROUTE_BGP +7 - ZEBRA_ROUTE_RADIX +.DE +.sp +.in 0 +.DS ++----------------------+ +| ifindex (4 octet) | ++----------------------+ +| prefixlen (1 octet)| ++----------------------+ +|IPv6 prefix (variable)| ++----------------------+ +.DE +.sp +.in 3 +I am not sure but it seems some operation systems IPv6 +implementation may need interface index when add and delete +linklocal routes. +.sp +I have added ifindex field to specify IPv6 routes interface +index. If this index is value zero, it will ignored. +.sp +.in 0 +.ne 4 +Interface information message format. +.sp +.in 0 +.DS +0 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Interface name (20) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Index (1) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Inteface flag (4) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Inteface metric (4) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Inteface MTU (4) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Inteface Address count (4) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +.DE +.sp +.in 3 +Address message format. +.sp +.in 0 +.ne 4 +Host inforamtion message format. +.sp +.in 0 +.DS +0 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +|IPv4 forwarding|IPv6 forwarding| ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +.DE +.sp +.in 3 +Host information contain IPv4/IPv6 forwarding information. diff --git a/doc/filter.texi b/doc/filter.texi new file mode 100644 index 00000000..1bc70cdb --- /dev/null +++ b/doc/filter.texi @@ -0,0 +1,192 @@ +@node Filtering +@comment node-name, next, previous, up +@chapter Filtering + +Zebra provides many very flexible filtering features. Filtering is used +for both input and output of the routing information. Once filtering is +defined, it can be applied in any direction. + +@menu +* IP Access List:: +* IP Prefix List:: +@end menu + +@node IP Access List, IP Prefix List, Filtering, Filtering +@comment node-name, next, previous, up +@subsection IP Access List + +@deffn {Command} {access-list @var{name} permit @var{ipv4-network}} {} +@deffnx {Command} {access-list @var{name} deny @var{ipv4-network}} {} +@end deffn + +Basic filtering is done by @code{access-list} as shown in the +following example. + +@example +access-list filter deny 10.0.0.0/9 +access-list filter permit 10.0.0.0/8 +@end example + +@node IP Prefix List, , IP Access List, Filtering +@comment node-name, next, previous, up +@subsection IP Prefix List + +@command{ip prefix-list} provides the most powerful prefix based +filtering mechanism. In addition to @command{access-list} functionality, +@command{ip prefix-list} has prefix length range specification and +sequential number specification. You can add or delete prefix based +filters to arbitrary points of prefix-list using sequential number specification. + +If no ip prefix-list is specified, it acts as permit. If @command{ip prefix-list} +is defined, and no match is found, default deny is applied. + +@c @deffn {Command} {ip prefix-list @var{name} [seq @var{number}] permit|deny [le @var{prefixlen}] [ge @var{prefixlen}]} {} +@deffn {Command} {ip prefix-list @var{name} (permit|deny) @var{prefix} [le @var{len}] [ge @var{len}]} {} +@deffnx {Command} {ip prefix-list @var{name} seq @var{number} (permit|deny) @var{prefix} [le @var{len}] [ge @var{len}]} {} + +You can create @command{ip prefix-list} using above commands. + +@table @asis + +@item @asis{seq} +seq @var{number} can be set either automatically or manually. In the +case that sequential numbers are set manually, the user may pick any +number less than 4294967295. In the case that sequential number are set +automatically, the sequential number will increase by a unit of five (5) +per list. If a list with no specified sequential number is created +after a list with a specified sequential number, the list will +automatically pick the next multiple of five (5) as the list number. +For example, if a list with number 2 already exists and a new list with +no specified number is created, the next list will be numbered 5. If +lists 2 and 7 already exist and a new list with no specified number is +created, the new list will be numbered 10. + +@item @asis{le} +@command{le} command specifies prefix length. The prefix list will be +applied if the prefix length is less than or equal to the le prefix length. + +@item @asis{ge} +@command{ge} command specifies prefix length. The prefix list will be +applied if the prefix length is greater than or equal to the ge prefix length. + +@end table + +@end deffn + +Less than or equal to prefix numbers and greater than or equal to +prefix numbers can be used together. The order of the le and ge +commands does not matter. + +If a prefix list with a different sequential number but with the exact +same rules as a previous list is created, an error will result. +However, in the case that the sequential number and the rules are +exactly similar, no error will result. + +If a list with the same sequential number as a previous list is created, +the new list will overwrite the old list. + +Matching of IP Prefix is performed from the smaller sequential number to the +larger. The matching will stop once any rule has been applied. + +In the case of no le or ge command, + +Version 0.85: the matching rule will apply to all prefix lengths that +matched the prefix list. + +Version 0.86 or later: In the case of no le or ge command, the prefix +length must match exactly the length specified in the prefix list. + + +@deffn {Command} {no ip prefix-list @var{name}} {} +@end deffn + +@menu +* ip prefix-list description:: +* ip prefix-list sequential number control:: +* Showing ip prefix-list:: +* Clear counter of ip prefix-list:: +@end menu + +@node ip prefix-list description, ip prefix-list sequential number control, IP Prefix List, IP Prefix List +@comment node-name, next, previous, up +@subsubsection ip prefix-list description + +@deffn {Command} {ip prefix-list @var{name} description @var{desc}} {} +Descriptions may be added to prefix lists. This command adds a +description to the prefix list. +@end deffn + +@deffn {Command} {no ip prefix-list @var{name} description [@var{desc}]} {} +Deletes the description from a prefix list. It is possible to use the +command without the full description. +@end deffn + +@node ip prefix-list sequential number control, Showing ip prefix-list, ip prefix-list description, IP Prefix List +@comment node-name, next, previous, up +@subsubsection ip prefix-list sequential number control + +@deffn {Command} {ip prefix-list sequence-number} {} +With this command, the IP prefix list sequential number is displayed. +This is the default behavior. +@end deffn + +@deffn {Command} {no ip prefix-list sequence-number} {} +With this command, the IP prefix list sequential number is not +displayed. +@end deffn + +@node Showing ip prefix-list, Clear counter of ip prefix-list, ip prefix-list sequential number control, IP Prefix List +@comment node-name, next, previous, up +@subsubsection Showing ip prefix-list + +@deffn {Command} {show ip prefix-list} {} +Display all IP prefix lists. +@end deffn + +@deffn {Command} {show ip prefix-list @var{name}} {} +Show IP prefix list can be used with a prefix list name. +@end deffn + +@deffn {Command} {show ip prefix-list @var{name} seq @var{num}} {} +Show IP prefix list can be used with a prefix list name and sequential +number. +@end deffn + +@deffn {Command} {show ip prefix-list @var{name} @var{a.b.c.d/m}} {} +If the command longer is used, all prefix lists with prefix lengths equal to +or longer than the specified length will be displayed. +If the command first match is used, the first prefix length match will be +displayed. +@end deffn + +@deffn {Command} {show ip prefix-list @var{name} @var{a.b.c.d/m} longer} {} +@end deffn + +@deffn {Command} {show ip prefix-list @var{name} @var{a.b.c.d/m} first-match} {} +@end deffn + +@deffn {Command} {show ip prefix-list summary} {} +@end deffn +@deffn {Command} {show ip prefix-list summary @var{name}} {} +@end deffn + +@deffn {Command} {show ip prefix-list detail} {} +@end deffn +@deffn {Command} {show ip prefix-list detail @var{name}} {} +@end deffn + +@node Clear counter of ip prefix-list, , Showing ip prefix-list, IP Prefix List +@comment node-name, next, previous, up +@subsubsection Clear counter of ip prefix-list + +@deffn {Command} {clear ip prefix-list} {} +Clears the counters of all IP prefix lists. Clear IP Prefix List can be +used with a specified name and prefix. +@end deffn + +@deffn {Command} {clear ip prefix-list @var{name}} {} +@end deffn + +@deffn {Command} {clear ip prefix-list @var{name} @var{a.b.c.d/m}} {} +@end deffn + diff --git a/doc/install.texi b/doc/install.texi new file mode 100644 index 00000000..72c826d6 --- /dev/null +++ b/doc/install.texi @@ -0,0 +1,218 @@ +@node Installation, Basic commands, Overview, Top +@comment node-name, next, previous, up +@chapter Installation + +@cindex How to install Zebra +@cindex Installation +@cindex Installing Zebra +@cindex Building the system +@cindex Making Zebra + + There are three steps for installing the software: configuration, +compilation, and installation. + +@menu +* Configure the Software:: +* Build the Software:: +* Install the Software:: +@end menu + + The easiest way to get Zebra running is to issue the following +commands: + +@example +% configure +% make +% make install +@end example + +@node Configure the Software, Build the Software, Installation, Installation +@comment node-name, next, previous, up +@section Configure the Software + +@cindex Configuration options +@cindex Options for configuring +@cindex Build options +@cindex Distribution configuration +@cindex Options to @code{./configure} + + Zebra has an excellent configure script which +automatically detects most host configurations. There are several +additional configure options you can use to turn off IPv6 support, to +disable the compilation of specific daemons, and to enable SNMP support. + +@table @option +@item --enable-guile +Turn on compilation of the zebra-guile interpreter. You will need the +guile library to make this. zebra-guile implementation is not yet +finished. So this option is only useful for zebra-guile developers. +@item --disable-ipv6 +Turn off IPv6 related features and daemons. Zebra configure script +automatically detects IPv6 stack. But sometimes you might want to +disable IPv6 support of Zebra. +@item --disable-zebra +Do not build zebra daemon. +@item --disable-ripd +Do not build ripd. +@item --disable-ripngd +Do not build ripngd. +@item --disable-ospfd +Do not build ospfd. +@item --disable-ospf6d +Do not build ospf6d. +@item --disable-bgpd +Do not build bgpd. +@item --disable-bgp-announce +Make @command{bgpd} which does not make bgp announcements at all. This +feature is good for using @command{bgpd} as a BGP announcement listener. +@item --enable-netlink +Force to enable @sc{gnu}/Linux netlink interface. Zebra configure +script detects netlink interface by checking a header file. When the header +file does not match to the current running kernel, configure script will +not turn on netlink support. +@item --enable-snmp +Enable SNMP support. By default, SNMP support is disabled. +@end table + +You may specify any combination of the above options to the configure +script. By default, the executables are placed in @file{/usr/local/sbin} +and the configuration files in @file{/usr/local/etc}. The @file{/usr/local/} +installation prefix and other directories may be changed using the following +options to the configuration script. + +@table @option +@item --prefix=@var{prefix} +Install architecture-independent files in @var{prefix} [/usr/local]. +@item --sysconfdir=@var{dir} +Read-only sample configuration file in @var{dir} [@var{prefix}/etc]. +@end table + +@example +% ./configure --disable-ipv6 +@end example + +This command will configure zebra and the routing daemons. + +@cindex Configuring Zebra +@cindex Configuration the software build +@cindex Building on Linux boxes +@cindex Linux configurations + +There are several options available only to @sc{gnu}/Linux systems: +@footnote{GNU/Linux has very flexible kernel configuration features. If +you use GNU/Linux, make sure that the current kernel configuration is +what you want. Zebra will run with any kernel configuration but some +recommendations do exist. + +@table @var + +@item CONFIG_NETLINK +Kernel/User netlink socket. +This is a brand new feature which enables +an advanced interface between the Linux kernel and Zebra (@pxref{Kernel Interface}). + +@item CONFIG_RTNETLINK +Routing messages. +This makes it possible to receive netlink routing messages. If you +specify this option, @command{zebra} can detect routing information +updates directly from the kernel (@pxref{Kernel Interface}). + +@item CONFIG_IP_MULTICAST +IP: multicasting. +This option should be specified when you use @command{ripd} or +@command{ospfd} because these protocols use multicast. + +@end table + +IPv6 support has been added in @sc{gnu}/Linux kernel version 2.2. If you +try to use the Zebra IPv6 feature on a @sc{gnu}/Linux kernel, please +make sure the following libraries have been installed. Please note that +these libraries will not be needed when you uses @sc{gnu} C library 2.1 +or upper. + +@table @code + +@item inet6-apps +The @code{inet6-apps} package includes basic IPv6 related libraries such +as @code{inet_ntop} and @code{inet_pton}. Some basic IPv6 programs such +as @command{ping}, @command{ftp}, and @command{inetd} are also +included. The @code{inet-apps} can be found at +@url{ftp://ftp.inner.net/pub/ipv6/}. + +@item net-tools +The @code{net-tools} package provides an IPv6 enabled interface and +routing utility. It contains @command{ifconfig}, @command{route}, +@command{netstat}, and other tools. @code{net-tools} may be found at +@url{http://www.tazenda.demon.co.uk/phil/net-tools/}. + +@end table +@c A - end of footnote +}. + +@node Build the Software, Install the Software, Configure the Software, Installation +@comment node-name, next, previous, up +@section Build the Software + +After configuring the software, you will need to compile it for your +system. Simply issue the command @command{make} in the root of the source +directory and the software will be compiled. If you have *any* problems +at this stage, be certain to send a bug report @xref{Bug Reports}. + +@example +% ./configure +. +. +. +./configure output +. +. +. +% make +@end example +@c A - End of node, Building the Software + + +@node Install the Software, , Build the Software, Installation +@comment node-name, next, previous, up +@section Install the Software + +Installing the software to your system consists of copying the compiled +programs and supporting files to a standard location. After the +installation process has completed, these files have been copied +from your work directory to @file{/usr/local/bin}, and @file{/usr/local/etc}. + +To install the Zebra suite, issue the following command at your shell +prompt: @command{make install}. + +@example +% +% make install +% +@end example + +@c A - removed this section and placed it with Install the Software +@c @node Additional Notes, , Install the Software, Installation +@comment node-name, next, previous, up +@c @section Additional Notes + +Zebra daemons have their own terminal interface or VTY. After +installation, you have to setup each beast's port number to connect to +them. Please add the following entries to @file{/etc/services}. + +@example +zebrasrv 2600/tcp # zebra service +zebra 2601/tcp # zebra vty +ripd 2602/tcp # RIPd vty +ripngd 2603/tcp # RIPngd vty +ospfd 2604/tcp # OSPFd vty +bgpd 2605/tcp # BGPd vty +ospf6d 2606/tcp # OSPF6d vty +@end example + +If you use a FreeBSD newer than 2.2.8, the above entries are already +added to @file{/etc/services} so there is no need to add it. If you +specify a port number when starting the daemon, these entries may not be +needed. + +You may need to make changes to the config files in +@file{@value{INSTALL_PREFIX_ETC}/*.conf}. @xref{Config Commands}. diff --git a/doc/ipv6.texi b/doc/ipv6.texi new file mode 100644 index 00000000..c24d1453 --- /dev/null +++ b/doc/ipv6.texi @@ -0,0 +1,32 @@ +@node IPv6 Support, Kernel Interface, Route Map, Top +@comment node-name, next, previous, up +@chapter IPv6 Support + +Zebra fully supports IPv6 routing. As described so far, Zebra supports +RIPng, OSPFv3 and BGP-4+. You can give IPv6 addresses to an interface +and configure static IPv6 routing information. Zebra-IPv6 also provides +automatic address configuration via a feature called @code{address +auto configuration}. To do it, the router must send router advertisement +messages to the all nodes that exist on the network. + +@menu +* Router Advertisement:: +@end menu + +@node Router Advertisement, , IPv6 Support, IPv6 Support +@comment node-name, next, previous, up +@section Router Advertisement + +@deffn {Interface Command} {ipv6 nd send-ra} {} +@end deffn + +@deffn {Interface Command} {ipv6 nd prefix-advertisement @var{ipv6prefix}} {} +@end deffn + +@example +@group +interface eth0 + ipv6 nd send-ra + ipv6 nd prefix-advertisement 3ffe:506:5009::/64 +@end group +@end example diff --git a/doc/kernel.texi b/doc/kernel.texi new file mode 100644 index 00000000..b863a1f6 --- /dev/null +++ b/doc/kernel.texi @@ -0,0 +1,48 @@ +@node Kernel Interface, SNMP Support, IPv6 Support, Top +@comment node-name, next, previous, up +@chapter Kernel Interface + +There are several different methods for reading kernel routing table +information, updating kernel routing tables, and for looking up +interfaces. + +@table @samp + +@item ioctl +The @samp{ioctl} method is a very traditional way for reading or writing +kernel information. @samp{ioctl} can be used for looking up interfaces +and for modifying interface addresses, flags, mtu settings and other +types of information. Also, @samp{ioctl} can insert and delete kernel +routing table entries. It will soon be available on almost any platform +which zebra supports, but it is a little bit ugly thus far, so if a +better method is supported by the kernel, zebra will use that. + +@item sysctl +@samp{sysctl} can lookup kernel information using MIB (Management +Information Base) syntax. Normally, it only provides a way of getting +information from the kernel. So one would usually want to change kernel +information using another method such as @samp{ioctl}. + +@item proc filesystem +@samp{proc filesystem} provides an easy way of getting kernel +information. + +@item routing socket + +@item netlink +On recent Linux kernels (2.0.x and 2.2.x), there is a kernel/user +communication support called @code{netlink}. It makes asynchronous +communication between kernel and Zebra possible, similar to a routing +socket on BSD systems. + +Before you use this feature, be sure to select (in kernel configuration) +the kernel/netlink support option 'Kernel/User network link driver' and +'Routing messages'. + +Today, the /dev/route special device file is obsolete. Netlink +communication is done by reading/writing over netlink socket. + +After the kernel configuration, please reconfigure and rebuild Zebra. +You can use netlink as a dynamic routing update channel between Zebra +and the kernel. +@end table diff --git a/doc/main.texi b/doc/main.texi new file mode 100644 index 00000000..7043bf14 --- /dev/null +++ b/doc/main.texi @@ -0,0 +1,186 @@ +@node Zebra +@comment node-name, next, previous, up +@chapter Zebra + +@c SYNOPSIS +@command{zebra} is an IP routing manager. It provides kernel routing +table updates, interface lookups, and redistribution of routes between +different routing protocols. + +@menu +* Invoking zebra:: Running the program +* Interface Commands:: Commands for zebra interfaces +* Static Route Commands:: Commands for adding static routes +* zebra Terminal Mode Commands:: Commands for zebra's VTY +@end menu + + +@node Invoking zebra, Interface Commands, Zebra, Zebra +@comment node-name, next, previous, up +@section Invoking zebra + +Besides the common invocation options (@pxref{Common Invocation Options}), the +@command{zebra} specific invocation options are listed below. + +@table @samp +@item -b +@itemx --batch +Runs in batch mode. @command{zebra} parses configuration file and terminates +immediately. + +@item -k +@itemx --keep_kernel +When zebra starts up, don't delete old self inserted routes. + +@item -l +@itemx --log_mode +Set verbose logging on. + +@item -r +@itemx --retain +When program terminates, retain routes added by zebra. + +@end table + +@node Interface Commands, Static Route Commands, Invoking zebra, Zebra +@comment node-name, next, previous, up +@section Interface Commands + +@deffn Command {interface @var{ifname}} {} +@end deffn + +@deffn {Interface Command} {shutdown} {} +@deffnx {Interface Command} {no shutdown} {} +Up or down the current interface. +@end deffn + +@deffn {Interface Command} {ip address @var{address}} {} +Set ip address for the interface. +@end deffn + +@deffn {Interface Command} {description @var{description} ...} {} +Set description for the interface. +@end deffn + +@deffn {Interface Command} {multicast} {} +@deffnx {Interface Command} {no multicast} {} +Enable or disables multicast flag for the interface. +@end deffn + +@deffn {Interface Command} {bandwidth <1-10000000>} {} +@deffnx {Interface Command} {no bandwidth <1-10000000>} {} +Set bandwidth value to the interface. This is for calculating OSPF +cost. This command does not affect the actual device configuration. +@end deffn + +@node Static Route Commands, zebra Terminal Mode Commands, Interface Commands, Zebra +@comment node-name, next, previous, up +@section Static Route Commands + +Static routing is a very fundamental feature of routing technology. It +defines static prefix and gateway. + +@deffn Command {ip route @var{network} @var{gateway}} {} +@var{network} is destination prefix with format of A.B.C.D/M. +@var{gateway} is gateway for the prefix. When @var{gateway} is +A.B.C.D format. It is taken as a IPv4 address gateway. Otherwise it +is treated as an interface name. + +@example +ip route 10.0.0.0/8 10.0.0.2 +ip route 10.0.0.0/8 ppp0 +@end example + +First example defines 10.0.0.0/8 static route with gateway 10.0.0.2. +Second one defines the same prefix but with gateway to interface ppp0. +@end deffn + +@deffn Command {ip route @var{network} @var{netmask} @var{gateway}} {} +This is alternate version of above command. When @var{network} is +A.B.C.D format, user must define @var{netmask} value with A.B.C.D +format. @var{gateway} is same option as above command + +@example +ip route 10.0.0.0 255.255.255.0 10.0.0.2 +ip route 10.0.0.0 255.255.255.0 ppp0 +@end example + +This is a same setting using this statement. +@end deffn + +@deffn Command {ip route @var{network} @var{gateway} @var{distance}} {} + +@end deffn + +Multiple nexthop static route + +@example +ip route 10.0.0.1/32 10.0.0.2 +ip route 10.0.0.1/32 10.0.0.3 +ip route 10.0.0.1/32 eth0 +@end example + +If there is no route to 10.0.0.2 and 10.0.0.3, and interface eth0 +is reachable, then the last route is installed into the kernel. + +@example +zebra> show ip route +S> 10.0.0.1/32 [1/0] via 10.0.0.2 inactive + via 10.0.0.3 inactive + * is directly connected, eth0 +@end example + +Floating static route + +@deffn Command {ipv6 route @var{network} @var{gateway}} {} + +@end deffn + +@deffn Command {ipv6 route @var{network} @var{gateway} @var{distance}} {} + +@end deffn + + +@deffn Command {table @var{tableno}} {} +Select the primary kernel routing table to be used. This only works +for kernels supporting multiple routing tables (like GNU/Linux 2.2.x +and later). After setting @var{tableno} with this command, +static routes defined after this are added to the specified table. +@end deffn + +@node zebra Terminal Mode Commands, , Static Route Commands, Zebra +@comment node-name, next, previous, up +@section zebra Terminal Mode Commands + +@deffn Command {show ip route} {} +Display current routes which zebra holds in its database. + +@example +@group +Router# show ip route +Codes: K - kernel route, C - connected, S - static, R - RIP, + B - BGP * - FIB route. + +K* 0.0.0.0/0 203.181.89.241 +S 0.0.0.0/0 203.181.89.1 +C* 127.0.0.0/8 lo +C* 203.181.89.240/28 eth0 +@end group +@end example +@end deffn + +@deffn Command {show ipv6 route} {} +@end deffn + +@deffn Command {show interface} {} +@end deffn + +@deffn Command {show ipforward} {} +Display whether the host's IP forwarding function is enabled or not. +Almost any UNIX kernel can be configured with IP forwarding disabled. +If so, the box can't work as a router. +@end deffn + +@deffn Command {show ipv6forward} {} +Display whether the host's IP v6 forwarding is enabled or not. +@end deffn diff --git a/doc/ospf6d.8 b/doc/ospf6d.8 new file mode 100644 index 00000000..1882c10e --- /dev/null +++ b/doc/ospf6d.8 @@ -0,0 +1,127 @@ +.TH OSPF6D 8 "July 2000" "Zebra Beast - OSPF6D" "Version 0.88" + +.SH NAME +ospf6d \- an OSPF routing engine for use with Zebra and IPv6 + +.SH SYNOPSIS +.B ospf6d +[ +.B \-dhv +] +[ +.B \-f config-file +] +[ +.B \-i pid-file +] +[ +.B \-P port-number +] + +.SH DESCRIPTION +.B ospf6d +is a routing component that works with the +.B zebra +routing engine. +\fBospf6d\fR. + + +.SH OPTIONS + +.TP +\fB\-d\fR, \fB\-\-daemon\fR +Runs in daemon mode, forking and exiting from tty. + +.TP +\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR +Specifies the config file to use for startup. If not specified this +option will likely default to \fB\fI/usr/local/etc/ospf6d.conf\fR. + +.TP +\fB\-h\fR, \fB\-\-help\fR +A brief message. + +.TP +\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR +When ospf6d starts its process idenifier is written to +\fB\fIpid-file\fR. The init system uses the recorded PID to stop or +restart ospf6d. The likely default is \fB\fI/var/run/ospf6d.pid\fR. + +.TP +\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR +Specify the port that the ospf6d VTY will listen on. This defaults to +2606, as specified in \fB\fI/etc/services\fR. + +.TP +\fB\-v\fR, \fB\-\-version\fR +Print the version and exit. + + +.SH COMMANDS + +\fB router ospf6 \fR +\fB router zebra \fR -- (Move routes into kernel table) + +\fB network [NETWORK] area [OSPF6-AREA-ID] \fR +\fB no network [NETWORK] \fR + +\fB show ip ospf6 interface \fR +\fB show ip ospf6 neighbor \fR +\fB show ip ospf6 database \fR +\fB show ip ospf6 route \fR + +\fB debug ospf6 ism \fR +\fB debug ospf6 packet \fR +\fB debug ospf6 nsm \fR + + + +.SH FILES + +.TP +.BI /usr/local/sbin/ospf6d +The default location of the +.B ospf6d +binary. + +.TP +.BI /usr/local/etc/ospf6d.conf +The default location of the +.B ospf6d +config file. + +.TP +.BI $(PWD)/ospf6d.log +If the +.B ospf6d +process is config'd to output logs to a file, then you will find this +file in the directory where you started \fBospf6d\fR. + + +.SH WARNING +This man page is intended as a quick reference for command line +options, and for config file commands. The definitive document is the +Info file \fBzebra\fR. + + +.SH DIAGNOSTICS +The ospf6d process may log to standard output, to a VTY, to a log +file, or through syslog to the system logs. \fBospf6d\fR supports many +debugging options, see the Info file, or the source for details. + + +.SH "SEE ALSO" +References to other related man pages: + +ripd(8), ripngd(8), ospfd(8), bgpd(8), zebra(8), vtysh(1) + + +.SH BUGS +.B ospf6d +eats bugs for breakfast. If you have food for the maintainers try +.BI + + +.SH AUTHOR[S] +See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors. + diff --git a/doc/ospf6d.texi b/doc/ospf6d.texi new file mode 100644 index 00000000..e3ac3d27 --- /dev/null +++ b/doc/ospf6d.texi @@ -0,0 +1,102 @@ +@node OSPFv3, BGP, OSPFv2, Top +@comment node-name, next, previous, up +@chapter OSPFv3 + +@command{ospf6d} is a daemon support OSPF version 3 for IPv6 network. +OSPF for IPv6 is described in RFC2740. + +@menu +* OSPF6 router:: +* OSPF6 area:: +* OSPF6 interface:: +* Redistribute routes to OSPF6:: +* Showing OSPF6 information:: +@end menu + +@node OSPF6 router, OSPF6 area, OSPFv3, OSPFv3 +@comment node-name, next, previous, up +@section OSPF6 router + +@deffn {Command} {router ospf6} {} +@end deffn + +@deffn {OSPF6 Command} {router-id @var{a.b.c.d}} {} +Set router's Router-ID. +@end deffn + +@deffn {OSPF6 Command} {interface @var{ifname} area @var{area}} {} +Bind interface to specified area, and start sending OSPF packets. @var{area} can +be specified as 0. +@end deffn + +@node OSPF6 area, OSPF6 interface, OSPF6 router, OSPFv3 +@comment node-name, next, previous, up +@section OSPF6 area + +Area support for OSPFv3 is not yet implemented. + +@node OSPF6 interface, Redistribute routes to OSPF6, OSPF6 area, OSPFv3 +@comment node-name, next, previous, up +@section OSPF6 interface + +@deffn {Interface Command} {ipv6 ospf6 cost COST} {} +Sets interface's output cost. Default value is 1. +@end deffn + +@deffn {Interface Command} {ipv6 ospf6 hello-interval HELLOINTERVAL} {} +Sets interface's Hello Interval. Default 40 +@end deffn + +@deffn {Interface Command} {ipv6 ospf6 dead-interval DEADINTERVAL} {} +Sets interface's Router Dead Interval. Default value is 40. +@end deffn + +@deffn {Interface Command} {ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL} {} +Sets interface's Rxmt Interval. Default value is 5. +@end deffn + +@deffn {Interface Command} {ipv6 ospf6 priority PRIORITY} {} +Sets interface's Router Priority. Default value is 1. +@end deffn + +@deffn {Interface Command} {ipv6 ospf6 transmit-delay TRANSMITDELAY} {} +Sets interface's Inf-Trans-Delay. Default value is 1. +@end deffn + +@node Redistribute routes to OSPF6, Showing OSPF6 information, OSPF6 interface, OSPFv3 +@comment node-name, next, previous, up +@section Redistribute routes to OSPF6 + +@deffn {OSPF6 Command} {redistribute static} {} +@deffnx {OSPF6 Command} {redistribute connected} {} +@deffnx {OSPF6 Command} {redistribute ripng} {} +@end deffn + +@node Showing OSPF6 information, , Redistribute routes to OSPF6, OSPFv3 +@comment node-name, next, previous, up +@section Showing OSPF6 information + +@deffn {Command} {show ipv6 ospf6 [INSTANCE_ID]} {} +INSTANCE_ID is an optional OSPF instance ID. To see router ID and OSPF +instance ID, simply type "show ipv6 ospf6 ". +@end deffn + +@deffn {Command} {show ipv6 ospf6 database} {} +This command shows LSA database summary. You can specify the type of LSA. +@end deffn + +@deffn {Command} {show ipv6 ospf6 interface} {} +To see OSPF interface configuration like costs. +@end deffn + +@deffn {Command} {show ipv6 ospf6 neighbor} {} +Shows state and chosen (Backup) DR of neighbor. +@end deffn + +@deffn {Command} {show ipv6 ospf6 request-list A.B.C.D} {} +Shows requestlist of neighbor. +@end deffn + +@deffn {Command} {show ipv6 route ospf6} {} +This command shows internal routing table. +@end deffn diff --git a/doc/ospfd.8 b/doc/ospfd.8 new file mode 100644 index 00000000..0fbfce4c --- /dev/null +++ b/doc/ospfd.8 @@ -0,0 +1,131 @@ +.TH OSPFD 8 "July 2000" "Zebra Beast - OSPFD" "Version 0.88" + +.SH NAME +ospfd \- an OSPF v2 routing engine for use with Zebra + +.SH SYNOPSIS +.B ospfd +[ +.B \-dhlv +] +[ +.B \-f config-file +] +[ +.B \-i pid-file +] +[ +.B \-P port-number +] + +.SH DESCRIPTION +.B ospfd +is a routing component that works with the +.B zebra +routing engine. + + +.SH OPTIONS + +.TP +\fB\-d\fR, \fB\-\-daemon\fR +Runs in daemon mode, forking and exiting from tty. + +.TP +\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR +Specifies the config file to use for startup. If not specified this +option will likely default to \fB\fI/usr/local/etc/ospfd.conf\fR. + +.TP +\fB\-h\fR, \fB\-\-help\fR +A brief message. + +.TP +\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR +When ospfd starts its process idenifier is written to +\fB\fIpid-file\fR. The init system uses the recorded PID to stop or +restart ospfd. The likely default is \fB\fI/var/run/ospfd.pid\fR. + +.TP +\fB\-l\fR, \fB\-\-log_mode\fR +Turn verbose logging on. + +.TP +\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR +Specify the port that the ospfd VTY will listen on. This defaults to +2604, as specified in \fB\fI/etc/services\fR. + +.TP +\fB\-v\fR, \fB\-\-version\fR +Print the version and exit. + + +.SH COMMANDS + +\fB router ospf \fR +\fB router zebra \fR -- (Move routes into kernel table) + +\fB network [NETWORK] area [OSPF-AREA-ID] \fR +\fB no network [NETWORK] \fR + +\fB show ip ospf interface \fR +\fB show ip ospf neighbor \fR +\fB show ip ospf database \fR +\fB show ip ospf route \fR + + +\fB debug ospf ism \fR +\fB debug ospf packet \fR +\fB debug ospf nsm \fR + + + +.SH FILES + +.TP +.BI /usr/local/sbin/ospfd +The default location of the +.B ospfd +binary. + +.TP +.BI /usr/local/etc/ospfd.conf +The default location of the +.B ospfd +config file. + +.TP +.BI $(PWD)/ospfd.log +If the +.B ospfd +process is config'd to output logs to a file, then you will find this +file in the directory where you started \fBospfd\fR. + + +.SH WARNING +This man page is intended as a quick reference for command line +options, and for config file commands. The definitive document is the +Info file \fBzebra\fR. + + +.SH DIAGNOSTICS +The ospfd process may log to standard output, to a VTY, to a log +file, or through syslog to the system logs. \fBospfd\fR supports many +debugging options, see the Info file, or the source for details. + + +.SH "SEE ALSO" +References to other related man pages: + +ripd(8), ripngd(8), ospf6d(8), bgpd(8), zebra(8), vtysh(1) + + +.SH BUGS +.B ospfd +eats bugs for breakfast. If you have food for the maintainers try +.BI + + +.SH AUTHOR[S] +See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors. + diff --git a/doc/ospfd.texi b/doc/ospfd.texi new file mode 100644 index 00000000..5952c051 --- /dev/null +++ b/doc/ospfd.texi @@ -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 index 00000000..68e6e391 --- /dev/null +++ b/doc/overview.texi @@ -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 index 00000000..7cae9c9d --- /dev/null +++ b/doc/protocol.texi @@ -0,0 +1,52 @@ +@node Zebra Protocol, Packet Binary Dump Format, SNMP Support, Top +@comment node-name, next, previous, up +@appendix Zebra Protocol + +Zebra Protocol is a protocol which is used between protocol daemon and +zebra. Each protocol daemon sends selected routes to zebra daemon. Then +zebra manages which route is installed into the forwarding table. + +Zebra Protocol is a TCP-based protocol. Below is common header of Zebra +Protocol. + +@example +@group +0 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Length (2) | Command (1) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example + +Length is total packet length including this header length. So minimum +length is three. Command is Zebra Protocol command. + +@example +ZEBRA_INTERFACE_ADD 1 +ZEBRA_INTERFACE_DELETE 2 +ZEBRA_INTERFACE_ADDRESS_ADD 3 +ZEBRA_INTERFACE_ADDRESS_DELETE 4 +ZEBRA_INTERFACE_UP 5 +ZEBRA_INTERFACE_DOWN 6 +ZEBRA_IPV4_ROUTE_ADD 7 +ZEBRA_IPV4_ROUTE_DELETE 8 +ZEBRA_IPV6_ROUTE_ADD 9 +ZEBRA_IPV6_ROUTE_DELETE 10 +ZEBRA_REDISTRIBUTE_ADD 11 +ZEBRA_REDISTRIBUTE_DELETE 12 +ZEBRA_REDISTRIBUTE_DEFAULT_ADD 13 +ZEBRA_REDISTRIBUTE_DEFAULT_DELETE 14 +ZEBRA_IPV4_NEXTHOP_LOOKUP 15 +ZEBRA_IPV6_NEXTHOP_LOOKUP 16 +@end example + +@example +@group +0 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Type | Flags | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example diff --git a/doc/ripd.8 b/doc/ripd.8 new file mode 100644 index 00000000..e15989ff --- /dev/null +++ b/doc/ripd.8 @@ -0,0 +1,212 @@ +.TH RIPD 8 "July 2000" "Zebra" "Version 0.88" + +.SH NAME +ripd \- a RIP routing engine for use with Zebra + +.SH SYNOPSIS +.B ripd +[ +.B \-dhrv +] +[ +.B \-f config-file +] +[ +.B \-i pid-file +] +[ +.B \-P port-number +] + +.SH DESCRIPTION +.B ripd +is a routing component that supports the +.B zebra +route engine. +.B ripd +supports RIPv1, RIPv2, and so forth. + + +.SH OPTIONS + +.TP +\fB\-d\fR, \fB\-\-daemon\fR +Runs in daemon mode, forking and exiting from tty. + +.TP +\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR +Specifies the config file to use for startup. If not specified this option will likely default to \fB\fI/usr/local/etc/ripd.conf\fR. + +.TP +\fB\-h\fR, \fB\-\-help\fR +A brief message. + +.TP +\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR +When ripd starts its process idenifier is written to +\fB\fIpid-file\fR. The init system uses the recorded PID to stop or +restart ripd. The likely default is \fB\fI/var/run/ripd.pid\fR. + +.TP +\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR +Specify the port that the ripd VTY will listen on. This defaults to +2602, as specified in \fB\fI/etc/services\fR. + +.TP +\fB\-r\fR, \fB\-\-retain\fR +When the program terminates, retain routes added by \fBripd\fR. + +.TP +\fB\-v\fR, \fB\-\-version\fR +Print the version and exit. + + +.SH COMMANDS + +\fB router rip \fR +\fB no router rip \fR + +\fB rip version [1|2] \fR +\fB no rip version [1|2] \fR + +\fB network [A.B.C.D/M] \fR +\fB no network [A.B.C.D/M] \fR + +\fB network [IFNAME] \fR +\fB no network [IFNAME] \fR + +\fB neighbor [A.B.C.D] \fR +\fB no neighbor [A.B.C.D] \fR + +\fB redistribute kernel \fR +\fB redistribute kernel metric [METRIC]\fR +\fB redistribute kernel route-map [ROUTE-MAP]\fR +\fB no redistribute kernel \fR + +\fB redistribute static \fR +\fB redistribute static metric [METRIC]\fR +\fB redistribute static route-map [ROUTE-MAP]\fR +\fB no redistribute static \fR + +\fB redistribute connected \fR +\fB redistribute connected metric [METRIC]\fR +\fB redistribute connected route-map [ROUTE-MAP]\fR +\fB no redistribute connected \fR + +\fB redistribute ospf \fR +\fB redistribute ospf metric [METRIC]\fR +\fB redistribute ospf route-map [ROUTE-MAP]\fR +\fB no redistribute ospf \fR + +\fB redistribute bgp \fR +\fB redistribute bgp metric [METRIC]\fR +\fB redistribute bgp route-map [ROUTE-MAP]\fR +\fB no redistribute bgp \fR + +\fB route [A.B.C.D/M] \fR +\fB no route [A.B.C.D/M] \fR + +\fB default-information originate \fR +\fB no default-information originate \fR + +\fB default-metric [METRIC] \fR +\fB no default-metric [METRIC] \fR + +\fB passive-interface [IFNAME] \fR +\fB no passive-interface [IFNAME] \fR + +\fB offset-list [ACCESS-LIST] [in|out]\fR +\fB offset-list [ACCESS-LIST] [in|out] [IFNAME]\fR +\fB no offset-list [ACCESS-LIST] [in|out]\fR + +\fB timers basic [UPDATE-INTERVAL] [INVALID] [TIMEOUT] [GARBAGE-COLLECT] \fR +\fB no timers basic \fR + +\fB distribute-list [ACCESS-LIST] [in|out] [IFNAME] \fR +\fB no distribute-list [ACCESS-LIST] [in|out] [IFNAME] \fR + +\fB distribute-list prefix [PREFIX-LIST] [in|out] [IFNAME] \fR +\fB no distribute-list prefix [PREFIX-LIST] [in|out] [IFNAME] \fR + +\fB distance [DISTANCE] \fR +\fB no distance [DISTANCE] \fR + +\fB distance [DISTANCE] [A.B.C.D/M] \fR +\fB no distance [DISTANCE] [A.B.C.D/M] \fR + +\fB distance [DISTANCE] [A.B.C.D/M] [ACCESS-LIST]\fR +\fB no distance [DISTANCE] [A.B.C.D/M] [ACCESS-LIST]\fR + +\fB ip rip send version [VERSION] \fR +\fB no ip rip send version [VERSION] \fR +\fB ip rip receive version [VERSION] \fR +\fB no ip rip receive version [VERSION] \fR + +\fB ip rip authentication mode [md5|text]\fR +\fB no ip rip authentication mode [md5|text]\fR + +\fB ip rip authentication key-chain [KEY-CHAIN]\fR +\fB no ip rip authentication key-chain [KEY-CHAIN]\fR + +\fB ip rip authentication string [STRING]\fR +\fB no ip rip authentication string [STRING]\fR + +\fB ip spli-horizon\fR +\fB no ip spli-horizon\fR + +\fB show ip rip \fR +\fB show ip protocols \fR +\fB show debugging rip \fR + +\fB debug rip \fR +\fB debug rip events \fR +\fB debug rip packet \fR +\fB debug rip zebra \fR + +.SH FILES + +.TP +.BI /usr/local/sbin/ripd +The default location of the +.B ripd +binary. + +.TP +.BI /usr/local/etc/ripd.conf +The default location of the +.B ripd +config file. + +.TP +.BI $(PWD)/ripd.log +If the +.B ripd +process is config'd to output logs to a file, then you will find this +file in the directory where you started \fBripd\fR. + + +.SH WARNING +This man page is intended as a quick reference for command line options, and for config file commands. The definitive document is the Info file \fBzebra\fR. + + +.SH DIAGNOSTICS +The ripd process may log to standard output, to a VTY, to a log file, or through syslog to the system logs. +.B ripd +supports many debugging options, see the Info file, or the source for details. + + +.SH "SEE ALSO" +References to other related man pages: + +ripngd(8), ospfd(8), ospf6d(8), bgpd(8), zebra(8) + + + +.SH BUGS +.B ripd +eats bugs for breakfast. If you have food for the maintainers try +.BI + + +.SH AUTHOR[S] +See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors. diff --git a/doc/ripd.texi b/doc/ripd.texi new file mode 100644 index 00000000..d598ca66 --- /dev/null +++ b/doc/ripd.texi @@ -0,0 +1,584 @@ +@c -*-texinfo-*- +@c This is part of the GNU Zebra Manual. +@c Copyright (C) 1999, 2000 Kunihiro Ishiguro +@c See file zebra.texi for copying conditions. +@node RIP +@comment node-name, next, previous, up +@chapter RIP + +RIP -- Routing Information Protocol is widely deployed interior gateway +protocol. RIP was developed in the 1970s at Xerox Labs as part of the +XNS routing protocol. RIP is a @dfn{distance-vector} protocol and is +based on the @dfn{Bellman-Ford} algorithms. As a distance-vector +protocol, RIP router send updates to its neighbors periodically, thus +allowing the convergence to a known topology. In each update, the +distance to any given network will be broadcasted to its neighboring +router. + +@command{ripd} supports RIP version 2 as described in RFC2453 and RIP +version 1 as described in RFC1058. + +@menu +* Starting and Stopping ripd:: +* RIP Configuration:: +* How to Announce RIP route:: +* Filtering RIP Routes:: +* RIP Metric Manipulation:: +* RIP distance:: +* RIP route-map:: +* RIP Authentication:: +* RIP Timers:: +* Show RIP Information:: +* RIP Debug Commands:: +@end menu + +@node Starting and Stopping ripd, RIP Configuration, RIP, RIP +@comment node-name, next, previous, up +@section Starting and Stopping ripd + +The default configuration file name of @command{ripd}'s is +@file{ripd.conf}. When invocation @command{ripd} searches directory +@value{INSTALL_PREFIX_ETC}. If @file{ripd.conf} is not there next +search current directory. + +RIP uses UDP port 521 to send and receive RIP packets. So the user must have +the capability to bind the port, generally this means that the user must +have superuser privileges. RIP protocol requires interface information +maintained by @command{zebra} daemon. So running @command{zebra} +is mandatory to run @command{ripd}. Thus minimum sequence for running +RIP is like below: + +@example +@group +# zebra -d +# ripd -d +@end group +@end example + +Please note that @command{zebra} must be invoked before @command{ripd}. + +To stop @command{ripd}. Please use @command{kill `cat +/var/run/ripd.pid`}. Certain signals have special meaningss to @command{ripd}. + +@table @samp +@item SIGHUP +Reload configuration file @file{ripd.conf}. All configurations are +reseted. All routes learned so far are cleared and removed from routing +table. +@item SIGUSR1 +Rotate @command{ripd} logfile. +@item SIGINT +@itemx SIGTERM +@command{ripd} sweeps all installed RIP routes then terminates properly. +@end table + +@command{ripd} invocation options. Common options that can be specified +(@pxref{Common Invocation Options}). + +@table @samp +@item -r +@itemx --retain +When the program terminates, retain routes added by @command{ripd}. +@end table + +@menu +* RIP netmask:: +@end menu + +@node RIP netmask, , Starting and Stopping ripd, Starting and Stopping ripd +@comment node-name, next, previous, up +@subsection RIP netmask + +The netmask features of @command{ripd} support both version 1 and version 2 of +RIP. Version 1 of RIP originally contained no netmask information. In +RIP version 1, network classes were originally used to determine the +size of the netmask. Class A networks use 8 bits of mask, Class B +networks use 16 bits of masks, while Class C networks use 24 bits of +mask. Today, the most widely used method of a network mask is assigned +to the packet on the basis of the interface that received the packet. +Version 2 of RIP supports a variable length subnet mask (VLSM). By +extending the subnet mask, the mask can be divided and reused. Each +subnet can be used for different purposes such as large to middle size +LANs and WAN links. Zebra @command{ripd} does not support the non-sequential +netmasks that are included in RIP Version 2. + +In a case of similar information with the same prefix and metric, the +old information will be suppressed. Ripd does not currently support +equal cost multipath routing. + + +@node RIP Configuration, How to Announce RIP route, Starting and Stopping ripd, RIP +@comment node-name, next, previous, up +@section RIP Configuration + +@deffn Command {router rip} {} +The @code{router rip} command is necessary to enable RIP. To disable +RIP, use the @code{no router rip} command. RIP must be enabled before +carrying out any of the RIP commands. +@end deffn + +@deffn Command {no rouer rip} {} +Disable RIP. +@end deffn + +RIP can be configured to process either Version 1 or Version 2 packets, +the default mode is Version 2. If no version is specified, then the RIP +daemon will default to Version 2. If RIP is set to Version +1, the setting "Version 1" will be displayed, but the setting "Version +2" will not be displayed whether or not Version 2 is set explicitly as +the version of RIP being used. + +@deffn {RIP Command} {network @var{network}} {} +@deffnx {RIP Command} {no network @var{network}} {} +Set the RIP enable interface by @var{network}. The interfaces which +have addresses matching with @var{network} are enabled. + +This group of commands either enables or disables RIP interfaces between +certain numbers of a specified network address. For example, if the +network for 10.0.0.0/24 is RIP enabled, this would result in all the +addresses from 10.0.0.0 to 10.0.0.255 being enabled for RIP. The @code{no +network} command will disable RIP for the specified network. +@end deffn + +@deffn {RIP Command} {network @var{ifname}} {} +@deffnx {RIP Command} {no network @var{ifname}} {} +Set a RIP enabled interface by @var{ifname}. Both the sending and +receiving of RIP packets will be enabled on the port specified in the +@code{network ifname} command. The @code{no network ifname} command will disable +RIP on the specified interface. +@end deffn + +@deffn {RIP Command} {neighbor @var{a.b.c.d}} {} +@deffnx {RIP Command} {no neighbor @var{a.b.c.d}} {} +Specify RIP neighbor. When a neighbor doesn't understand multicast, +this command is used to specify neighbors. In some cases, not all +routers will be able to understand multicasting, where packets are sent +to a network or a group of addresses. In a situation where a neighbor +cannot process multicast packets, it is necessary to establish a direct +link between routers. The neighbor command allows the network +administrator to specify a router as a RIP neighbor. The @code{no +neighbor a.b.c.d} command will disable the RIP neighbor. +@end deffn + +Below is very simple RIP configuration. Interface @code{eth0} and +interface which address match to @code{10.0.0.0/8} are RIP enabled. + +@example +@group +! +router rip + network 10.0.0.0/8 + network eth0 +! +@end group +@end example + +Passive interface + +@deffn {RIP command} {passive-interface @var{IFNAME}} {} +@deffnx {RIP command} {no passive-interface @var{IFNAME}} {} +This command sets the specified interface to passive mode. On passive mode +interface, all receiving packets are processed as normal and ripd does +not send either multicast or unicast RIP packets except to RIP neighbors +specified with @code{neighbor} command. +@end deffn + +RIP version handling + +@deffn {RIP Command} {version @var{version}} {} +Set RIP process's version. @var{version} can be ``1'' or ``2''. +@end deffn + +@deffn {Interface command} {ip rip send version @var{version}} {} +@var{version} can be `1', `2', `1 2'. This configuration command +overrides the router's rip version setting. The command will enable the +selected interface to send packets with RIP Version 1, RIP Version 2, or +both. In the case of '1 2', packets will be both broadcast and +multicast. +@end deffn + +@deffn {Interface command} {ip rip receive version @var{version}} {} +Version setting for incoming RIP packets. This command will enable the +selected interface to receive packets in RIP Version 1, RIP Version 2, +or both. +@end deffn + +RIP split-horizon + +@deffn {Interface command} {ip split-horizon} {} +@deffnx {Interface command} {no ip split-horizon} {} +Control split-horizon on the interface. Default is @code{ip +split-horizon}. If you don't perform split-horizon on the interface, +please specify @code{no ip split-horizon}. +@end deffn + +@node How to Announce RIP route, Filtering RIP Routes, RIP Configuration, RIP +@comment node-name, next, previous, up +@section How to Announce RIP route + +@deffn {RIP command} {redistribute kernel} {} +@deffnx {RIP command} {redistribute kernel metric <0-16>} {} +@deffnx {RIP command} {redistribute kernel route-map @var{route-map}} {} +@deffnx {RIP command} {no redistribute kernel} {} +@code{redistribute kernel} redistributes routing information from +kernel route entries into the RIP tables. @code{no redistribute kernel} +disables the routes. +@end deffn + +@deffn {RIP command} {redistribute static} {} +@deffnx {RIP command} {redistribute static metric <0-16>} {} +@deffnx {RIP command} {redistribute static route-map @var{route-map}} {} +@deffnx {RIP command} {no redistribute static} {} +@code{redistribute static} redistributes routing information from +static route entries into the RIP tables. @code{no redistribute static} +disables the routes. +@end deffn + +@deffn {RIP command} {redistribute connected} {} +@deffnx {RIP command} {redistribute connected metric <0-16>} {} +@deffnx {RIP command} {redistribute connected route-map @var{route-map}} {} +@deffnx {RIP command} {no redistribute connected} {} +Redistribute connected routes into the RIP tables. @code{no +redistribute connected} disables the connected routes in the RIP tables. +This command redistribute connected of the interface which RIP disabled. +The connected route on RIP enabled interface is announced by default. +@end deffn + +@deffn {RIP command} {redistribute ospf} {} +@deffnx {RIP command} {redistribute ospf metric <0-16>} {} +@deffnx {RIP command} {redistribute ospf route-map @var{route-map}} {} +@deffnx {RIP command} {no redistribute ospf} {} +@code{redistribute ospf} redistributes routing information from +ospf route entries into the RIP tables. @code{no redistribute ospf} +disables the routes. +@end deffn + +@deffn {RIP command} {redistribute bgp} {} +@deffnx {RIP command} {redistribute bgp metric <0-16>} {} +@deffnx {RIP command} {redistribute bgp route-map @var{route-map}} {} +@deffnx {RIP command} {no redistribute bgp} {} +@code{redistribute bgp} redistributes routing information from +bgp route entries into the RIP tables. @code{no redistribute bgp} +disables the routes. +@end deffn + +If you want to specify RIP only static routes: + +@deffn {RIP command} {default-information originate} {} +@end deffn + +@deffn {RIP command} {route @var{a.b.c.d/m}} {} +@deffnx {RIP command} {no route @var{a.b.c.d/m}} {} +This command is specific to Zebra. The @code{route} command makes a static +route only inside RIP. This command should be used only by advanced +users who are particularly knowledgeable about the RIP protocol. In +most cases, we recommend creating a static route in Zebra and +redistributing it in RIP using @code{redistribute static}. +@end deffn + + +@node Filtering RIP Routes, RIP Metric Manipulation, How to Announce RIP route, RIP +@comment node-name, next, previous, up +@section Filtering RIP Routes + +RIP routes can be filtered by a distribute-list. + +@deffn Command {distribute-list @var{access_list} @var{direct} @var{ifname}} {} +You can apply access lists to the interface with a @code{distribute-list} +command. @var{access_list} is the access list name. @var{direct} is +@samp{in} or @samp{out}. If @var{direct} is @samp{in} the access list +is applied to input packets. + +The @code{distribute-list} command can be used to filter the RIP path. +@code{distribute-list} can apply access-lists to a chosen interface. +First, one should specify the access-list. Next, the name of the +access-list is used in the distribute-list command. For example, in the +following configuration @samp{eth0} will permit only the paths that +match the route 10.0.0.0/8 + +@example +@group +! +router rip + distribute-list private in eth0 +! +access-list private permit 10 10.0.0.0/8 +access-list private deny any +! +@end group +@end example +@end deffn + +@code{distribute-list} can be applied to both incoming and outgoing data. + +@deffn Command {distribute-list prefix @var{prefix_list} (in|out) @var{ifname}} {} +You can apply prefix lists to the interface with a +@code{distribute-list} command. @var{prefix_list} is the prefix list +name. Next is the direction of @samp{in} or @samp{out}. If +@var{direct} is @samp{in} the access list is applied to input packets. +@end deffn + +@node RIP Metric Manipulation, RIP distance, Filtering RIP Routes, RIP +@comment node-name, next, previous, up +@section RIP Metric Manipulation + +RIP metric is a value for distance for the network. Usually +@command{ripd} increment the metric when the network information is +received. Redistributed routes' metric is set to 1. + +@deffn {RIP command} {default-metric <1-16>} {} +@deffnx {RIP command} {no default-metric <1-16>} {} +This command modifies the default metric value for redistributed routes. The +default value is 1. This command does not affect connected route +even if it is redistributed by @command{redistribute connected}. To modify +connected route's metric value, please use @command{redistribute +connected metric} or @command{route-map}. @command{offset-list} also +affects connected routes. +@end deffn + +@deffn {RIP command} {offset-list @var{access-list} (in|out)} {} +@deffnx {RIP command} {offset-list @var{access-list} (in|out) @var{ifname}} {} +@end deffn + +@node RIP distance, RIP route-map, RIP Metric Manipulation, RIP +@comment node-name, next, previous, up +@section RIP distance + +Distance value is used in zebra daemon. Default RIP distance is 120. + +@deffn {RIP command} {distance <1-255>} {} +@deffnx {RIP command} {no distance <1-255>} {} +Set default RIP distance to specified value. +@end deffn + +@deffn {RIP command} {distance <1-255> @var{A.B.C.D/M}} {} +@deffnx {RIP command} {no distance <1-255> @var{A.B.C.D/M}} {} +Set default RIP distance to specified value when the route's source IP +address matches the specified prefix. +@end deffn + +@deffn {RIP command} {distance <1-255> @var{A.B.C.D/M} @var{access-list}} {} +@deffnx {RIP command} {no distance <1-255> @var{A.B.C.D/M} @var{access-list}} {} +Set default RIP distance to specified value when the route's source IP +address matches the specified prefix and the specified access-list. +@end deffn + +@node RIP route-map, RIP Authentication, RIP distance, RIP +@comment node-name, next, previous, up +@section RIP route-map + +Usage of @command{ripd}'s route-map support. + +Optional argument route-map MAP_NAME can be added to each @code{redistribute} +statement. + +@example +redistribute static [route-map MAP_NAME] +redistribute connected [route-map MAP_NAME] +..... +@end example + +Cisco applies route-map _before_ routes will exported to rip route +table. In current Zebra's test implementation, @command{ripd} applies route-map +after routes are listed in the route table and before routes will be announced +to an interface (something like output filter). I think it is not so clear, +but it is draft and it may be changed at future. + +Route-map statement (@pxref{Route Map}) is needed to use route-map +functionality. + +@deffn {Route Map} {match interface @var{word}} {} +This command match to incoming interface. Notation of this match is +different from Cisco. Cisco uses a list of interfaces - NAME1 NAME2 +... NAMEN. Ripd allows only one name (maybe will change in the +future). Next - Cisco means interface which includes next-hop of +routes (it is somewhat similar to "ip next-hop" statement). Ripd +means interface where this route will be sent. This difference is +because "next-hop" of same routes which sends to different interfaces +must be different. Maybe it'd be better to made new matches - say +"match interface-out NAME" or something like that. +@end deffn + +@deffn {Route Map} {match ip address @var{word}} {} +@deffnx {Route Map} {match ip address prefix-list @var{word}} {} +Match if route destination is permitted by access-list. +@end deffn + +@deffn {Route Map} {match ip next-hop A.B.C.D} {} +Cisco uses here , @command{ripd} IPv4 address. Match if +route has this next-hop (meaning next-hop listed in the rip route +table - "show ip rip") +@end deffn + +@deffn {Route Map} {match metric <0-4294967295>} {} +This command match to the metric value of RIP updates. For other +protocol compatibility metric range is shown as <0-4294967295>. But +for RIP protocol only the value range <0-16> make sense. +@end deffn + +@deffn {Route Map} {set ip next-hop A.B.C.D} {} +This command set next hop value in RIPv2 protocol. This command does +not affect RIPv1 because there is no next hop field in the packet. +@end deffn + +@deffn {Route Map} {set metric <0-4294967295>} {} +Set a metric for matched route when sending announcement. The metric +value range is very large for compatibility with other protocols. For +RIP, valid metric values are from 1 to 16. +@end deffn + +@node RIP Authentication, RIP Timers, RIP route-map, RIP +@comment node-name, next, previous, up +@section RIP Authentication + +@deffn {Interface command} {ip rip authentication mode md5} {} +@deffnx {Interface command} {no ip rip authentication mode md5} {} +Set the interface with RIPv2 MD5 authentication. +@end deffn + +@deffn {Interface command} {ip rip authentication mode text} {} +@deffnx {Interface command} {no ip rip authentication mode text} {} +Set the interface with RIPv2 simple password authentication. +@end deffn + +@deffn {Interface command} {ip rip authentication string @var{string}} {} +@deffnx {Interface command} {no ip rip authentication string @var{string}} {} +RIP version 2 has simple text authentication. This command sets +authentication string. The string must be shorter than 16 characters. +@end deffn + +@deffn {Interface command} {ip rip authentication key-chain @var{key-chain}} {} +@deffnx {Interface command} {no ip rip authentication key-chain @var{key-chain}} {} +Specifiy Keyed MD5 chain. +@end deffn + +@example +! +key chain test + key 1 + key-string test +! +interface eth1 + ip rip authentication mode md5 + ip rip authentication key-chain test +! +@end example + +@node RIP Timers, Show RIP Information, RIP Authentication, RIP +@comment node-name, next, previous, up +@section RIP Timers + +@deffn {RIP command} {timers basic @var{update} @var{timeout} @var{garbage}} {} + +RIP protocol has several timers. User can configure those timers' values +by @code{timers basic} command. + +The default settings for the timers are as follows: + +@itemize @bullet +@item +The update timer is 30 seconds. Every update timer seconds, the RIP +process is awakened to send an unsolicited Response message containing +the complete routing table to all neighboring RIP routers. + +@item +The timeout timer is 180 seconds. Upon expiration of the timeout, the +route is no longer valid; however, it is retained in the routing table +for a short time so that neighbors can be notified that the route has +been dropped. + +@item +The garbage collect timer is 120 seconds. Upon expiration of the +garbage-collection timer, the route is finally removed from the routing +table. + +@end itemize + +The @code{timers basic} command allows the the default values of the timers +listed above to be changed. +@end deffn + +@deffn {RIP command} {no timers basic} {} +The @code{no timers basic} command will reset the timers to the default +settings listed above. +@end deffn + +@node Show RIP Information, RIP Debug Commands, RIP Timers, RIP +@comment node-name, next, previous, up +@section Show RIP Information + +To display RIP routes. + +@deffn Command {show ip rip} {} +Show RIP routes. +@end deffn + +The command displays all RIP routes. For routes that are received +through RIP, this command will display the time the packet was sent and +the tag information. This command will also display this information +for routes redistributed into RIP. + +@c Exmaple here. + +@deffn Command {show ip protocols} {} +The command displays current RIP status. It includes RIP timer, +filtering, version, RIP enabled interface and RIP peer inforation. +@end deffn + +@example +@group +ripd> @b{show ip protocols} +Routing Protocol is "rip" + Sending updates every 30 seconds with +/-50%, next due in 35 seconds + Timeout after 180 seconds, garbage collect after 120 seconds + Outgoing update filter list for all interface is not set + Incoming update filter list for all interface is not set + Default redistribution metric is 1 + Redistributing: kernel connected + Default version control: send version 2, receive version 2 + Interface Send Recv + Routing for Networks: + eth0 + eth1 + 1.1.1.1 + 203.181.89.241 + Routing Information Sources: + Gateway BadPackets BadRoutes Distance Last Update +@end group +@end example + +@node RIP Debug Commands, , Show RIP Information, RIP +@comment node-name, next, previous, up +@section RIP Debug Commands + +Debug for RIP protocol. + +@deffn Command {debug rip events} {} +Debug rip events. +@end deffn + +@code{debug rip} will show RIP events. Sending and receiving +packets, timers, and changes in interfaces are events shown with @command{ripd}. + +@deffn Command {debug rip packet} {} +Debug rip packet. +@end deffn + +@code{debug rip packet} will display detailed information about the RIP +packets. The origin and port number of the packet as well as a packet +dump is shown. + +@deffn Command {debug rip zebra} {} +Debug rip between zebra communication. +@end deffn + +This command will show the communication between @command{ripd} and @command{zebra}. The +main information will include addition and deletion of paths to the +kernel and the sending and receiving of interface information. + +@deffn Command {show debugging rip} {} +Display @command{ripd}'s debugging option. +@end deffn + +@code{show debugging rip} will show all information currently set for ripd +debug. diff --git a/doc/ripngd.8 b/doc/ripngd.8 new file mode 100644 index 00000000..cff8abe6 --- /dev/null +++ b/doc/ripngd.8 @@ -0,0 +1,143 @@ +.TH RIPNGD 8 "July 2000" "Zebra Beast - RIPNGD" "Version 0.88" + +.SH NAME +ripngd \- a RIP routing engine for use with Zebra and IPv6 + +.SH SYNOPSIS +.B ripngd +[ +.B \-dhlrv +] +[ +.B \-f config-file +] +[ +.B \-i pid-file +] +[ +.B \-P port-number +] + +.SH DESCRIPTION +.B ripngd +is a routing component that works with the +.B zebra +routing engine. + + + +.SH OPTIONS + +.TP +\fB\-d\fR, \fB\-\-daemon\fR +Runs in daemon mode, forking and exiting from tty. + +.TP +\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR +Specifies the config file to use for startup. If not specified this +option will likely default to \fB\fI/usr/local/etc/ripngd.conf\fR. + +.TP +\fB\-h\fR, \fB\-\-help\fR +A brief message. + +.TP +\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR +When ripngd starts its process idenifier is written to +\fB\fIpid-file\fR. The init system uses the recorded PID to stop or +restart ripngd. The likely default is \fB\fI/var/run/ripngd.pid\fR. + +.TP +\fB\-l\fR, \fB\-\-log_mode\fR +Turn verbose logging on. + +.TP +\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR +Specify the port that the ripngd VTY will listen on. This defaults to +2603, as specified in \fB\fI/etc/services\fR. + +.TP +\fB\-r\fR, \fB\-\-retain\fR +When the program terminates, retain routes added by \fBripd\fR. + +.TP +\fB\-v\fR, \fB\-\-version\fR +Print the version and exit. + + +.SH COMMANDS + +\fB router ripng \fR +\fB router zebra \fR -- (Move routes into kernel table) + +\fB network [NETWORK] \fR +\fB no network [NETWORK] \fR + +\fB network [IFNAME] \fR +\fB no network [IFNAME] \fR + +\fB route [NETWORK] \fR +\fB no route [NETWORK] \fR + +\fB flush_timer [FLUSH] \fR + +\fB distribute-list [ACCESS-LIST] [in|out] [IFNAME] \fR + +\fB show ip ripng \fR +\fB show debugging ripng \fR + +\fB debug ripng \fR +\fB debug ripng events \fR +\fB debug ripng packet \fR +\fB debug ripng zebra \fR + + + +.SH FILES + +.TP +.BI /usr/local/sbin/ripngd +The default location of the +.B ripngd +binary. + +.TP +.BI /usr/local/etc/ripngd.conf +The default location of the +.B ripngd +config file. + +.TP +.BI $(PWD)/ripngd.log +If the +.B ripngd +process is config'd to output logs to a file, then you will find this +file in the directory where you started \fBripngd\fR. + + +.SH WARNING +This man page is intended as a quick reference for command line +options, and for config file commands. The definitive document is the +Info file \fBzebra\fR. + + +.SH DIAGNOSTICS +The ripngd process may log to standard output, to a VTY, to a log +file, or through syslog to the system logs. \fBripngd\fR supports many +debugging options, see the Info file, or the source for details. + + +.SH "SEE ALSO" +References to other related man pages: + +ripd(8), ospfd(8), ospf6d(8), bgpd(8), zebra(8), vtysh(1) + +.SH BUGS +.B ripngd +eats bugs for breakfast. If you have food for the maintainers try +.BI + + +.SH AUTHOR[S] +See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors. + diff --git a/doc/ripngd.texi b/doc/ripngd.texi new file mode 100644 index 00000000..b49f0bf3 --- /dev/null +++ b/doc/ripngd.texi @@ -0,0 +1,85 @@ +@node RIPng, OSPFv2, RIP, Top +@comment node-name, next, previous, up +@chapter RIPng + +@command{ripngd} supports the RIPng protocol as described in RFC2080. It's an +IPv6 reincarnation of the RIP protocol. + +@menu +* Invoking ripngd:: +* ripngd Configuration:: +* ripngd Terminal Mode Commands:: +* ripngd Filtering Commands:: +@end menu + +@node Invoking ripngd, ripngd Configuration, RIPng, RIPng +@comment node-name, next, previous, up +@section Invoking ripngd + +There are no @code{ripngd} specific invocation options. Common options +can be specified (@pxref{Common Invocation Options}). + +@node ripngd Configuration, ripngd Terminal Mode Commands, Invoking ripngd, RIPng +@comment node-name, next, previous, up +@section ripngd Configuration + +Currently ripngd supports the following commands: + +@deffn Command {router ripng} {} +Enable RIPng. +@end deffn + +@deffn {RIPng Command} {flush_timer @var{time}} {} +Set flush timer. +@end deffn + +@deffn {RIPng Command} {network @var{network}} {} +Set RIPng enabled interface by @var{network} +@end deffn + +@deffn {RIPng Command} {network @var{ifname}} {} +Set RIPng enabled interface by @var{ifname} +@end deffn + +@deffn {RIPng Command} {route @var{network}} {} +Set RIPng static routing announcement of @var{network}. +@end deffn + +@deffn Command {router zebra} {} +This command is the default and does not appear in the configuration. +With this statement, RIPng routes go to the @command{zebra} daemon. +@end deffn + +@node ripngd Terminal Mode Commands, ripngd Filtering Commands, ripngd Configuration, RIPng +@comment node-name, next, previous, up +@section ripngd Terminal Mode Commands + +@deffn Command {show ip ripng} {} +@end deffn + +@deffn Command {show debugging ripng} {} +@end deffn + +@deffn Command {debug ripng events} {} +@end deffn + +@deffn Command {debug ripng packet} {} +@end deffn + +@deffn Command {debug ripng zebra} {} +@end deffn + +@node ripngd Filtering Commands, , ripngd Terminal Mode Commands, RIPng +@comment node-name, next, previous, up +@section ripngd Filtering Commands + +@deffn Command {distribute-list @var{access_list} (in|out) @var{ifname}} {} +You can apply an access-list to the interface using the +@code{distribute-list} command. @var{access_list} is an access-list +name. @var{direct} is @samp{in} or @samp{out}. If @var{direct} is +@samp{in}, the access-list is applied only to incoming packets. + +@example +distribute-list local-only out sit1 +@end example +@end deffn diff --git a/doc/routemap.texi b/doc/routemap.texi new file mode 100644 index 00000000..478f4626 --- /dev/null +++ b/doc/routemap.texi @@ -0,0 +1,91 @@ +@node Route Map, IPv6 Support, Filtering, Top +@comment node-name, next, previous, up +@chapter Route Map + +Route map is a very useful function in zebra. There is a match and set +statement permitted in a route map. + +@example +@group +route-map test permit 10 + match ip address 10 + set local-preference 200 +@end group +@end example + +This means that if a route matches ip access-list number 10 it's +local-preference value is set to 200. + +@menu +* Route Map Command:: +* Route Map Match Command:: +* Route Map Set Command:: +@end menu + +@node Route Map Command, Route Map Match Command, Route Map, Route Map +@comment node-name, next, previous, up +@subsection Route Map Command + +@deffn {Command} {route-map @var{route-map-name} permit @var{priority}} {} +@end deffn + +@node Route Map Match Command, Route Map Set Command, Route Map Command, Route Map +@comment node-name, next, previous, up +@subsection Route Map Match Command + +@deffn {Route-map Command} {match ip address @var{access_list}} {} +Matches the specified @var{access_list} +@end deffn + +@deffn {Route-map Command} {match ip next-hop @var{ipv4_addr}} {} +Matches the specified @var{ipv4_addr}. +@end deffn + +@deffn {Route-map Command} {match aspath @var{as_path}} {} +Matches the specified @var{as_path}. +@end deffn + +@deffn {Route-map Command} {match metric @var{metric}} {} +Matches the specified @var{metric}. +@end deffn + +@deffn {Route-map Command} {match community @var{community_list}} {} +Matches the specified @var{community_list} +@end deffn + +@node Route Map Set Command, , Route Map Match Command, Route Map +@comment node-name, next, previous, up +@subsection Route Map Set Command + +@deffn {Route-map Command} {set ip next-hop @var{ipv4_address}} {} +Set the BGP nexthop address. +@end deffn + +@deffn {Route-map Command} {set local-preference @var{local_pref}} {} +Set the BGP local preference. +@end deffn + +@deffn {Route-map Command} {set weight @var{weight}} {} +Set the route's weight. +@end deffn + +@deffn {Route-map Command} {set metric @var{metric}} {} +Set the BGP attribute MED. +@end deffn + +@deffn {Route-map Command} {set as-path prepend @var{as_path}} {} +Set the BGP AS path to prepend. +@end deffn + +@deffn {Route-map Command} {set community @var{community}} {} +Set the BGP community attribute. +@end deffn + +@deffn {Route-map Command} {set ipv6 next-hop global @var{ipv6_address}} {} +Set the BGP-4+ global IPv6 nexthop address. +@end deffn + +@deffn {Route-map Command} {set ipv6 next-hop local @var{ipv6_address}} {} +Set the BGP-4+ link local IPv6 nexthop address. +@end deffn + diff --git a/doc/snmp.texi b/doc/snmp.texi new file mode 100644 index 00000000..315c91c9 --- /dev/null +++ b/doc/snmp.texi @@ -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 index 00000000..332e392f --- /dev/null +++ b/doc/texinfo.tex @@ -0,0 +1,5625 @@ +% texinfo.tex -- TeX macros to handle Texinfo files. +% +% Load plain if necessary, i.e., if running under initex. +\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi +% +\def\texinfoversion{1999-02-14.16}% +% +% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99 +% Free Software Foundation, Inc. +% +% This texinfo.tex file is free software; you can redistribute it and/or +% modify it under the terms of the GNU General Public License as +% published by the Free Software Foundation; either version 2, or (at +% your option) any later version. +% +% This texinfo.tex file is distributed in the hope that it will be +% useful, but WITHOUT ANY WARRANTY; without even the implied warranty +% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +% General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this texinfo.tex file; see the file COPYING. If not, write +% to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +% Boston, MA 02111-1307, USA. +% +% In other words, you are welcome to use, share and improve this program. +% You are forbidden to forbid anyone else to use, share and improve +% what you give them. Help stamp out software-hoarding! +% +% Please try the latest version of texinfo.tex before submitting bug +% reports; you can get the latest version from: +% ftp://ftp.gnu.org/pub/gnu/texinfo.tex +% (and all GNU mirrors, see http://www.gnu.org/order/ftp.html) +% ftp://tug.org/tex/texinfo.tex +% ftp://ctan.org/macros/texinfo/texinfo.tex +% (and all CTAN mirrors, finger ctan@ctan.org for a list). +% /home/gd/gnu/doc/texinfo.tex on the GNU machines. +% The texinfo.tex in any given Texinfo distribution could well be out +% of date, so if that's what you're using, please check. +% There is a small home page for Texinfo at http://texinfo.org/. +% +% Send bug reports to bug-texinfo@gnu.org. Please include including a +% complete document in each bug report with which we can reproduce the +% problem. Patches are, of course, greatly appreciated. +% +% To process a Texinfo manual with TeX, it's most reliable to use the +% texi2dvi shell script that comes with the distribution. For a simple +% manual foo.texi, however, you can get away with this: +% tex foo.texi +% texindex foo.?? +% tex foo.texi +% tex foo.texi +% dvips foo.dvi -o # or whatever, to process the dvi file; this makes foo.ps. +% The extra runs of TeX get the cross-reference information correct. +% Sometimes one run after texindex suffices, and sometimes you need more +% than two; texi2dvi does it as many times as necessary. +% +% It is possible to adapt texinfo.tex for other languages. You can get +% the existing language-specific files from ftp://ftp.gnu.org/gnu/texinfo/. + +\message{Loading texinfo [version \texinfoversion]:} + +% If in a .fmt file, print the version number +% and turn on active characters that we couldn't do earlier because +% they might have appeared in the input file name. +\everyjob{\message{[Texinfo version \texinfoversion]}% + \catcode`+=\active \catcode`\_=\active} + +% Save some parts of plain tex whose names we will redefine. + +\let\ptexb=\b +\let\ptexbullet=\bullet +\let\ptexc=\c +\let\ptexcomma=\, +\let\ptexdot=\. +\let\ptexdots=\dots +\let\ptexend=\end +\let\ptexequiv=\equiv +\let\ptexexclam=\! +\let\ptexi=\i +\let\ptexlbrace=\{ +\let\ptexrbrace=\} +\let\ptexstar=\* +\let\ptext=\t + +% We never want plain's outer \+ definition in Texinfo. +% For @tex, we can use \tabalign. +\let\+ = \relax + + +\message{Basics,} +\chardef\other=12 + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Set up fixed words for English if not already set. +\ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi +\ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi +\ifx\putwordfile\undefined \gdef\putwordfile{file}\fi +\ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi +\ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi +\ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi +\ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi +\ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi +\ifx\putwordof\undefined \gdef\putwordof{of}\fi +\ifx\putwordon\undefined \gdef\putwordon{on}\fi +\ifx\putwordpage\undefined \gdef\putwordpage{page}\fi +\ifx\putwordsection\undefined \gdef\putwordsection{section}\fi +\ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi +\ifx\putwordsee\undefined \gdef\putwordsee{see}\fi +\ifx\putwordSee\undefined \gdef\putwordSee{See}\fi +\ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi +\ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi +% +\ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi +\ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi +\ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi +\ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi +\ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi +\ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi +\ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi +\ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi +\ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi +\ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi +\ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi +\ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi +% +\ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi +\ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi +\ifx\putwordDefivar\undefined \gdef\putwordDefivar{Instance Variable}\fi +\ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi +\ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi +\ifx\putwordDeftypevar\undefined\gdef\putwordDeftypevar{Variable}\fi +\ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi +\ifx\putwordDeftypefun\undefined\gdef\putwordDeftypefun{Function}\fi + +% Ignore a token. +% +\def\gobble#1{} + +\hyphenation{ap-pen-dix} +\hyphenation{mini-buf-fer mini-buf-fers} +\hyphenation{eshell} +\hyphenation{white-space} + +% Margin to add to right of even pages, to left of odd pages. +\newdimen \bindingoffset +\newdimen \normaloffset +\newdimen\pagewidth \newdimen\pageheight + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% since that produces some useless output on the terminal. +% +\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% +\ifx\eTeXversion\undefined +\def\loggingall{\tracingcommands2 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% +\else +\def\loggingall{\tracingcommands3 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \tracingscantokens1 \tracingassigns1 \tracingifs1 + \tracinggroups1 \tracingnesting2 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% +\fi + +% For @cropmarks command. +% Do @cropmarks to get crop marks. +% +\newif\ifcropmarks +\let\cropmarks = \cropmarkstrue +% +% Dimensions to add cropmarks at corners. +% Added by P. A. MacKay, 12 Nov. 1986 +% +\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines +\newdimen\cornerlong \cornerlong=1pc +\newdimen\cornerthick \cornerthick=.3pt +\newdimen\topandbottommargin \topandbottommargin=.75in + +% Main output routine. +\chardef\PAGE = 255 +\output = {\onepageout{\pagecontents\PAGE}} + +\newbox\headlinebox +\newbox\footlinebox + +% \onepageout takes a vbox as an argument. Note that \pagecontents +% does insertions, but you have to call it yourself. +\def\onepageout#1{% + \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi + % + \ifodd\pageno \advance\hoffset by \bindingoffset + \else \advance\hoffset by -\bindingoffset\fi + % + % Do this outside of the \shipout so @code etc. will be expanded in + % the headline as they should be, not taken literally (outputting ''code). + \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% + \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% + % + {% + % Have to do this stuff outside the \shipout because we want it to + % take effect in \write's, yet the group defined by the \vbox ends + % before the \shipout runs. + % + \escapechar = `\\ % use backslash in output files. + \indexdummies % don't expand commands in the output. + \normalturnoffactive % \ in index entries must not stay \, e.g., if + % the page break happens to be in the middle of an example. + \shipout\vbox{% + \ifcropmarks \vbox to \outervsize\bgroup + \hsize = \outerhsize + \vskip-\topandbottommargin + \vtop to0pt{% + \line{\ewtop\hfil\ewtop}% + \nointerlineskip + \line{% + \vbox{\moveleft\cornerthick\nstop}% + \hfill + \vbox{\moveright\cornerthick\nstop}% + }% + \vss}% + \vskip\topandbottommargin + \line\bgroup + \hfil % center the page within the outer (page) hsize. + \ifodd\pageno\hskip\bindingoffset\fi + \vbox\bgroup + \fi + % + \unvbox\headlinebox + \pagebody{#1}% + \ifdim\ht\footlinebox > 0pt + % Only leave this space if the footline is nonempty. + % (We lessened \vsize for it in \oddfootingxxx.) + % The \baselineskip=24pt in plain's \makefootline has no effect. + \vskip 2\baselineskip + \unvbox\footlinebox + \fi + % + \ifcropmarks + \egroup % end of \vbox\bgroup + \hfil\egroup % end of (centering) \line\bgroup + \vskip\topandbottommargin plus1fill minus1fill + \boxmaxdepth = \cornerthick + \vbox to0pt{\vss + \line{% + \vbox{\moveleft\cornerthick\nsbot}% + \hfill + \vbox{\moveright\cornerthick\nsbot}% + }% + \nointerlineskip + \line{\ewbot\hfil\ewbot}% + }% + \egroup % \vbox from first cropmarks clause + \fi + }% end of \shipout\vbox + }% end of group with \turnoffactive + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi +} + +\newinsert\margin \dimen\margin=\maxdimen + +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +% marginal hacks, juha@viisa.uucp (Juha Takala) +\ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi +\dimen@=\dp#1 \unvbox#1 +\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi +\ifr@ggedbottom \kern-\dimen@ \vfil \fi} +} + +% Here are the rules for the cropmarks. Note that they are +% offset so that the space between them is truly \outerhsize or \outervsize +% (P. A. MacKay, 12 November, 1986) +% +\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} +\def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} +\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} +\def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + +% Parse an argument, then pass it to #1. The argument is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% +\def\parsearg#1{% + \let\next = #1% + \begingroup + \obeylines + \futurelet\temp\parseargx +} + +% If the next token is an obeyed space (from an @example environment or +% the like), remove it and recurse. Otherwise, we're done. +\def\parseargx{% + % \obeyedspace is defined far below, after the definition of \sepspaces. + \ifx\obeyedspace\temp + \expandafter\parseargdiscardspace + \else + \expandafter\parseargline + \fi +} + +% Remove a single space (as the delimiter token to the macro call). +{\obeyspaces % + \gdef\parseargdiscardspace {\futurelet\temp\parseargx}} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + % + % First remove any @c comment, then any @comment. + % Result of each macro is put in \toks0. + \argremovec #1\c\relax % + \expandafter\argremovecomment \the\toks0 \comment\relax % + % + % Call the caller's macro, saved as \next in \parsearg. + \expandafter\next\expandafter{\the\toks0}% + }% +} + +% Since all \c{,omment} does is throw away the argument, we can let TeX +% do that for us. The \relax here is matched by the \relax in the call +% in \parseargline; it could be more or less anything, its purpose is +% just to delimit the argument to the \c. +\def\argremovec#1\c#2\relax{\toks0 = {#1}} +\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}} + +% \argremovec{,omment} might leave us with trailing spaces, though; e.g., +% @end itemize @c foo +% will have two active spaces as part of the argument with the +% `itemize'. Here we remove all active spaces from #1, and assign the +% result to \toks0. +% +% This loses if there are any *other* active characters besides spaces +% in the argument -- _ ^ +, for example -- since they get expanded. +% Fortunately, Texinfo does not define any such commands. (If it ever +% does, the catcode of the characters in questionwill have to be changed +% here.) But this means we cannot call \removeactivespaces as part of +% \argremovec{,omment}, since @c uses \parsearg, and thus the argument +% that \parsearg gets might well have any character at all in it. +% +\def\removeactivespaces#1{% + \begingroup + \ignoreactivespaces + \edef\temp{#1}% + \global\toks0 = \expandafter{\temp}% + \endgroup +} + +% Change the active space to expand to nothing. +% +\begingroup + \obeyspaces + \gdef\ignoreactivespaces{\obeyspaces\let =\empty} +\endgroup + + +\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + +%% These are used to keep @begin/@end levels from running away +%% Call \inENV within environments (after a \begingroup) +\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi} +\def\ENVcheck{% +\ifENV\errmessage{Still within an environment; press RETURN to continue} +\endgroup\fi} % This is not perfect, but it should reduce lossage + +% @begin foo is the same as @foo, for now. +\newhelp\EMsimple{Press RETURN to continue.} + +\outer\def\begin{\parsearg\beginxxx} + +\def\beginxxx #1{% +\expandafter\ifx\csname #1\endcsname\relax +{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else +\csname #1\endcsname\fi} + +% @end foo executes the definition of \Efoo. +% +\def\end{\parsearg\endxxx} +\def\endxxx #1{% + \removeactivespaces{#1}% + \edef\endthing{\the\toks0}% + % + \expandafter\ifx\csname E\endthing\endcsname\relax + \expandafter\ifx\csname \endthing\endcsname\relax + % There's no \foo, i.e., no ``environment'' foo. + \errhelp = \EMsimple + \errmessage{Undefined command `@end \endthing'}% + \else + \unmatchedenderror\endthing + \fi + \else + % Everything's ok; the right environment has been started. + \csname E\endthing\endcsname + \fi +} + +% There is an environment #1, but it hasn't been started. Give an error. +% +\def\unmatchedenderror#1{% + \errhelp = \EMsimple + \errmessage{This `@end #1' doesn't have a matching `@#1'}% +} + +% Define the control sequence \E#1 to give an unmatched @end error. +% +\def\defineunmatchedend#1{% + \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}% +} + + +% Single-spacing is done by various environments (specifically, in +% \nonfillstart and \quotations). +\newskip\singlespaceskip \singlespaceskip = 12.5pt +\def\singlespace{% + % Why was this kern here? It messes up equalizing space above and below + % environments. --karl, 6may93 + %{\advance \baselineskip by -\singlespaceskip + %\kern \baselineskip}% + \setleading \singlespaceskip +} + +%% Simple single-character @ commands + +% @@ prints an @ +% Kludge this until the fonts are right (grr). +\def\@{{\tt\char64}} + +% This is turned off because it was never documented +% and you can use @w{...} around a quote to suppress ligatures. +%% Define @` and @' to be the same as ` and ' +%% but suppressing ligatures. +%\def\`{{`}} +%\def\'{{'}} + +% Used to generate quoted braces. +\def\mylbrace {{\tt\char123}} +\def\myrbrace {{\tt\char125}} +\let\{=\mylbrace +\let\}=\myrbrace +\begingroup + % Definitions to produce actual \{ & \} command in an index. + \catcode`\{ = 12 \catcode`\} = 12 + \catcode`\[ = 1 \catcode`\] = 2 + \catcode`\@ = 0 \catcode`\\ = 12 + @gdef@lbracecmd[\{]% + @gdef@rbracecmd[\}]% +@endgroup + +% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent +% Others are defined by plain TeX: @` @' @" @^ @~ @= @v @H. +\let\, = \c +\let\dotaccent = \. +\def\ringaccent#1{{\accent23 #1}} +\let\tieaccent = \t +\let\ubaraccent = \b +\let\udotaccent = \d + +% Other special characters: @questiondown @exclamdown +% Plain TeX defines: @AA @AE @O @OE @L (and lowercase versions) @ss. +\def\questiondown{?`} +\def\exclamdown{!`} + +% Dotless i and dotless j, used for accents. +\def\imacro{i} +\def\jmacro{j} +\def\dotless#1{% + \def\temp{#1}% + \ifx\temp\imacro \ptexi + \else\ifx\temp\jmacro \j + \else \errmessage{@dotless can be used only with i or j}% + \fi\fi +} + +% Be sure we're in horizontal mode when doing a tie, since we make space +% equivalent to this in @example-like environments. Otherwise, a space +% at the beginning of a line will start with \penalty -- and +% since \penalty is valid in vertical mode, we'd end up putting the +% penalty on the vertical list instead of in the new paragraph. +{\catcode`@ = 11 + % Avoid using \@M directly, because that causes trouble + % if the definition is written into an index file. + \global\let\tiepenalty = \@M + \gdef\tie{\leavevmode\penalty\tiepenalty\ } +} + +% @: forces normal size whitespace following. +\def\:{\spacefactor=1000 } + +% @* forces a line break. +\def\*{\hfil\break\hbox{}\ignorespaces} + +% @. is an end-of-sentence period. +\def\.{.\spacefactor=3000 } + +% @! is an end-of-sentence bang. +\def\!{!\spacefactor=3000 } + +% @? is an end-of-sentence query. +\def\?{?\spacefactor=3000 } + +% @w prevents a word break. Without the \leavevmode, @w at the +% beginning of a paragraph, when TeX is still in vertical mode, would +% produce a whole line of output instead of starting the paragraph. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% max (\topskip - \ht (first item), 0). If that height is large, +% therefore, no glue is inserted, and the space between the headline and +% the text is small, which looks bad. +% +\def\group{\begingroup + \ifnum\catcode13=\active \else + \errhelp = \groupinvalidhelp + \errmessage{@group invalid in context where filling is enabled}% + \fi + % + % The \vtop we start below produces a box with normal height and large + % depth; thus, TeX puts \baselineskip glue before it, and (when the + % next line of text is done) \lineskip glue after it. (See p.82 of + % the TeXbook.) Thus, space below is not quite equal to space + % above. But it's pretty close. + \def\Egroup{% + \egroup % End the \vtop. + \endgroup % End the \group. + }% + % + \vtop\bgroup + % We have to put a strut on the last line in case the @group is in + % the midst of an example, rather than completely enclosing it. + % Otherwise, the interline space between the last line of the group + % and the first line afterwards is too small. But we can't put the + % strut in \Egroup, since there it would be on a line by itself. + % Hence this just inserts a strut at the beginning of each line. + \everypar = {\strut}% + % + % Since we have a strut on every line, we don't need any of TeX's + % normal interline spacing. + \offinterlineskip + % + % OK, but now we have to do something about blank + % lines in the input in @example-like environments, which normally + % just turn into \lisppar, which will insert no space now that we've + % turned off the interline space. Simplest is to make them be an + % empty paragraph. + \ifx\par\lisppar + \edef\par{\leavevmode \par}% + % + % Reset ^^M's definition to new definition of \par. + \obeylines + \fi + % + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an + % end-of-line in the output. We don't want the end-of-line after + % the `@group' to put extra space in the output. Since @group + % should appear on a line by itself (according to the Texinfo + % manual), we don't worry about eating any user text. + \comment +} +% +% TeX puts in an \escapechar (i.e., `@') at the beginning of the help +% message, so this ends up printing `@group can only ...'. +% +\newhelp\groupinvalidhelp{% +group can only be used in environments such as @example,^^J% +where each line of input produces a line of output.} + +% @need space-in-mils +% forces a page break if there is not space-in-mils remaining. + +\newdimen\mil \mil=0.001in + +\def\need{\parsearg\needx} + +% Old definition--didn't work. +%\def\needx #1{\par % +%% This method tries to make TeX break the page naturally +%% if the depth of the box does not fit. +%{\baselineskip=0pt% +%\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak +%\prevdepth=-1000pt +%}} + +\def\needx#1{% + % Go into vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % Don't add any leading before our big empty box, but allow a page + % break, since the best break might be right here. + \allowbreak + \nointerlineskip + \vtop to #1\mil{\vfil}% + % + % TeX does not even consider page breaks if a penalty added to the + % main vertical list is 10000 or more. But in order to see if the + % empty box we just added fits on the page, we must make it consider + % page breaks. On the other hand, we don't want to actually break the + % page after the empty box. So we use a penalty of 9999. + % + % There is an extremely small chance that TeX will actually break the + % page at this \penalty, if there are no other feasible breakpoints in + % sight. (If the user is using lots of big @group commands, which + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak +} + +% @br forces paragraph break + +\let\br = \par + +% @dots{} output an ellipsis using the current font. +% We do .5em per period so that it has the same spacing in a typewriter +% font as three actual period characters. +% +\def\dots{% + \leavevmode + \hbox to 1.5em{% + \hskip 0pt plus 0.25fil minus 0.25fil + .\hss.\hss.% + \hskip 0pt plus 0.5fil minus 0.5fil + }% +} + +% @enddots{} is an end-of-sentence ellipsis. +% +\def\enddots{% + \leavevmode + \hbox to 2em{% + \hskip 0pt plus 0.25fil minus 0.25fil + .\hss.\hss.\hss.% + \hskip 0pt plus 0.5fil minus 0.5fil + }% + \spacefactor=3000 +} + + +% @page forces the start of a new page +% +\def\page{\par\vfill\supereject} + +% @exdent text.... +% outputs text on separate line in roman font, starting at standard page margin + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\def\exdent{\parsearg\exdentyyy} +\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}} + +% This defn is used inside nofill environments such as @example. +\def\nofillexdent{\parsearg\nofillexdentyyy} +\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount +\leftline{\hskip\leftskip{\rm#1}}}} + +% @inmargin{TEXT} puts TEXT in the margin next to the current paragraph. + +\def\inmargin#1{% +\strut\vadjust{\nobreak\kern-\strutdepth + \vtop to \strutdepth{\baselineskip\strutdepth\vss + \llap{\rightskip=\inmarginspacing \vbox{\noindent #1}}\null}}} +\newskip\inmarginspacing \inmarginspacing=1cm +\def\strutdepth{\dp\strutbox} + +%\hbox{{\rm#1}}\hfil\break}} + +% @include file insert text of that file as input. +% Allow normal characters that we make active in the argument (a file name). +\def\include{\begingroup + \catcode`\\=12 + \catcode`~=12 + \catcode`^=12 + \catcode`_=12 + \catcode`|=12 + \catcode`<=12 + \catcode`>=12 + \catcode`+=12 + \parsearg\includezzz} +% Restore active chars for included file. +\def\includezzz#1{\endgroup\begingroup + % Read the included file in a group so nested @include's work. + \def\thisfile{#1}% + \input\thisfile +\endgroup} + +\def\thisfile{} + +% @center line outputs that line, centered + +\def\center{\parsearg\centerzzz} +\def\centerzzz #1{{\advance\hsize by -\leftskip +\advance\hsize by -\rightskip +\centerline{#1}}} + +% @sp n outputs n lines of vertical space + +\def\sp{\parsearg\spxxx} +\def\spxxx #1{\vskip #1\baselineskip} + +% @comment ...line which is ignored... +% @c is the same as @comment +% @ignore ... @end ignore is another way to write a comment + +\def\comment{\begingroup \catcode`\^^M=\other% +\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% +\commentxxx} +{\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}} + +\let\c=\comment + +% @paragraphindent NCHARS +% We'll use ems for NCHARS, close enough. +% We cannot implement @paragraphindent asis, though. +% +\def\asisword{asis} % no translation, these are keywords +\def\noneword{none} +% +\def\paragraphindent{\parsearg\doparagraphindent} +\def\doparagraphindent#1{% + \def\temp{#1}% + \ifx\temp\asisword + \else + \ifx\temp\noneword + \defaultparindent = 0pt + \else + \defaultparindent = #1em + \fi + \fi + \parindent = \defaultparindent +} + +% @asis just yields its argument. Used with @table, for example. +% +\def\asis#1{#1} + +% @math means output in math mode. +% We don't use $'s directly in the definition of \math because control +% sequences like \math are expanded when the toc file is written. Then, +% we read the toc file back, the $'s will be normal characters (as they +% should be, according to the definition of Texinfo). So we must use a +% control sequence to switch into and out of math mode. +% +% This isn't quite enough for @math to work properly in indices, but it +% seems unlikely it will ever be needed there. +% +\let\implicitmath = $ +\def\math#1{\implicitmath #1\implicitmath} + +% @bullet and @minus need the same treatment as @math, just above. +\def\bullet{\implicitmath\ptexbullet\implicitmath} +\def\minus{\implicitmath-\implicitmath} + +% @refill is a no-op. +\let\refill=\relax + +% If working on a large document in chapters, it is convenient to +% be able to disable indexing, cross-referencing, and contents, for test runs. +% This is done with @novalidate (before @setfilename). +% +\newif\iflinks \linkstrue % by default we want the aux files. +\let\novalidate = \linksfalse + +% @setfilename is done at the beginning of every texinfo file. +% So open here the files we need to have open while reading the input. +% This makes it possible to make a .fmt file for texinfo. +\def\setfilename{% + \iflinks + \readauxfile + \fi % \openindices needs to do some work in any case. + \openindices + \fixbackslash % Turn off hack to swallow `\input texinfo'. + \global\let\setfilename=\comment % Ignore extra @setfilename cmds. + % + % If texinfo.cnf is present on the system, read it. + % Useful for site-wide @afourpaper, etc. + % Just to be on the safe side, close the input stream before the \input. + \openin 1 texinfo.cnf + \ifeof1 \let\temp=\relax \else \def\temp{\input texinfo.cnf }\fi + \closein1 + \temp + % + \comment % Ignore the actual filename. +} + +% Called from \setfilename. +% +\def\openindices{% + \newindex{cp}% + \newcodeindex{fn}% + \newcodeindex{vr}% + \newcodeindex{tp}% + \newcodeindex{ky}% + \newcodeindex{pg}% +} + +% @bye. +\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + + +\message{fonts,} +% Font-change commands. + +% Texinfo sort of supports the sans serif font style, which plain TeX does not. +% So we set up a \sf analogous to plain's \rm, etc. +\newfam\sffam +\def\sf{\fam=\sffam \tensf} +\let\li = \sf % Sometimes we call it \li, not \sf. + +% We don't need math for this one. +\def\ttsl{\tenttsl} + +% Use Computer Modern fonts at \magstephalf (11pt). +\newcount\mainmagstep +\mainmagstep=\magstephalf + +% Set the font macro #1 to the font named #2, adding on the +% specified font prefix (normally `cm'). +% #3 is the font's design size, #4 is a scale factor +\def\setfont#1#2#3#4{\font#1=\fontprefix#2#3 scaled #4} + +% Use cm as the default font prefix. +% To specify the font prefix, you must define \fontprefix +% before you read in texinfo.tex. +\ifx\fontprefix\undefined +\def\fontprefix{cm} +\fi +% Support font families that don't use the same naming scheme as CM. +\def\rmshape{r} +\def\rmbshape{bx} %where the normal face is bold +\def\bfshape{b} +\def\bxshape{bx} +\def\ttshape{tt} +\def\ttbshape{tt} +\def\ttslshape{sltt} +\def\itshape{ti} +\def\itbshape{bxti} +\def\slshape{sl} +\def\slbshape{bxsl} +\def\sfshape{ss} +\def\sfbshape{ss} +\def\scshape{csc} +\def\scbshape{csc} + +\ifx\bigger\relax +\let\mainmagstep=\magstep1 +\setfont\textrm\rmshape{12}{1000} +\setfont\texttt\ttshape{12}{1000} +\else +\setfont\textrm\rmshape{10}{\mainmagstep} +\setfont\texttt\ttshape{10}{\mainmagstep} +\fi +% Instead of cmb10, you many want to use cmbx10. +% cmbx10 is a prettier font on its own, but cmb10 +% looks better when embedded in a line with cmr10. +\setfont\textbf\bfshape{10}{\mainmagstep} +\setfont\textit\itshape{10}{\mainmagstep} +\setfont\textsl\slshape{10}{\mainmagstep} +\setfont\textsf\sfshape{10}{\mainmagstep} +\setfont\textsc\scshape{10}{\mainmagstep} +\setfont\textttsl\ttslshape{10}{\mainmagstep} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep + +% A few fonts for @defun, etc. +\setfont\defbf\bxshape{10}{\magstep1} %was 1314 +\setfont\deftt\ttshape{10}{\magstep1} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf} + +% Fonts for indices and small examples (9pt). +% We actually use the slanted font rather than the italic, +% because texinfo normally uses the slanted fonts for that. +% Do not make many font distinctions in general in the index, since they +% aren't very useful. +\setfont\ninett\ttshape{9}{1000} +\setfont\ninettsl\ttslshape{10}{900} +\setfont\indrm\rmshape{9}{1000} +\setfont\indit\itshape{9}{1000} +\setfont\indsl\slshape{9}{1000} +\let\indtt=\ninett +\let\indttsl=\ninettsl +\let\indsf=\indrm +\let\indbf=\indrm +\setfont\indsc\scshape{10}{900} +\font\indi=cmmi9 +\font\indsy=cmsy9 + +% Fonts for title page: +\setfont\titlerm\rmbshape{12}{\magstep3} +\setfont\titleit\itbshape{10}{\magstep4} +\setfont\titlesl\slbshape{10}{\magstep4} +\setfont\titlett\ttbshape{12}{\magstep3} +\setfont\titlettsl\ttslshape{10}{\magstep4} +\setfont\titlesf\sfbshape{17}{\magstep1} +\let\titlebf=\titlerm +\setfont\titlesc\scbshape{10}{\magstep4} +\font\titlei=cmmi12 scaled \magstep3 +\font\titlesy=cmsy10 scaled \magstep4 +\def\authorrm{\secrm} + +% Chapter (and unnumbered) fonts (17.28pt). +\setfont\chaprm\rmbshape{12}{\magstep2} +\setfont\chapit\itbshape{10}{\magstep3} +\setfont\chapsl\slbshape{10}{\magstep3} +\setfont\chaptt\ttbshape{12}{\magstep2} +\setfont\chapttsl\ttslshape{10}{\magstep3} +\setfont\chapsf\sfbshape{17}{1000} +\let\chapbf=\chaprm +\setfont\chapsc\scbshape{10}{\magstep3} +\font\chapi=cmmi12 scaled \magstep2 +\font\chapsy=cmsy10 scaled \magstep3 + +% Section fonts (14.4pt). +\setfont\secrm\rmbshape{12}{\magstep1} +\setfont\secit\itbshape{10}{\magstep2} +\setfont\secsl\slbshape{10}{\magstep2} +\setfont\sectt\ttbshape{12}{\magstep1} +\setfont\secttsl\ttslshape{10}{\magstep2} +\setfont\secsf\sfbshape{12}{\magstep1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep2} +\font\seci=cmmi12 scaled \magstep1 +\font\secsy=cmsy10 scaled \magstep2 + +% \setfont\ssecrm\bxshape{10}{\magstep1} % This size an font looked bad. +% \setfont\ssecit\itshape{10}{\magstep1} % The letters were too crowded. +% \setfont\ssecsl\slshape{10}{\magstep1} +% \setfont\ssectt\ttshape{10}{\magstep1} +% \setfont\ssecsf\sfshape{10}{\magstep1} + +%\setfont\ssecrm\bfshape{10}{1315} % Note the use of cmb rather than cmbx. +%\setfont\ssecit\itshape{10}{1315} % Also, the size is a little larger than +%\setfont\ssecsl\slshape{10}{1315} % being scaled magstep1. +%\setfont\ssectt\ttshape{10}{1315} +%\setfont\ssecsf\sfshape{10}{1315} + +%\let\ssecbf=\ssecrm + +% Subsection fonts (13.15pt). +\setfont\ssecrm\rmbshape{12}{\magstephalf} +\setfont\ssecit\itbshape{10}{1315} +\setfont\ssecsl\slbshape{10}{1315} +\setfont\ssectt\ttbshape{12}{\magstephalf} +\setfont\ssecttsl\ttslshape{10}{1315} +\setfont\ssecsf\sfbshape{12}{\magstephalf} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{\magstep1} +\font\sseci=cmmi12 scaled \magstephalf +\font\ssecsy=cmsy10 scaled 1315 +% The smallcaps and symbol fonts should actually be scaled \magstep1.5, +% but that is not a standard magnification. + +% In order for the font changes to affect most math symbols and letters, +% we have to define the \textfont of the standard families. Since +% texinfo doesn't allow for producing subscripts and superscripts, we +% don't bother to reset \scriptfont and \scriptscriptfont (which would +% also require loading a lot more fonts). +% +\def\resetmathfonts{% + \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy + \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf + \textfont\ttfam = \tentt \textfont\sffam = \tensf +} + + +% The font-changing commands redefine the meanings of \tenSTYLE, instead +% of just \STYLE. We do this so that font changes will continue to work +% in math mode, where it is the current \fam that is relevant in most +% cases, not the current font. Plain TeX does \def\bf{\fam=\bffam +% \tenbf}, for example. By redefining \tenbf, we obviate the need to +% redefine \bf itself. +\def\textfonts{% + \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl + \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc + \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl + \resetmathfonts} +\def\titlefonts{% + \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl + \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc + \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy + \let\tenttsl=\titlettsl + \resetmathfonts \setleading{25pt}} +\def\titlefont#1{{\titlefonts\rm #1}} +\def\chapfonts{% + \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl + \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl + \resetmathfonts \setleading{19pt}} +\def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl + \resetmathfonts \setleading{16pt}} +\def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl + \resetmathfonts \setleading{15pt}} +\let\subsubsecfonts = \subsecfonts % Maybe make sssec fonts scaled magstephalf? +\def\indexfonts{% + \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl + \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc + \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy \let\tenttsl=\indttsl + \resetmathfonts \setleading{12pt}} + +% Set up the default fonts, so we can use them for creating boxes. +% +\textfonts + +% Define these so they can be easily changed for other fonts. +\def\angleleft{$\langle$} +\def\angleright{$\rangle$} + +% Count depth in font-changes, for error checks +\newcount\fontdepth \fontdepth=0 + +% Fonts for short table of contents. +\setfont\shortcontrm\rmshape{12}{1000} +\setfont\shortcontbf\bxshape{12}{1000} +\setfont\shortcontsl\slshape{12}{1000} + +%% Add scribe-like font environments, plus @l for inline lisp (usually sans +%% serif) and @ii for TeX italic + +% \smartitalic{ARG} outputs arg in italics, followed by an italic correction +% unless the following character is such as not to need one. +\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi} +\def\smartslanted#1{{\sl #1}\futurelet\next\smartitalicx} +\def\smartitalic#1{{\it #1}\futurelet\next\smartitalicx} + +\let\i=\smartitalic +\let\var=\smartslanted +\let\dfn=\smartslanted +\let\emph=\smartitalic +\let\cite=\smartslanted + +\def\b#1{{\bf #1}} +\let\strong=\b + +% We can't just use \exhyphenpenalty, because that only has effect at +% the end of a paragraph. Restore normal hyphenation at the end of the +% group within which \nohyphenation is presumably called. +% +\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} +\def\restorehyphenation{\hyphenchar\font = `- } + +\def\t#1{% + {\tt \rawbackslash \frenchspacing #1}% + \null +} +\let\ttfont=\t +\def\samp#1{`\tclose{#1}'\null} +\setfont\smallrm\rmshape{8}{1000} +\font\smallsy=cmsy9 +\def\key#1{{\smallrm\textfont2=\smallsy \leavevmode\hbox{% + \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{% + \vbox{\hrule\kern-0.4pt + \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}% + \kern-0.4pt\hrule}% + \kern-.06em\raise0.4pt\hbox{\angleright}}}} +% The old definition, with no lozenge: +%\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null} +\def\ctrl #1{{\tt \rawbackslash \hat}#1} + +% @file, @option are the same as @samp. +\let\file=\samp +\let\option=\samp + +% @code is a modification of @t, +% which makes spaces the same size as normal in the surrounding text. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \frenchspacing + #1% + }% + \null +} + +% We *must* turn on hyphenation at `-' and `_' in \code. +% Otherwise, it is too hard to avoid overfull hboxes +% in the Emacs manual, the Library manual, etc. + +% Unfortunately, TeX uses one parameter (\hyphenchar) to control +% both hyphenation at - and hyphenation within words. +% We must therefore turn them both off (\tclose does that) +% and arrange explicitly to hyphenate at a dash. +% -- rms. +{ + \catcode`\-=\active + \catcode`\_=\active + % + \global\def\code{\begingroup + \catcode`\-=\active \let-\codedash + \catcode`\_=\active \let_\codeunder + \codex + } + % + % If we end up with any active - characters when handling the index, + % just treat them as a normal -. + \global\def\indexbreaks{\catcode`\-=\active \let-\realdash} +} + +\def\realdash{-} +\def\codedash{-\discretionary{}{}{}} +\def\codeunder{\ifusingtt{\normalunderscore\discretionary{}{}{}}{\_}} +\def\codex #1{\tclose{#1}\endgroup} + +%\let\exp=\tclose %Was temporary + +% @kbd is like @code, except that if the argument is just one @key command, +% then @kbd has no effect. + +% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), +% `example' (@kbd uses ttsl only inside of @example and friends), +% or `code' (@kbd uses normal tty font always). +\def\kbdinputstyle{\parsearg\kbdinputstylexxx} +\def\kbdinputstylexxx#1{% + \def\arg{#1}% + \ifx\arg\worddistinct + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% + \else\ifx\arg\wordexample + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% + \else\ifx\arg\wordcode + \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% + \fi\fi\fi +} +\def\worddistinct{distinct} +\def\wordexample{example} +\def\wordcode{code} + +% Default is kbdinputdistinct. (Too much of a hassle to call the macro, +% the catcodes are wrong for parsearg to work.) +\gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl} + +\def\xkey{\key} +\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% +\ifx\one\xkey\ifx\threex\three \key{#2}% +\else{\tclose{\kbdfont\look}}\fi +\else{\tclose{\kbdfont\look}}\fi} + +% For @url, @env, @command quotes seem unnecessary, so use \code. +\let\url=\code +\let\env=\code +\let\command=\code + +% @uref (abbreviation for `urlref') takes an optional (comma-separated) +% second argument specifying the text to display and an optional third +% arg as text to display instead of (rather than in addition to) the url +% itself. First (mandatory) arg is the url. Perhaps eventually put in +% a hypertex \special here. +% +\def\uref#1{\douref #1,,,\finish} +\def\douref#1,#2,#3,#4\finish{% + \setbox0 = \hbox{\ignorespaces #3}% + \ifdim\wd0 > 0pt + \unhbox0 % third arg given, show only that + \else + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0 > 0pt + \unhbox0\ (\code{#1})% second arg given, show both it and url + \else + \code{#1}% only url given, so show it + \fi + \fi +} + +% rms does not like the angle brackets --karl, 17may97. +% So now @email is just like @uref. +%\def\email#1{\angleleft{\tt #1}\angleright} +\let\email=\uref + +% Check if we are currently using a typewriter font. Since all the +% Computer Modern typewriter fonts have zero interword stretch (and +% shrink), and it is reasonable to expect all typewriter fonts to have +% this property, we can check that font parameter. +% +\def\ifmonospace{\ifdim\fontdimen3\font=0pt } + +% Typeset a dimension, e.g., `in' or `pt'. The only reason for the +% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt. +% +\def\dmn#1{\thinspace #1} + +\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} + +% @l was never documented to mean ``switch to the Lisp font'', +% and it is not used as such in any manual I can find. We need it for +% Polish suppressed-l. --karl, 22sep96. +%\def\l#1{{\li #1}\null} + +% Explicit font changes: @r, @sc, undocumented @ii. +\def\r#1{{\rm #1}} % roman font +\def\sc#1{{\smallcaps#1}} % smallcaps font +\def\ii#1{{\it #1}} % italic font + +% @acronym downcases the argument and prints in smallcaps. +\def\acronym#1{{\smallcaps \lowercase{#1}}} + +% @pounds{} is a sterling sign. +\def\pounds{{\it\$}} + + +\message{page headings,} + +\newskip\titlepagetopglue \titlepagetopglue = 1.5in +\newskip\titlepagebottomglue \titlepagebottomglue = 2pc + +% First the title page. Must do @settitle before @titlepage. +\newif\ifseenauthor +\newif\iffinishedtitlepage + +% Do an implicit @contents or @shortcontents after @end titlepage if the +% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage. +% +\newif\ifsetcontentsaftertitlepage + \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue +\newif\ifsetshortcontentsaftertitlepage + \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue + +\def\shorttitlepage{\parsearg\shorttitlepagezzz} +\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\def\titlepage{\begingroup \parindent=0pt \textfonts + \let\subtitlerm=\tenrm + \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}% + % + \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}% + % + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % + % Now you can print the title using @title. + \def\title{\parsearg\titlezzz}% + \def\titlezzz##1{\leftline{\titlefonts\rm ##1} + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt width \hsize \vskip4pt}% + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Now you can put text using @subtitle. + \def\subtitle{\parsearg\subtitlezzz}% + \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}% + % + % @author should come last, but may come many times. + \def\author{\parsearg\authorzzz}% + \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi + {\authorfont \leftline{##1}}}% + % + % Most title ``pages'' are actually two pages long, with space + % at the top of the second. We don't want the ragged left on the second. + \let\oldpage = \page + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \oldpage + \let\page = \oldpage + \hbox{}}% +% \def\page{\oldpage \hbox{}} +} + +\def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + % + % If they want short, they certainly want long too. + \ifsetshortcontentsaftertitlepage + \shortcontents + \contents + \global\let\shortcontents = \relax + \global\let\contents = \relax + \fi + % + \ifsetcontentsaftertitlepage + \contents + \global\let\contents = \relax + \global\let\shortcontents = \relax + \fi + % + \HEADINGSon +} + +\def\finishtitlepage{% + \vskip4pt \hrule height 2pt width \hsize + \vskip\titlepagebottomglue + \finishedtitlepagetrue +} + +%%% Set up page headings and footings. + +\let\thispage=\folio + +\newtoks\evenheadline % headline on even pages +\newtoks\oddheadline % headline on odd pages +\newtoks\evenfootline % footline on even pages +\newtoks\oddfootline % footline on odd pages + +% Now make Tex use those variables +\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} +\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} +\let\HEADINGShook=\relax + +% Commands to set those variables. +% For example, this is what @headings on does +% @evenheading @thistitle|@thispage|@thischapter +% @oddheading @thischapter|@thispage|@thistitle +% @evenfooting @thisfile|| +% @oddfooting ||@thisfile + +\def\evenheading{\parsearg\evenheadingxxx} +\def\oddheading{\parsearg\oddheadingxxx} +\def\everyheading{\parsearg\everyheadingxxx} + +\def\evenfooting{\parsearg\evenfootingxxx} +\def\oddfooting{\parsearg\oddfootingxxx} +\def\everyfooting{\parsearg\everyfootingxxx} + +{\catcode`\@=0 % + +\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish} +\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish} +\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{% +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyheadingxxx#1{\oddheadingxxx{#1}\evenheadingxxx{#1}}% + +\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish} +\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish} +\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{% + \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% + % + % Leave some space for the footline. Hopefully ok to assume + % @evenfooting will not be used by itself. + \global\advance\pageheight by -\baselineskip + \global\advance\vsize by -\baselineskip +} + +\gdef\everyfootingxxx#1{\oddfootingxxx{#1}\evenfootingxxx{#1}} +% +}% unbind the catcode of @. + +% @headings double turns headings on for double-sided printing. +% @headings single turns headings on for single-sided printing. +% @headings off turns them off. +% @headings on same as @headings double, retained for compatibility. +% @headings after turns on double-sided headings after this page. +% @headings doubleafter turns on double-sided headings after this page. +% @headings singleafter turns on single-sided headings after this page. +% By default, they are off at the start of a document, +% and turned `on' after @end titlepage. + +\def\headings #1 {\csname HEADINGS#1\endcsname} + +\def\HEADINGSoff{ +\global\evenheadline={\hfil} \global\evenfootline={\hfil} +\global\oddheadline={\hfil} \global\oddfootline={\hfil}} +\HEADINGSoff +% When we turn headings on, set the page number to 1. +% For double-sided printing, put current file name in lower left corner, +% chapter name on inside top of right hand pages, document +% title on inside top of left hand pages, and page numbers on outside top +% edge of all pages. +\def\HEADINGSdouble{ +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} +\let\contentsalignmacro = \chappager + +% For single-sided printing, chapter title goes across top left of page, +% page number on top right. +\def\HEADINGSsingle{ +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} +\def\HEADINGSon{\HEADINGSdouble} + +\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} +\let\HEADINGSdoubleafter=\HEADINGSafter +\def\HEADINGSdoublex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} + +\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} +\def\HEADINGSsinglex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} + +% Subroutines used in generating headings +% Produces Day Month Year style of output. +\def\today{% + \number\day\space + \ifcase\month + \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr + \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug + \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec + \fi + \space\number\year} + +% @settitle line... specifies the title of the document, for headings. +% It generates no output of its own. +\def\thistitle{\putwordNoTitle} +\def\settitle{\parsearg\settitlezzz} +\def\settitlezzz #1{\gdef\thistitle{#1}} + + +\message{tables,} +% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x). + +% default indentation of table text +\newdimen\tableindent \tableindent=.8in +% default indentation of @itemize and @enumerate text +\newdimen\itemindent \itemindent=.3in +% margin between end of table item and start of table text. +\newdimen\itemmargin \itemmargin=.1in + +% used internally for \itemindent minus \itemmargin +\newdimen\itemmax + +% Note @table, @vtable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\newif\ifitemxneedsnegativevskip + +\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\itemxpar \parsearg\itemzzz} + +\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz} +\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz} + +\def\internalBkitem{\smallbreak \parsearg\kitemzzz} +\def\internalBkitemx{\itemxpar \parsearg\kitemzzz} + +\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}% + \itemzzz {#1}} + +\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}% + \itemzzz {#1}} + +\def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemfont{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % If the item text does not fit in the space we have, put it on a line + % by itself, and do not allow a page break either before or after that + % line. We do not start a paragraph here because then if the next + % command is, e.g., @kindex, the whatsit would get put into the + % horizontal list on a line by itself, resulting in extra blank space. + \ifdim \wd0>\itemmax + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil + \leavevmode\unhbox0\par + \endgroup + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. Unfortunately + % we can't prevent a possible page break at the following + % \baselineskip glue. + \nobreak + \endgroup + \itemxneedsnegativevskipfalse + \else + % The item text fits into the space. Start a paragraph, so that the + % following text (if any) will end up on the same line. + \noindent + % Do this with kerns and \unhbox so that if there is a footnote in + % the item text, it can migrate to the main vertical list and + % eventually be printed. + \nobreak\kern-\tableindent + \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0 + \unhbox0 + \nobreak\kern\dimen0 + \endgroup + \itemxneedsnegativevskiptrue + \fi +} + +\def\item{\errmessage{@item while not in a table}} +\def\itemx{\errmessage{@itemx while not in a table}} +\def\kitem{\errmessage{@kitem while not in a table}} +\def\kitemx{\errmessage{@kitemx while not in a table}} +\def\xitem{\errmessage{@xitem while not in a table}} +\def\xitemx{\errmessage{@xitemx while not in a table}} + +% Contains a kludge to get @end[description] to work. +\def\description{\tablez{\dontindex}{1}{}{}{}{}} + +% @table, @ftable, @vtable. +\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex} +{\obeylines\obeyspaces% +\gdef\tablex #1^^M{% +\tabley\dontindex#1 \endtabley}} + +\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex} +{\obeylines\obeyspaces% +\gdef\ftablex #1^^M{% +\tabley\fnitemindex#1 \endtabley +\def\Eftable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex} +{\obeylines\obeyspaces% +\gdef\vtablex #1^^M{% +\tabley\vritemindex#1 \endtabley +\def\Evtable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\dontindex #1{} +\def\fnitemindex #1{\doind {fn}{\code{#1}}}% +\def\vritemindex #1{\doind {vr}{\code{#1}}}% + +{\obeyspaces % +\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup% +\tablez{#1}{#2}{#3}{#4}{#5}{#6}}} + +\def\tablez #1#2#3#4#5#6{% +\aboveenvbreak % +\begingroup % +\def\Edescription{\Etable}% Necessary kludge. +\let\itemindex=#1% +\ifnum 0#3>0 \advance \leftskip by #3\mil \fi % +\ifnum 0#4>0 \tableindent=#4\mil \fi % +\ifnum 0#5>0 \advance \rightskip by #5\mil \fi % +\def\itemfont{#2}% +\itemmax=\tableindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \tableindent % +\exdentamount=\tableindent +\parindent = 0pt +\parskip = \smallskipamount +\ifdim \parskip=0pt \parskip=2pt \fi% +\def\Etable{\endgraf\afterenvbreak\endgroup}% +\let\item = \internalBitem % +\let\itemx = \internalBitemx % +\let\kitem = \internalBkitem % +\let\kitemx = \internalBkitemx % +\let\xitem = \internalBxitem % +\let\xitemx = \internalBxitemx % +} + +% This is the counter used by @enumerate, which is really @itemize + +\newcount \itemno + +\def\itemize{\parsearg\itemizezzz} + +\def\itemizezzz #1{% + \begingroup % ended by the @end itemize + \itemizey {#1}{\Eitemize} +} + +\def\itemizey #1#2{% +\aboveenvbreak % +\itemmax=\itemindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \itemindent % +\exdentamount=\itemindent +\parindent = 0pt % +\parskip = \smallskipamount % +\ifdim \parskip=0pt \parskip=2pt \fi% +\def#2{\endgraf\afterenvbreak\endgroup}% +\def\itemcontents{#1}% +\let\item=\itemizeitem} + +% Set sfcode to normal for the chars that usually have another value. +% These are `.?!:;,' +\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000 + \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 } + +% \splitoff TOKENS\endmark defines \first to be the first token in +% TOKENS, and \rest to be the remainder. +% +\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% + +% Allow an optional argument of an uppercase letter, lowercase letter, +% or number, to specify the first label in the enumerated list. No +% argument is the same as `1'. +% +\def\enumerate{\parsearg\enumeratezzz} +\def\enumeratezzz #1{\enumeratey #1 \endenumeratey} +\def\enumeratey #1 #2\endenumeratey{% + \begingroup % ended by the @end enumerate + % + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % An ``uppercase letter'' is one whose \lccode is both nonzero, and + % not equal to itself. + % Otherwise, we assume it's a number. + % + % We need the \relax at the end of the \ifnum lines to stop TeX from + % continuing to look for a . + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi +} + +% An @enumerate whose labels are integers. The starting integer is +% given in \thearg. +% +\def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% +} + +% The starting (lowercase) letter is in \thearg. +\def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% +} + +% The starting (uppercase) letter is in \thearg. +\def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% +} + +% Call itemizey, adding a period to the first argument and supplying the +% common last two arguments. Also subtract one from the initial value in +% \itemno, since @item increments \itemno. +% +\def\startenumeration#1{% + \advance\itemno by -1 + \itemizey{#1.}\Eenumerate\flushcr +} + +% @alphaenumerate and @capsenumerate are abbreviations for giving an arg +% to @enumerate. +% +\def\alphaenumerate{\enumerate{a}} +\def\capsenumerate{\enumerate{A}} +\def\Ealphaenumerate{\Eenumerate} +\def\Ecapsenumerate{\Eenumerate} + +% Definition of @item while inside @itemize. + +\def\itemizeitem{% +\advance\itemno by 1 +{\let\par=\endgraf \smallbreak}% +\ifhmode \errmessage{In hmode at itemizeitem}\fi +{\parskip=0in \hskip 0pt +\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}% +\vadjust{\penalty 1200}}% +\flushcr} + +% @multitable macros +% Amy Hendrickson, 8/18/94, 3/6/96 +% +% @multitable ... @end multitable will make as many columns as desired. +% Contents of each column will wrap at width given in preamble. Width +% can be specified either with sample text given in a template line, +% or in percent of \hsize, the current width of text on page. + +% Table can continue over pages but will only break between lines. + +% To make preamble: +% +% Either define widths of columns in terms of percent of \hsize: +% @multitable @columnfractions .25 .3 .45 +% @item ... +% +% Numbers following @columnfractions are the percent of the total +% current hsize to be used for each column. You may use as many +% columns as desired. + + +% Or use a template: +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item ... +% using the widest term desired in each column. +% +% For those who want to use more than one line's worth of words in +% the preamble, break the line within one argument and it +% will parse correctly, i.e., +% +% @multitable {Column 1 template} {Column 2 template} {Column 3 +% template} +% Not: +% @multitable {Column 1 template} {Column 2 template} +% {Column 3 template} + +% Each new table line starts with @item, each subsequent new column +% starts with @tab. Empty columns may be produced by supplying @tab's +% with nothing between them for as many times as empty columns are needed, +% ie, @tab@tab@tab will produce two empty columns. + +% @item, @tab, @multitable or @end multitable do not need to be on their +% own lines, but it will not hurt if they are. + +% Sample multitable: + +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item first col stuff @tab second col stuff @tab third col +% @item +% first col stuff +% @tab +% second col stuff +% @tab +% third col +% @item first col stuff @tab second col stuff +% @tab Many paragraphs of text may be used in any column. +% +% They will wrap at the width determined by the template. +% @item@tab@tab This will be in third column. +% @end multitable + +% Default dimensions may be reset by user. +% @multitableparskip is vertical space between paragraphs in table. +% @multitableparindent is paragraph indent in table. +% @multitablecolmargin is horizontal space to be left between columns. +% @multitablelinespace is space to leave between table items, baseline +% to baseline. +% 0pt means it depends on current normal line spacing. +% +\newskip\multitableparskip +\newskip\multitableparindent +\newdimen\multitablecolspace +\newskip\multitablelinespace +\multitableparskip=0pt +\multitableparindent=6pt +\multitablecolspace=12pt +\multitablelinespace=0pt + +% Macros used to set up halign preamble: +% +\let\endsetuptable\relax +\def\xendsetuptable{\endsetuptable} +\let\columnfractions\relax +\def\xcolumnfractions{\columnfractions} +\newif\ifsetpercent + +% #1 is the part of the @columnfraction before the decimal point, which +% is presumably either 0 or the empty string (but we don't check, we +% just throw it away). #2 is the decimal part, which we use as the +% percent of \hsize for this column. +\def\pickupwholefraction#1.#2 {% + \global\advance\colcount by 1 + \expandafter\xdef\csname col\the\colcount\endcsname{.#2\hsize}% + \setuptable +} + +\newcount\colcount +\def\setuptable#1{% + \def\firstarg{#1}% + \ifx\firstarg\xendsetuptable + \let\go = \relax + \else + \ifx\firstarg\xcolumnfractions + \global\setpercenttrue + \else + \ifsetpercent + \let\go\pickupwholefraction + \else + \global\advance\colcount by 1 + \setbox0=\hbox{#1\unskip }% Add a normal word space as a separator; + % typically that is always in the input, anyway. + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi + \fi + \ifx\go\pickupwholefraction + % Put the argument back for the \pickupwholefraction call, so + % we'll always have a period there to be parsed. + \def\go{\pickupwholefraction#1}% + \else + \let\go = \setuptable + \fi% + \fi + \go +} + +% multitable syntax +\def\tab{&\hskip1sp\relax} % 2/2/96 + % tiny skip here makes sure this column space is + % maintained, even if it is never used. + +% @multitable ... @end multitable definitions: +% +\def\multitable{\parsearg\dotable} +\def\dotable#1{\bgroup + \vskip\parskip + \let\item\crcr + \tolerance=9500 + \hbadness=9500 + \setmultitablespacing + \parskip=\multitableparskip + \parindent=\multitableparindent + \overfullrule=0pt + \global\colcount=0 + \def\Emultitable{\global\setpercentfalse\cr\egroup\egroup}% + % + % To parse everything between @multitable and @item: + \setuptable#1 \endsetuptable + % + % \everycr will reset column counter, \colcount, at the end of + % each line. Every column entry will cause \colcount to advance by one. + % The table preamble + % looks at the current \colcount to find the correct column width. + \everycr{\noalign{% + % + % \filbreak%% keeps underfull box messages off when table breaks over pages. + % Maybe so, but it also creates really weird page breaks when the table + % breaks over pages. Wouldn't \vfil be better? Wait until the problem + % manifests itself, so it can be fixed for real --karl. + \global\colcount=0\relax}}% + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. + \halign\bgroup&\global\advance\colcount by 1\relax + \multistrut\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname + % + % In order to keep entries from bumping into each other + % we will add a \leftskip of \multitablecolspace to all columns after + % the first one. + % + % If a template has been used, we will add \multitablecolspace + % to the width of each template entry. + % + % If the user has set preamble in terms of percent of \hsize we will + % use that dimension as the width of the column, and the \leftskip + % will keep entries from bumping into each other. Table will start at + % left margin and final column will justify at right margin. + % + % Make sure we don't inherit \rightskip from the outer environment. + \rightskip=0pt + \ifnum\colcount=1 + % The first column will be indented with the surrounding text. + \advance\hsize by\leftskip + \else + \ifsetpercent \else + % If user has not set preamble in terms of percent of \hsize + % we will advance \hsize by \multitablecolspace. + \advance\hsize by \multitablecolspace + \fi + % In either case we will make \leftskip=\multitablecolspace: + \leftskip=\multitablecolspace + \fi + % Ignoring space at the beginning and end avoids an occasional spurious + % blank line, when TeX decides to break the line at the space before the + % box from the multistrut, so the strut ends up on a line by itself. + % For example: + % @multitable @columnfractions .11 .89 + % @item @code{#} + % @tab Legal holiday which is valid in major parts of the whole country. + % Is automatically provided with highlighting sequences respectively marking + % characters. + \noindent\ignorespaces##\unskip\multistrut}\cr +} + +\def\setmultitablespacing{% test to see if user has set \multitablelinespace. +% If so, do nothing. If not, give it an appropriate dimension based on +% current baselineskip. +\ifdim\multitablelinespace=0pt +%% strut to put in table in case some entry doesn't have descenders, +%% to keep lines equally spaced +\let\multistrut = \strut +%% Test to see if parskip is larger than space between lines of +%% table. If not, do nothing. +%% If so, set to same dimension as multitablelinespace. +\else +\gdef\multistrut{\vrule height\multitablelinespace depth\dp0 +width0pt\relax} \fi +\ifdim\multitableparskip>\multitablelinespace +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi% +\ifdim\multitableparskip=0pt +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi} + + +\message{conditionals,} +% Prevent errors for section commands. +% Used in @ignore and in failing conditionals. +\def\ignoresections{% + \let\chapter=\relax + \let\unnumbered=\relax + \let\top=\relax + \let\unnumberedsec=\relax + \let\unnumberedsection=\relax + \let\unnumberedsubsec=\relax + \let\unnumberedsubsection=\relax + \let\unnumberedsubsubsec=\relax + \let\unnumberedsubsubsection=\relax + \let\section=\relax + \let\subsec=\relax + \let\subsubsec=\relax + \let\subsection=\relax + \let\subsubsection=\relax + \let\appendix=\relax + \let\appendixsec=\relax + \let\appendixsection=\relax + \let\appendixsubsec=\relax + \let\appendixsubsection=\relax + \let\appendixsubsubsec=\relax + \let\appendixsubsubsection=\relax + \let\contents=\relax + \let\smallbook=\relax + \let\titlepage=\relax +} + +% Used in nested conditionals, where we have to parse the Texinfo source +% and so want to turn off most commands, in case they are used +% incorrectly. +% +\def\ignoremorecommands{% + \let\defcodeindex = \relax + \let\defcv = \relax + \let\deffn = \relax + \let\deffnx = \relax + \let\defindex = \relax + \let\defivar = \relax + \let\defmac = \relax + \let\defmethod = \relax + \let\defop = \relax + \let\defopt = \relax + \let\defspec = \relax + \let\deftp = \relax + \let\deftypefn = \relax + \let\deftypefun = \relax + \let\deftypevar = \relax + \let\deftypevr = \relax + \let\defun = \relax + \let\defvar = \relax + \let\defvr = \relax + \let\ref = \relax + \let\xref = \relax + \let\printindex = \relax + \let\pxref = \relax + \let\settitle = \relax + \let\setchapternewpage = \relax + \let\setchapterstyle = \relax + \let\everyheading = \relax + \let\evenheading = \relax + \let\oddheading = \relax + \let\everyfooting = \relax + \let\evenfooting = \relax + \let\oddfooting = \relax + \let\headings = \relax + \let\include = \relax + \let\lowersections = \relax + \let\down = \relax + \let\raisesections = \relax + \let\up = \relax + \let\set = \relax + \let\clear = \relax + \let\item = \relax +} + +% Ignore @ignore ... @end ignore. +% +\def\ignore{\doignore{ignore}} + +% Ignore @ifinfo, @ifhtml, @ifnottex, @html, @menu, and @direntry text. +% +\def\ifinfo{\doignore{ifinfo}} +\def\ifhtml{\doignore{ifhtml}} +\def\ifnottex{\doignore{ifnottex}} +\def\html{\doignore{html}} +\def\menu{\doignore{menu}} +\def\direntry{\doignore{direntry}} + +% @dircategory CATEGORY -- specify a category of the dir file +% which this file should belong to. Ignore this in TeX. +\let\dircategory = \comment + +% Ignore text until a line `@end #1'. +% +\def\doignore#1{\begingroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define a command to swallow text until we reach `@end #1'. + % This @ is a catcode 12 token (that is the normal catcode of @ in + % this texinfo.tex file). We change the catcode of @ below to match. + \long\def\doignoretext##1@end #1{\enddoignore}% + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \catcode32 = 10 + % + % Ignore braces, too, so mismatched braces don't cause trouble. + \catcode`\{ = 9 + \catcode`\} = 9 + % + % We must not have @c interpreted as a control sequence. + \catcode`\@ = 12 + % + % Make the letter c a comment character so that the rest of the line + % will be ignored. This way, the document can have (for example) + % @c @end ifinfo + % and the @end ifinfo will be properly ignored. + % (We've just changed @ to catcode 12.) + \catcode`\c = 14 + % + % And now expand that command. + \doignoretext +} + +% What we do to finish off ignored text. +% +\def\enddoignore{\endgroup\ignorespaces}% + +\newif\ifwarnedobs\warnedobsfalse +\def\obstexwarn{% + \ifwarnedobs\relax\else + % We need to warn folks that they may have trouble with TeX 3.0. + % This uses \immediate\write16 rather than \message to get newlines. + \immediate\write16{} + \immediate\write16{WARNING: for users of Unix TeX 3.0!} + \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).} + \immediate\write16{If you are running another version of TeX, relax.} + \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.} + \immediate\write16{ Then upgrade your TeX installation if you can.} + \immediate\write16{ (See ftp://ftp.gnu.org/pub/gnu/TeX.README.)} + \immediate\write16{If you are stuck with version 3.0, run the} + \immediate\write16{ script ``tex3patch'' from the Texinfo distribution} + \immediate\write16{ to use a workaround.} + \immediate\write16{} + \global\warnedobstrue + \fi +} + +% **In TeX 3.0, setting text in \nullfont hangs tex. For a +% workaround (which requires the file ``dummy.tfm'' to be installed), +% uncomment the following line: +%%%%%\font\nullfont=dummy\let\obstexwarn=\relax + +% Ignore text, except that we keep track of conditional commands for +% purposes of nesting, up to an `@end #1' command. +% +\def\nestedignore#1{% + \obstexwarn + % We must actually expand the ignored text to look for the @end + % command, so that nested ignore constructs work. Thus, we put the + % text into a \vbox and then do nothing with the result. To minimize + % the change of memory overflow, we follow the approach outlined on + % page 401 of the TeXbook: make the current font be a dummy font. + % + \setbox0 = \vbox\bgroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define `@end #1' to end the box, which will in turn undefine the + % @end command again. + \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}% + % + % We are going to be parsing Texinfo commands. Most cause no + % trouble when they are used incorrectly, but some commands do + % complicated argument parsing or otherwise get confused, so we + % undefine them. + % + % We can't do anything about stray @-signs, unfortunately; + % they'll produce `undefined control sequence' errors. + \ignoremorecommands + % + % Set the current font to be \nullfont, a TeX primitive, and define + % all the font commands to also use \nullfont. We don't use + % dummy.tfm, as suggested in the TeXbook, because not all sites + % might have that installed. Therefore, math mode will still + % produce output, but that should be an extremely small amount of + % stuff compared to the main input. + % + \nullfont + \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont + \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont + \let\tensf = \nullfont + % Similarly for index fonts (mostly for their use in + % smallexample) + \let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont + \let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont + \let\indsf = \nullfont + % + % Don't complain when characters are missing from the fonts. + \tracinglostchars = 0 + % + % Don't bother to do space factor calculations. + \frenchspacing + % + % Don't report underfull hboxes. + \hbadness = 10000 + % + % Do minimal line-breaking. + \pretolerance = 10000 + % + % Do not execute instructions in @tex + \def\tex{\doignore{tex}}% + % Do not execute macro definitions. + % `c' is a comment character, so the word `macro' will get cut off. + \def\macro{\doignore{ma}}% +} + +% @set VAR sets the variable VAR to an empty value. +% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. +% +% Since we want to separate VAR from REST-OF-LINE (which might be +% empty), we can't just use \parsearg; we have to insert a space of our +% own to delimit the rest of the line, and then take it out again if we +% didn't need it. Make sure the catcode of space is correct to avoid +% losing inside @example, for instance. +% +\def\set{\begingroup\catcode` =10 + \catcode`\-=12 \catcode`\_=12 % Allow - and _ in VAR. + \parsearg\setxxx} +\def\setxxx#1{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + \def\temp{#2}% + \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty + \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted. + \fi + \endgroup +} +% Can't use \xdef to pre-expand #2 and save some time, since \temp or +% \next or other control sequences that we've defined might get us into +% an infinite loop. Consider `@set foo @cite{bar}'. +\def\setzzz#1#2 \endsetzzz{\expandafter\gdef\csname SET#1\endcsname{#2}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\def\clear{\parsearg\clearxxx} +\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax} + +% @value{foo} gets the text saved in variable foo. +{ + \catcode`\_ = \active + % + % We might end up with active _ or - characters in the argument if + % we're called from @code, as @code{@value{foo-bar_}}. So \let any + % such active characters to their normal equivalents. + \gdef\value{\begingroup + \catcode`\-=12 \catcode`\_=12 + \indexbreaks \let_\normalunderscore + \valuexxx} +} +\def\valuexxx#1{\expandablevalue{#1}\endgroup} + +% We have this subroutine so that we can handle at least some @value's +% properly in indexes (we \let\value to this in \indexdummies). Ones +% whose names contain - or _ still won't work, but we can't do anything +% about that. The command has to be fully expandable, since the result +% winds up in the index file. This means that if the variable's value +% contains other Texinfo commands, it's almost certain it will fail +% (although perhaps we could fix that with sufficient work to do a +% one-level expansion on the result, instead of complete). +% +\def\expandablevalue#1{% + \expandafter\ifx\csname SET#1\endcsname\relax + {[No value for ``#1'']}% + \else + \csname SET#1\endcsname + \fi +} + +% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined +% with @set. +% +\def\ifset{\parsearg\ifsetxxx} +\def\ifsetxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifsetfail + \else + \expandafter\ifsetsucceed + \fi +} +\def\ifsetsucceed{\conditionalsucceed{ifset}} +\def\ifsetfail{\nestedignore{ifset}} +\defineunmatchedend{ifset} + +% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been +% defined with @set, or has been undefined with @clear. +% +\def\ifclear{\parsearg\ifclearxxx} +\def\ifclearxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifclearsucceed + \else + \expandafter\ifclearfail + \fi +} +\def\ifclearsucceed{\conditionalsucceed{ifclear}} +\def\ifclearfail{\nestedignore{ifclear}} +\defineunmatchedend{ifclear} + +% @iftex, @ifnothtml, @ifnotinfo always succeed; we read the text +% following, through the first @end iftex (etc.). Make `@end iftex' +% (etc.) valid only after an @iftex. +% +\def\iftex{\conditionalsucceed{iftex}} +\def\ifnothtml{\conditionalsucceed{ifnothtml}} +\def\ifnotinfo{\conditionalsucceed{ifnotinfo}} +\defineunmatchedend{iftex} +\defineunmatchedend{ifnothtml} +\defineunmatchedend{ifnotinfo} + +% We can't just want to start a group at @iftex (for example) and end it +% at @end iftex, since then @set commands inside the conditional have no +% effect (they'd get reverted at the end of the group). So we must +% define \Eiftex to redefine itself to be its previous value. (We can't +% just define it to fail again with an ``unmatched end'' error, since +% the @ifset might be nested.) +% +\def\conditionalsucceed#1{% + \edef\temp{% + % Remember the current value of \E#1. + \let\nece{prevE#1} = \nece{E#1}% + % + % At the `@end #1', redefine \E#1 to be its previous value. + \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}% + }% + \temp +} + +% We need to expand lots of \csname's, but we don't want to expand the +% control sequences after we've constructed them. +% +\def\nece#1{\expandafter\noexpand\csname#1\endcsname} + +% @defininfoenclose. +\let\definfoenclose=\comment + + +\message{indexing,} +% Index generation facilities + +% Define \newwrite to be identical to plain tex's \newwrite +% except not \outer, so it can be used within \newindex. +{\catcode`\@=11 +\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}} + +% \newindex {foo} defines an index named foo. +% It automatically defines \fooindex such that +% \fooindex ...rest of line... puts an entry in the index foo. +% It also defines \fooindfile to be the number of the output channel for +% the file that accumulates this index. The file's extension is foo. +% The name of an index should be no more than 2 characters long +% for the sake of vms. +% +\def\newindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 % Open the file + \fi + \expandafter\xdef\csname#1index\endcsname{% % Define @#1index + \noexpand\doindex{#1}} +} + +% @defindex foo == \newindex{foo} + +\def\defindex{\parsearg\newindex} + +% Define @defcodeindex, like @defindex except put all entries in @code. + +\def\newcodeindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 + \fi + \expandafter\xdef\csname#1index\endcsname{% + \noexpand\docodeindex{#1}} +} + +\def\defcodeindex{\parsearg\newcodeindex} + +% @synindex foo bar makes index foo feed into index bar. +% Do this instead of @defindex foo if you don't want it as a separate index. +% The \closeout helps reduce unnecessary open files; the limit on the +% Acorn RISC OS is a mere 16 files. +\def\synindex#1 #2 {% + \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname + \expandafter\closeout\csname#1indfile\endcsname + \expandafter\let\csname#1indfile\endcsname=\synindexfoo + \expandafter\xdef\csname#1index\endcsname{% define \xxxindex + \noexpand\doindex{#2}}% +} + +% @syncodeindex foo bar similar, but put all entries made for index foo +% inside @code. +\def\syncodeindex#1 #2 {% + \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname + \expandafter\closeout\csname#1indfile\endcsname + \expandafter\let\csname#1indfile\endcsname=\synindexfoo + \expandafter\xdef\csname#1index\endcsname{% define \xxxindex + \noexpand\docodeindex{#2}}% +} + +% Define \doindex, the driver for all \fooindex macros. +% Argument #1 is generated by the calling \fooindex macro, +% and it is "foo", the name of the index. + +% \doindex just uses \parsearg; it calls \doind for the actual work. +% This is because \doind is more useful to call from other macros. + +% There is also \dosubind {index}{topic}{subtopic} +% which makes an entry in a two-level index such as the operation index. + +\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} +\def\singleindexer #1{\doind{\indexname}{#1}} + +% like the previous two, but they put @code around the argument. +\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} +\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} + +\def\indexdummies{% +\def\ { }% +% Take care of the plain tex accent commands. +\def\"{\realbackslash "}% +\def\`{\realbackslash `}% +\def\'{\realbackslash '}% +\def\^{\realbackslash ^}% +\def\~{\realbackslash ~}% +\def\={\realbackslash =}% +\def\b{\realbackslash b}% +\def\c{\realbackslash c}% +\def\d{\realbackslash d}% +\def\u{\realbackslash u}% +\def\v{\realbackslash v}% +\def\H{\realbackslash H}% +% Take care of the plain tex special European modified letters. +\def\oe{\realbackslash oe}% +\def\ae{\realbackslash ae}% +\def\aa{\realbackslash aa}% +\def\OE{\realbackslash OE}% +\def\AE{\realbackslash AE}% +\def\AA{\realbackslash AA}% +\def\o{\realbackslash o}% +\def\O{\realbackslash O}% +\def\l{\realbackslash l}% +\def\L{\realbackslash L}% +\def\ss{\realbackslash ss}% +% Take care of texinfo commands likely to appear in an index entry. +% (Must be a way to avoid doing expansion at all, and thus not have to +% laboriously list every single command here.) +\def\@{@}% will be @@ when we switch to @ as escape char. +% Need these in case \tex is in effect and \{ is a \delimiter again. +% But can't use \lbracecmd and \rbracecmd because texindex assumes +% braces and backslashes are used only as delimiters. +\let\{ = \mylbrace +\let\} = \myrbrace +\def\_{{\realbackslash _}}% +\def\w{\realbackslash w }% +\def\bf{\realbackslash bf }% +%\def\rm{\realbackslash rm }% +\def\sl{\realbackslash sl }% +\def\sf{\realbackslash sf}% +\def\tt{\realbackslash tt}% +\def\gtr{\realbackslash gtr}% +\def\less{\realbackslash less}% +\def\hat{\realbackslash hat}% +\def\TeX{\realbackslash TeX}% +\def\dots{\realbackslash dots }% +\def\result{\realbackslash result}% +\def\equiv{\realbackslash equiv}% +\def\expansion{\realbackslash expansion}% +\def\print{\realbackslash print}% +\def\error{\realbackslash error}% +\def\point{\realbackslash point}% +\def\copyright{\realbackslash copyright}% +\def\tclose##1{\realbackslash tclose {##1}}% +\def\code##1{\realbackslash code {##1}}% +\def\uref##1{\realbackslash uref {##1}}% +\def\url##1{\realbackslash url {##1}}% +\def\env##1{\realbackslash env {##1}}% +\def\command##1{\realbackslash command {##1}}% +\def\option##1{\realbackslash option {##1}}% +\def\dotless##1{\realbackslash dotless {##1}}% +\def\samp##1{\realbackslash samp {##1}}% +\def\,##1{\realbackslash ,{##1}}% +\def\t##1{\realbackslash t {##1}}% +\def\r##1{\realbackslash r {##1}}% +\def\i##1{\realbackslash i {##1}}% +\def\b##1{\realbackslash b {##1}}% +\def\sc##1{\realbackslash sc {##1}}% +\def\cite##1{\realbackslash cite {##1}}% +\def\key##1{\realbackslash key {##1}}% +\def\file##1{\realbackslash file {##1}}% +\def\var##1{\realbackslash var {##1}}% +\def\kbd##1{\realbackslash kbd {##1}}% +\def\dfn##1{\realbackslash dfn {##1}}% +\def\emph##1{\realbackslash emph {##1}}% +\def\acronym##1{\realbackslash acronym {##1}}% +% +% Handle some cases of @value -- where the variable name does not +% contain - or _, and the value does not contain any +% (non-fully-expandable) commands. +\let\value = \expandablevalue +% +\unsepspaces +% Turn off macro expansion +\turnoffmacros +} + +% If an index command is used in an @example environment, any spaces +% therein should become regular spaces in the raw index file, not the +% expansion of \tie (\\leavevmode \penalty \@M \ ). +{\obeyspaces + \gdef\unsepspaces{\obeyspaces\let =\space}} + +% \indexnofonts no-ops all font-change commands. +% This is used when outputting the strings to sort the index by. +\def\indexdummyfont#1{#1} +\def\indexdummytex{TeX} +\def\indexdummydots{...} + +\def\indexnofonts{% +% Just ignore accents. +\let\,=\indexdummyfont +\let\"=\indexdummyfont +\let\`=\indexdummyfont +\let\'=\indexdummyfont +\let\^=\indexdummyfont +\let\~=\indexdummyfont +\let\==\indexdummyfont +\let\b=\indexdummyfont +\let\c=\indexdummyfont +\let\d=\indexdummyfont +\let\u=\indexdummyfont +\let\v=\indexdummyfont +\let\H=\indexdummyfont +\let\dotless=\indexdummyfont +% Take care of the plain tex special European modified letters. +\def\oe{oe}% +\def\ae{ae}% +\def\aa{aa}% +\def\OE{OE}% +\def\AE{AE}% +\def\AA{AA}% +\def\o{o}% +\def\O{O}% +\def\l{l}% +\def\L{L}% +\def\ss{ss}% +\let\w=\indexdummyfont +\let\t=\indexdummyfont +\let\r=\indexdummyfont +\let\i=\indexdummyfont +\let\b=\indexdummyfont +\let\emph=\indexdummyfont +\let\strong=\indexdummyfont +\let\cite=\indexdummyfont +\let\sc=\indexdummyfont +%Don't no-op \tt, since it isn't a user-level command +% and is used in the definitions of the active chars like <, >, |... +%\let\tt=\indexdummyfont +\let\tclose=\indexdummyfont +\let\code=\indexdummyfont +\let\url=\indexdummyfont +\let\uref=\indexdummyfont +\let\env=\indexdummyfont +\let\command=\indexdummyfont +\let\option=\indexdummyfont +\let\file=\indexdummyfont +\let\samp=\indexdummyfont +\let\kbd=\indexdummyfont +\let\key=\indexdummyfont +\let\var=\indexdummyfont +\let\TeX=\indexdummytex +\let\dots=\indexdummydots +\def\@{@}% +} + +% To define \realbackslash, we must make \ not be an escape. +% We must first make another character (@) an escape +% so we do not become unable to do a definition. + +{\catcode`\@=0 \catcode`\\=\other + @gdef@realbackslash{\}} + +\let\indexbackslash=0 %overridden during \printindex. +\let\SETmarginindex=\relax % put index entries in margin (undocumented)? + +% For \ifx comparisons. +\def\emptymacro{\empty} + +% Most index entries go through here, but \dosubind is the general case. +% +\def\doind#1#2{\dosubind{#1}{#2}\empty} + +% Workhorse for all \fooindexes. +% #1 is name of index, #2 is stuff to put there, #3 is subentry -- +% \empty if called from \doind, as we usually are. The main exception +% is with defuns, which call us directly. +% +\def\dosubind#1#2#3{% + % Put the index entry in the margin if desired. + \ifx\SETmarginindex\relax\else + \insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}% + \fi + {% + \count255=\lastpenalty + {% + \indexdummies % Must do this here, since \bf, etc expand at this stage + \escapechar=`\\ + {% + \let\folio = 0% We will expand all macros now EXCEPT \folio. + \def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now + % so it will be output as is; and it will print as backslash. + % + \def\thirdarg{#3}% + % + % If third arg is present, precede it with space in sort key. + \ifx\thirdarg\emptymacro + \let\subentry = \empty + \else + \def\subentry{ #3}% + \fi + % + % First process the index entry with all font commands turned + % off to get the string to sort by. + {\indexnofonts \xdef\indexsorttmp{#2\subentry}}% + % + % Now the real index entry with the fonts. + \toks0 = {#2}% + % + % If third (subentry) arg is present, add it to the index + % string. And include a space. + \ifx\thirdarg\emptymacro \else + \toks0 = \expandafter{\the\toks0 \space #3}% + \fi + % + % Set up the complete index entry, with both the sort key + % and the original text, including any font commands. We write + % three arguments to \entry to the .?? file, texindex reduces to + % two when writing the .??s sorted result. + \edef\temp{% + \write\csname#1indfile\endcsname{% + \realbackslash entry{\indexsorttmp}{\folio}{\the\toks0}}% + }% + % + % If a skip is the last thing on the list now, preserve it + % by backing up by \lastskip, doing the \write, then inserting + % the skip again. Otherwise, the whatsit generated by the + % \write will make \lastskip zero. The result is that sequences + % like this: + % @end defun + % @tindex whatever + % @defun ... + % will have extra space inserted, because the \medbreak in the + % start of the @defun won't see the skip inserted by the @end of + % the previous defun. + % + % But don't do any of this if we're not in vertical mode. We + % don't want to do a \vskip and prematurely end a paragraph. + % + % Avoid page breaks due to these extra skips, too. + % + \iflinks + \ifvmode + \skip0 = \lastskip + \ifdim\lastskip = 0pt \else \nobreak\vskip-\lastskip \fi + \fi + % + \temp % do the write + % + % + \ifvmode \ifdim\skip0 = 0pt \else \nobreak\vskip\skip0 \fi \fi + \fi + }% + }% + \penalty\count255 + }% +} + +% The index entry written in the file actually looks like +% \entry {sortstring}{page}{topic} +% or +% \entry {sortstring}{page}{topic}{subtopic} +% The texindex program reads in these files and writes files +% containing these kinds of lines: +% \initial {c} +% before the first topic whose initial is c +% \entry {topic}{pagelist} +% for a topic that is used without subtopics +% \primary {topic} +% for the beginning of a topic that is used with subtopics +% \secondary {subtopic}{pagelist} +% for each subtopic. + +% Define the user-accessible indexing commands +% @findex, @vindex, @kindex, @cindex. + +\def\findex {\fnindex} +\def\kindex {\kyindex} +\def\cindex {\cpindex} +\def\vindex {\vrindex} +\def\tindex {\tpindex} +\def\pindex {\pgindex} + +\def\cindexsub {\begingroup\obeylines\cindexsub} +{\obeylines % +\gdef\cindexsub "#1" #2^^M{\endgroup % +\dosubind{cp}{#2}{#1}}} + +% Define the macros used in formatting output of the sorted index material. + +% @printindex causes a particular index (the ??s file) to get printed. +% It does not print any chapter heading (usually an @unnumbered). +% +\def\printindex{\parsearg\doprintindex} +\def\doprintindex#1{\begingroup + \dobreak \chapheadingskip{10000}% + % + \indexfonts \rm + \tolerance = 9500 + \indexbreaks + % + % See if the index file exists and is nonempty. + % Change catcode of @ here so that if the index file contains + % \initial {@} + % as its first line, TeX doesn't complain about mismatched braces + % (because it thinks @} is a control sequence). + \catcode`\@ = 11 + \openin 1 \jobname.#1s + \ifeof 1 + % \enddoublecolumns gets confused if there is no text in the index, + % and it loses the chapter title and the aux file entries for the + % index. The easiest way to prevent this problem is to make sure + % there is some text. + \putwordIndexNonexistent + \else + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \temp + \ifeof 1 + \putwordIndexIsEmpty + \else + % Index files are almost Texinfo source, but we use \ as the escape + % character. It would be better to use @, but that's too big a change + % to make right now. + \def\indexbackslash{\rawbackslashxx}% + \catcode`\\ = 0 + \escapechar = `\\ + \begindoublecolumns + \input \jobname.#1s + \enddoublecolumns + \fi + \fi + \closein 1 +\endgroup} + +% These macros are used by the sorted index file itself. +% Change them to control the appearance of the index. + +\def\initial#1{{% + % Some minor font changes for the special characters. + \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt + % + % Remove any glue we may have, we'll be inserting our own. + \removelastskip + % + % We like breaks before the index initials, so insert a bonus. + \penalty -300 + % + % Typeset the initial. Making this add up to a whole number of + % baselineskips increases the chance of the dots lining up from column + % to column. It still won't often be perfect, because of the stretch + % we need before each entry, but it's better. + % + % No shrink because it confuses \balancecolumns. + \vskip 1.67\baselineskip plus .5\baselineskip + \leftline{\secbf #1}% + \vskip .33\baselineskip plus .1\baselineskip + % + % Do our best not to break after the initial. + \nobreak +}} + +% This typesets a paragraph consisting of #1, dot leaders, and then #2 +% flush to the right margin. It is used for index and table of contents +% entries. The paragraph is indented by \leftskip. +% +\def\entry#1#2{\begingroup + % + % Start a new paragraph if necessary, so our assignments below can't + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % dots pretty far over on the line. Unfortunately, a large + % indentation looks wrong when the entry text itself is broken across + % lines. So we use a small indentation and put up with long leaders. + % + % \hangafter is reset to 1 (which is the value we want) at the start + % of each paragraph, so we need not do anything with that. + \hangindent = 2em + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % A bit of stretch before each entry for the benefit of balancing columns. + \vskip 0pt plus1pt + % + % Start a ``paragraph'' for the index entry so the line breaking + % parameters we've set above will have an effect. + \noindent + % + % Insert the text of the index entry. TeX will do line-breaking on it. + #1% + % The following is kludged to not output a line of dots in the index if + % there are no page numbers. The next person who breaks this will be + % cursed by a Unix daemon. + \def\tempa{{\rm }}% + \def\tempb{#2}% + \edef\tempc{\tempa}% + \edef\tempd{\tempb}% + \ifx\tempc\tempd\ \else% + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ #2% The page number ends the paragraph. + \fi% + \par +\endgroup} + +% Like \dotfill except takes at least 1 em. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill} + +\def\primary #1{\line{#1\hfil}} + +\newskip\secondaryindent \secondaryindent=0.5cm + +\def\secondary #1#2{ +{\parfillskip=0in \parskip=0in +\hangindent =1in \hangafter=1 +\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par +}} + +% Define two-column mode, which we use to typeset indexes. +% Adapted from the TeXbook, page 416, which is to say, +% the manmac.tex format used to print the TeXbook itself. +\catcode`\@=11 + +\newbox\partialpage +\newdimen\doublecolumnhsize + +\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns + % Grab any single-column material above us. + \output = {% + % + % Here is a possibility not foreseen in manmac: if we accumulate a + % whole lot of material, we might end up calling this \output + % routine twice in a row (see the doublecol-lose test, which is + % essentially a couple of indexes with @setchapternewpage off). In + % that case we just ship out what is in \partialpage with the normal + % output routine. Generally, \partialpage will be empty when this + % runs and this will be a no-op. See the indexspread.tex test case. + \ifvoid\partialpage \else + \onepageout{\pagecontents\partialpage}% + \fi + % + \global\setbox\partialpage = \vbox{% + % Unvbox the main output page. + \unvbox\PAGE + \kern-\topskip \kern\baselineskip + }% + }% + \eject % run that output routine to set \partialpage + % + % Use the double-column output routine for subsequent pages. + \output = {\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % format, but then we repeat the same computation. Repeating a couple + % of assignments once per index is clearly meaningless for the + % execution time, so we may as well do it in one place. + % + % First we halve the line length, less a little for the gutter between + % the columns. We compute the gutter based on the line length, so it + % changes automatically with the paper format. The magic constant + % below is chosen so that the gutter has the same value (well, +-<1pt) + % as it did when we hard-coded it. + % + % We put the result in a separate register, \doublecolumhsize, so we + % can restore it in \pagesofar, after \hsize itself has (potentially) + % been clobbered. + % + \doublecolumnhsize = \hsize + \advance\doublecolumnhsize by -.04154\hsize + \divide\doublecolumnhsize by 2 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \advance\vsize by -\ht\partialpage + \vsize = 2\vsize +} + +% The double-column output routine for all double-column pages except +% the last. +% +\def\doublecolumnout{% + \splittopskip=\topskip \splitmaxdepth=\maxdepth + % Get the available space for the double columns -- the normal + % (undoubled) page height minus any material left over from the + % previous page. + \dimen@ = \vsize + \divide\dimen@ by 2 + % + % box0 will be the left-hand column, box2 the right. + \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ + \onepageout\pagesofar + \unvbox255 + \penalty\outputpenalty +} +\def\pagesofar{% + % Re-output the contents of the output page -- any previous material, + % followed by the two boxes we just split, in box0 and box2. + \unvbox\partialpage + % + \hsize = \doublecolumnhsize + \wd0=\hsize \wd2=\hsize + \hbox to\pagewidth{\box0\hfil\box2}% +} +\def\enddoublecolumns{% + \output = {% + % Split the last of the double-column material. Leave it on the + % current page, no automatic page break. + \balancecolumns + % + % If we end up splitting too much material for the current page, + % though, there will be another page break right after this \output + % invocation ends. Having called \balancecolumns once, we do not + % want to call it again. Therefore, reset \output to its normal + % definition right away. (We hope \balancecolumns will never be + % called on to balance too much material, but if it is, this makes + % the output somewhat more palatable.) + \global\output = {\onepageout{\pagecontents\PAGE}}% + }% + \eject + \endgroup % started in \begindoublecolumns + % + % \pagegoal was set to the doubled \vsize above, since we restarted + % the current page. We're now back to normal single-column + % typesetting, so reset \pagegoal to the normal \vsize (after the + % \endgroup where \vsize got restored). + \pagegoal = \vsize +} +\def\balancecolumns{% + % Called at the end of the double column material. + \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. + \dimen@ = \ht0 + \advance\dimen@ by \topskip + \advance\dimen@ by-\baselineskip + \divide\dimen@ by 2 % target to split to + %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}% + \splittopskip = \topskip + % Loop until we get a decent breakpoint. + {% + \vbadness = 10000 + \loop + \global\setbox3 = \copy0 + \global\setbox1 = \vsplit3 to \dimen@ + \ifdim\ht3>\dimen@ + \global\advance\dimen@ by 1pt + \repeat + }% + %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}% + \setbox0=\vbox to\dimen@{\unvbox1}% + \setbox2=\vbox to\dimen@{\unvbox3}% + % + \pagesofar +} +\catcode`\@ = \other + + +\message{sectioning,} +% Define chapters, sections, etc. + +\newcount\chapno +\newcount\secno \secno=0 +\newcount\subsecno \subsecno=0 +\newcount\subsubsecno \subsubsecno=0 + +% This counter is funny since it counts through charcodes of letters A, B, ... +\newcount\appendixno \appendixno = `\@ +\def\appendixletter{\char\the\appendixno} + +% Each @chapter defines this as the name of the chapter. +% page headings and footings can use it. @section does likewise. +\def\thischapter{} +\def\thissection{} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raise/lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% Choose a numbered-heading macro +% #1 is heading level if unmodified by @raisesections or @lowersections +% #2 is text for heading +\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \chapterzzz{#2} +\or + \seczzz{#2} +\or + \numberedsubseczzz{#2} +\or + \numberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \chapterzzz{#2} + \else + \numberedsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses appendix heading levels +\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \appendixzzz{#2} +\or + \appendixsectionzzz{#2} +\or + \appendixsubseczzz{#2} +\or + \appendixsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \appendixzzz{#2} + \else + \appendixsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses numberless heading levels +\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \unnumberedzzz{#2} +\or + \unnumberedseczzz{#2} +\or + \unnumberedsubseczzz{#2} +\or + \unnumberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \unnumberedzzz{#2} + \else + \unnumberedsubsubseczzz{#2} + \fi +\fi +} + +% @chapter, @appendix, @unnumbered. +\def\thischaptername{No Chapter Title} +\outer\def\chapter{\parsearg\chapteryyy} +\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz +\def\chapterzzz #1{% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \chapno by 1 \message{\putwordChapter\space \the\chapno}% +\chapmacro {#1}{\the\chapno}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +% We don't substitute the actual chapter name into \thischapter +% because we don't want its macros evaluated now. +\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}% + {\the\chapno}}}% +\temp +\donoderef +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec +} + +\outer\def\appendix{\parsearg\appendixyyy} +\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz +\def\appendixzzz #1{% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \appendixno by 1 +\message{\putwordAppendix\space \appendixletter}% +\chapmacro {#1}{\putwordAppendix{} \appendixletter}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}% + {\putwordAppendix{} \appendixletter}}}% +\temp +\appendixnoderef +\global\let\section = \appendixsec +\global\let\subsection = \appendixsubsec +\global\let\subsubsection = \appendixsubsubsec +} + +% @centerchap is like @unnumbered, but the heading is centered. +\outer\def\centerchap{\parsearg\centerchapyyy} +\def\centerchapyyy #1{{\let\unnumbchapmacro=\centerchapmacro \unnumberedyyy{#1}}} + +% @top is like @unnumbered. +\outer\def\top{\parsearg\unnumberedyyy} + +\outer\def\unnumbered{\parsearg\unnumberedyyy} +\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz +\def\unnumberedzzz #1{% +\secno=0 \subsecno=0 \subsubsecno=0 +% +% This used to be simply \message{#1}, but TeX fully expands the +% argument to \message. Therefore, if #1 contained @-commands, TeX +% expanded them. For example, in `@unnumbered The @cite{Book}', TeX +% expanded @cite (which turns out to cause errors because \cite is meant +% to be executed, not expanded). +% +% Anyway, we don't want the fully-expanded definition of @cite to appear +% as a result of the \message, we just want `@cite' itself. We use +% \the to achieve this: TeX expands \the only once, +% simply yielding the contents of . (We also do this for +% the toc entries.) +\toks0 = {#1}\message{(\the\toks0)}% +% +\unnumbchapmacro {#1}% +\gdef\thischapter{#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbchapentry{\the\toks0}}}% +\temp +\unnumbnoderef +\global\let\section = \unnumberedsec +\global\let\subsection = \unnumberedsubsec +\global\let\subsubsection = \unnumberedsubsubsec +} + +% Sections. +\outer\def\numberedsec{\parsearg\secyyy} +\def\secyyy #1{\numhead1{#1}} % normally calls seczzz +\def\seczzz #1{% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}% + {\the\chapno}{\the\secno}}}% +\temp +\donoderef +\nobreak +} + +\outer\def\appendixsection{\parsearg\appendixsecyyy} +\outer\def\appendixsec{\parsearg\appendixsecyyy} +\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz +\def\appendixsectionzzz #1{% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}% + {\appendixletter}{\the\secno}}}% +\temp +\appendixnoderef +\nobreak +} + +\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy} +\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz +\def\unnumberedseczzz #1{% +\plainsecheading {#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsecentry{\the\toks0}}}% +\temp +\unnumbnoderef +\nobreak +} + +% Subsections. +\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy} +\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz +\def\numberedsubseczzz #1{% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}% + {\the\chapno}{\the\secno}{\the\subsecno}}}% +\temp +\donoderef +\nobreak +} + +\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy} +\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz +\def\appendixsubseczzz #1{% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}% + {\appendixletter}{\the\secno}{\the\subsecno}}}% +\temp +\appendixnoderef +\nobreak +} + +\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy} +\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz +\def\unnumberedsubseczzz #1{% +\plainsubsecheading {#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsecentry% + {\the\toks0}}}% +\temp +\unnumbnoderef +\nobreak +} + +% Subsubsections. +\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy} +\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz +\def\numberedsubsubseczzz #1{% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}% + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}% +\temp +\donoderef +\nobreak +} + +\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy} +\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz +\def\appendixsubsubseczzz #1{% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}% + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}% +\temp +\appendixnoderef +\nobreak +} + +\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy} +\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz +\def\unnumberedsubsubseczzz #1{% +\plainsubsubsecheading {#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsubsecentry% + {\the\toks0}}}% +\temp +\unnumbnoderef +\nobreak +} + +% These are variants which are not "outer", so they can appear in @ifinfo. +% Actually, they should now be obsolete; ordinary section commands should work. +\def\infotop{\parsearg\unnumberedzzz} +\def\infounnumbered{\parsearg\unnumberedzzz} +\def\infounnumberedsec{\parsearg\unnumberedseczzz} +\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz} +\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz} + +\def\infoappendix{\parsearg\appendixzzz} +\def\infoappendixsec{\parsearg\appendixseczzz} +\def\infoappendixsubsec{\parsearg\appendixsubseczzz} +\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz} + +\def\infochapter{\parsearg\chapterzzz} +\def\infosection{\parsearg\sectionzzz} +\def\infosubsection{\parsearg\subsectionzzz} +\def\infosubsubsection{\parsearg\subsubsectionzzz} + +% These macros control what the section commands do, according +% to what kind of chapter we are in (ordinary, appendix, or unnumbered). +% Define them by default for a numbered chapter. +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec + +% Define @majorheading, @heading and @subheading + +% NOTE on use of \vbox for chapter headings, section headings, and such: +% 1) We use \vbox rather than the earlier \line to permit +% overlong headings to fold. +% 2) \hyphenpenalty is set to 10000 because hyphenation in a +% heading is obnoxious; this forbids it. +% 3) Likewise, headings look best if no \parindent is used, and +% if justification is not attempted. Hence \raggedright. + + +\def\majorheading{\parsearg\majorheadingzzz} +\def\majorheadingzzz #1{% +{\advance\chapheadingskip by 10pt \chapbreak }% +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +\def\chapheading{\parsearg\chapheadingzzz} +\def\chapheadingzzz #1{\chapbreak % +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +% @heading, @subheading, @subsubheading. +\def\heading{\parsearg\plainsecheading} +\def\subheading{\parsearg\plainsubsecheading} +\def\subsubheading{\parsearg\plainsubsubsecheading} + +% These macros generate a chapter, section, etc. heading only +% (including whitespace, linebreaking, etc. around it), +% given all the information in convenient, parsed form. + +%%% Args are the skip and penalty (usually negative) +\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + +\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} + +%%% Define plain chapter starts, and page on/off switching for it +% Parameter controlling skip before chapter headings (if needed) + +\newskip\chapheadingskip + +\def\chapbreak{\dobreak \chapheadingskip {-4000}} +\def\chappager{\par\vfill\supereject} +\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} + +\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + +\def\CHAPPAGoff{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chapbreak +\global\let\pagealignmacro=\chappager} + +\def\CHAPPAGon{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chappager +\global\let\pagealignmacro=\chappager +\global\def\HEADINGSon{\HEADINGSsingle}} + +\def\CHAPPAGodd{ +\global\let\contentsalignmacro = \chapoddpage +\global\let\pchapsepmacro=\chapoddpage +\global\let\pagealignmacro=\chapoddpage +\global\def\HEADINGSon{\HEADINGSdouble}} + +\CHAPPAGon + +\def\CHAPFplain{ +\global\let\chapmacro=\chfplain +\global\let\unnumbchapmacro=\unnchfplain +\global\let\centerchapmacro=\centerchfplain} + +% Plain chapter opening. +% #1 is the text, #2 the chapter number or empty if unnumbered. +\def\chfplain#1#2{% + \pchapsepmacro + {% + \chapfonts \rm + \def\chapnum{#2}% + \setbox0 = \hbox{#2\ifx\chapnum\empty\else\enspace\fi}% + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 \centerparametersmaybe + \unhbox0 #1\par}% + }% + \nobreak\bigskip % no page break after a chapter title + \nobreak +} + +% Plain opening for unnumbered. +\def\unnchfplain#1{\chfplain{#1}{}} + +% @centerchap -- centered and unnumbered. +\let\centerparametersmaybe = \relax +\def\centerchfplain#1{{% + \def\centerparametersmaybe{% + \advance\rightskip by 3\rightskip + \leftskip = \rightskip + \parfillskip = 0pt + }% + \chfplain{#1}{}% +}} + +\CHAPFplain % The default + +\def\unnchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\nobreak +} + +\def\chfopen #1#2{\chapoddpage {\chapfonts +\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% +\par\penalty 5000 % +} + +\def\centerchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt + \hfill {\rm #1}\hfill}}\bigskip \par\nobreak +} + +\def\CHAPFopen{ +\global\let\chapmacro=\chfopen +\global\let\unnumbchapmacro=\unnchfopen +\global\let\centerchapmacro=\centerchfopen} + + +% Section titles. +\newskip\secheadingskip +\def\secheadingbreak{\dobreak \secheadingskip {-1000}} +\def\secheading#1#2#3{\sectionheading{sec}{#2.#3}{#1}} +\def\plainsecheading#1{\sectionheading{sec}{}{#1}} + +% Subsection titles. +\newskip \subsecheadingskip +\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}} +\def\subsecheading#1#2#3#4{\sectionheading{subsec}{#2.#3.#4}{#1}} +\def\plainsubsecheading#1{\sectionheading{subsec}{}{#1}} + +% Subsubsection titles. +\let\subsubsecheadingskip = \subsecheadingskip +\let\subsubsecheadingbreak = \subsecheadingbreak +\def\subsubsecheading#1#2#3#4#5{\sectionheading{subsubsec}{#2.#3.#4.#5}{#1}} +\def\plainsubsubsecheading#1{\sectionheading{subsubsec}{}{#1}} + + +% Print any size section title. +% +% #1 is the section type (sec/subsec/subsubsec), #2 is the section +% number (maybe empty), #3 the text. +\def\sectionheading#1#2#3{% + {% + \expandafter\advance\csname #1headingskip\endcsname by \parskip + \csname #1headingbreak\endcsname + }% + {% + % Switch to the right set of fonts. + \csname #1fonts\endcsname \rm + % + % Only insert the separating space if we have a section number. + \def\secnum{#2}% + \setbox0 = \hbox{#2\ifx\secnum\empty\else\enspace\fi}% + % + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 % zero if no section number + \unhbox0 #3}% + }% + \ifdim\parskip<10pt \nobreak\kern10pt\nobreak\kern-\parskip\fi \nobreak +} + + +\message{toc,} +\newwrite\tocfile + +% Write an entry to the toc file, opening it if necessary. +% Called from @chapter, etc. We supply {\folio} at the end of the +% argument, which will end up as the last argument to the \...entry macro. +% +% We open the .toc file here instead of at @setfilename or any other +% given time so that @contents can be put in the document anywhere. +% +\newif\iftocfileopened +\def\writetocentry#1{% + \iftocfileopened\else + \immediate\openout\tocfile = \jobname.toc + \global\tocfileopenedtrue + \fi + \iflinks \write\tocfile{#1{\folio}}\fi +} + +\newskip\contentsrightmargin \contentsrightmargin=1in +\newcount\savepageno +\newcount\lastnegativepageno \lastnegativepageno = -1 + +% Finish up the main text and prepare to read what we've written +% to \tocfile. +% +\def\startcontents#1{% + % If @setchapternewpage on, and @headings double, the contents should + % start on an odd page, unlike chapters. Thus, we maintain + % \contentsalignmacro in parallel with \pagealignmacro. + % From: Torbjorn Granlund + \contentsalignmacro + \immediate\closeout\tocfile + % + % Don't need to put `Contents' or `Short Contents' in the headline. + % It is abundantly clear what they are. + \unnumbchapmacro{#1}\def\thischapter{}% + \savepageno = \pageno + \begingroup % Set up to handle contents files properly. + \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11 + % We can't do this, because then an actual ^ in a section + % title fails, e.g., @chapter ^ -- exponentiation. --karl, 9jul97. + %\catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi + \raggedbottom % Worry more about breakpoints than the bottom. + \advance\hsize by -\contentsrightmargin % Don't use the full line length. + % + % Roman numerals for page numbers. + \ifnum \pageno>0 \pageno = \lastnegativepageno \fi +} + + +% Normal (long) toc. +\def\contents{% + \startcontents{\putwordTOC}% + \openin 1 \jobname.toc + \ifeof 1 \else + \closein 1 + \input \jobname.toc + \fi + \vfill \eject + \contentsalignmacro % in case @setchapternewpage odd is in effect + \endgroup + \lastnegativepageno = \pageno + \pageno = \savepageno +} + +% And just the chapters. +\def\summarycontents{% + \startcontents{\putwordShortTOC}% + % + \let\chapentry = \shortchapentry + \let\unnumbchapentry = \shortunnumberedentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl + \rm + \hyphenpenalty = 10000 + \advance\baselineskip by 1pt % Open it up a little. + \def\secentry ##1##2##3##4{} + \def\unnumbsecentry ##1##2{} + \def\subsecentry ##1##2##3##4##5{} + \def\unnumbsubsecentry ##1##2{} + \def\subsubsecentry ##1##2##3##4##5##6{} + \def\unnumbsubsubsecentry ##1##2{} + \openin 1 \jobname.toc + \ifeof 1 \else + \closein 1 + \input \jobname.toc + \fi + \vfill \eject + \contentsalignmacro % in case @setchapternewpage odd is in effect + \endgroup + \lastnegativepageno = \pageno + \pageno = \savepageno +} +\let\shortcontents = \summarycontents + +% These macros generate individual entries in the table of contents. +% The first argument is the chapter or section name. +% The last argument is the page number. +% The arguments in between are the chapter number, section number, ... + +% Chapter-level things, for both the long and short contents. +\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}} + +% See comments in \dochapentry re vbox and related settings +\def\shortchapentry#1#2#3{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}% +} + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter. +% We could simplify the code here by writing out an \appendixentry +% command in the toc file for appendices, instead of using \chapentry +% for both, but it doesn't seem worth it. +\setbox0 = \hbox{\shortcontrm \putwordAppendix } +\newdimen\shortappendixwidth \shortappendixwidth = \wd0 + +\def\shortchaplabel#1{% + % We typeset #1 in a box of constant width, regardless of the text of + % #1, so the chapter titles will come out aligned. + \setbox0 = \hbox{#1}% + \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi + % + % This space should be plenty, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in by \shortchapentry above.) + \advance\dimen0 by 1.1em + \hbox to \dimen0{#1\hfil}% +} + +\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}} +\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}} + +% Sections. +\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}} +\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}} + +% Subsections. +\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}} +\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}} + +% And subsubsections. +\def\subsubsecentry#1#2#3#4#5#6{% + \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}} +\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}} + +% This parameter controls the indentation of the various levels. +\newdimen\tocindent \tocindent = 3pc + +% Now for the actual typesetting. In all these, #1 is the text and #2 is the +% page number. +% +% If the toc has to be broken over pages, we want it to be at chapters +% if at all possible; hence the \penalty. +\def\dochapentry#1#2{% + \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno{#2}}% + \endgroup + \nobreak\vskip .25\baselineskip plus.1\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +% Final typesetting of a toc entry; we use the same \entry macro as for +% the index entries, but we want to suppress hyphenation here. (We +% can't do that in the \entry macro, since index entries might consist +% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.) +\def\tocentry#1#2{\begingroup + \vskip 0pt plus1pt % allow a little stretch for the sake of nice page breaks + % Do not use \turnoffactive in these arguments. Since the toc is + % typeset in cmr, so characters such as _ would come out wrong; we + % have to do the usual translation tricks. + \entry{#1}{#2}% +\endgroup} + +% Space between chapter (or whatever) number and the title. +\def\labelspace{\hskip1em \relax} + +\def\dopageno#1{{\rm #1}} +\def\doshortpageno#1{{\rm #1}} + +\def\chapentryfonts{\secfonts \rm} +\def\secentryfonts{\textfonts} +\let\subsecentryfonts = \textfonts +\let\subsubsecentryfonts = \textfonts + + +\message{environments,} + +% Since these characters are used in examples, it should be an even number of +% \tt widths. Each \tt character is 1en, so two makes it 1em. +% Furthermore, these definitions must come after we define our fonts. +\newbox\dblarrowbox \newbox\longdblarrowbox +\newbox\pushcharbox \newbox\bullbox +\newbox\equivbox \newbox\errorbox + +%{\tentt +%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil} +%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil} +%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil} +%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil} +% Adapted from the manmac format (p.420 of TeXbook) +%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex +% depth .1ex\hfil} +%} + +% @point{}, @result{}, @expansion{}, @print{}, @equiv{}. +\def\point{$\star$} +\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} +\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% Adapted from the TeXbook's \boxit. +{\tentt \global\dimen0 = 3em}% Width of the box. +\dimen2 = .55pt % Thickness of rules +% The text. (`r' is open on the right, `e' somewhat less so on the left.) +\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt} + +\global\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{ + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} + +% The @error{} command. +\def\error{\leavevmode\lower.7ex\copy\errorbox} + +% @tex ... @end tex escapes into raw Tex temporarily. +% One exception: @ is still an escape character, so that @end tex works. +% But \@ or @@ will get a plain tex @ character. + +\def\tex{\begingroup + \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 + \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 + \catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie + \catcode `\%=14 + \catcode 43=12 % plus + \catcode`\"=12 + \catcode`\==12 + \catcode`\|=12 + \catcode`\<=12 + \catcode`\>=12 + \escapechar=`\\ + % + \let\b=\ptexb + \let\bullet=\ptexbullet + \let\c=\ptexc + \let\,=\ptexcomma + \let\.=\ptexdot + \let\dots=\ptexdots + \let\equiv=\ptexequiv + \let\!=\ptexexclam + \let\i=\ptexi + \let\{=\ptexlbrace + \let\+=\tabalign + \let\}=\ptexrbrace + \let\*=\ptexstar + \let\t=\ptext + % + \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% + \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% + \def\@{@}% +\let\Etex=\endgroup} + +% Define @lisp ... @endlisp. +% @lisp does a \begingroup so it can rebind things, +% including the definition of @endlisp (which normally is erroneous). + +% Amount to narrow the margins by for @lisp. +\newskip\lispnarrowing \lispnarrowing=0.4in + +% This is the definition that ^^M gets inside @lisp, @example, and other +% such environments. \null is better than a space, since it doesn't +% have any width. +\def\lisppar{\null\endgraf} + +% Make each space character in the input produce a normal interword +% space in the output. Don't allow a line break at this space, as this +% is used only in environments like @example, where each line of input +% should produce a line of output anyway. +% +{\obeyspaces % +\gdef\sepspaces{\obeyspaces\let =\tie}} + +% Define \obeyedspace to be our active space, whatever it is. This is +% for use in \parsearg. +{\sepspaces% +\global\let\obeyedspace= } + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% Make spacing and below environment symmetrical. We use \parskip here +% to help in doing that, since in @example-like environments \parskip +% is reset to zero; thus the \afterenvbreak inserts no space -- but the +% start of the next paragraph will insert \parskip +% +\def\aboveenvbreak{{\advance\envskipamount by \parskip +\endgraf \ifdim\lastskip<\envskipamount +\removelastskip \penalty-50 \vskip\envskipamount \fi}} + +\let\afterenvbreak = \aboveenvbreak + +% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins. +\let\nonarrowing=\relax + +% @cartouche ... @end cartouche: draw rectangle w/rounded corners around +% environment contents. +\font\circle=lcircle10 +\newdimen\circthick +\newdimen\cartouter\newdimen\cartinner +\newskip\normbskip\newskip\normpskip\newskip\normlskip +\circthick=\fontdimen8\circle +% +\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth +\def\ctr{{\hskip 6pt\circle\char'010}} +\def\cbl{{\circle\char'012\hskip -6pt}} +\def\cbr{{\hskip 6pt\circle\char'011}} +\def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} +\def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} +% +\newskip\lskip\newskip\rskip + +\long\def\cartouche{% +\begingroup + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt %we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18.4pt % allow for 3pt kerns on either +% side, and for 6pt waste from +% each corner char, and rule thickness + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % Flag to tell @lisp, etc., not to narrow margin. + \let\nonarrowing=\comment + \vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \hsize=\cartinner + \kern3pt + \begingroup + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip +\def\Ecartouche{% + \endgroup + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup +\endgroup +}} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\def\nonfillstart{% + \aboveenvbreak + \inENV % This group ends at the end of the body + \hfuzz = 12pt % Don't be fussy + \sepspaces % Make spaces be word-separators rather than space tokens. + \singlespace + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + \parindent = 0pt + \emergencystretch = 0pt % don't try to avoid overfull boxes + % @cartouche defines \nonarrowing to inhibit narrowing + % at next level down. + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \let\exdent=\nofillexdent + \let\nonarrowing=\relax + \fi +} + +% Define the \E... control sequence only if we are inside the particular +% environment, so the error checking in \end will work. +% +% To end an @example-like environment, we first end the paragraph (via +% \afterenvbreak's vertical glue), and then the group. That way we keep +% the zero \parskip that the environments set -- \parskip glue will be +% inserted at the beginning of the next paragraph in the document, after +% the environment. +% +\def\nonfillfinish{\afterenvbreak\endgroup} + +% @lisp: indented, narrowed, typewriter font. +\def\lisp{\begingroup + \nonfillstart + \let\Elisp = \nonfillfinish + \tt + \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. + \gobble % eat return +} + +% @example: Same as @lisp. +\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp} + +% @small... is usually equivalent to the non-small (@smallbook +% redefines). We must call \example (or whatever) last in the +% definition, since it reads the return following the @example (or +% whatever) command. +% +% This actually allows (for example) @end display inside an +% @smalldisplay. Too bad, but makeinfo will catch the error anyway. +% +\def\smalldisplay{\begingroup\def\Esmalldisplay{\nonfillfinish\endgroup}\display} +\def\smallexample{\begingroup\def\Esmallexample{\nonfillfinish\endgroup}\lisp} +\def\smallformat{\begingroup\def\Esmallformat{\nonfillfinish\endgroup}\format} +\def\smalllisp{\begingroup\def\Esmalllisp{\nonfillfinish\endgroup}\lisp} + +% Real @smallexample and @smalllisp (when @smallbook): use smaller fonts. +% Originally contributed by Pavel@xerox. +\def\smalllispx{\begingroup + \def\Esmalllisp{\nonfillfinish\endgroup}% + \def\Esmallexample{\nonfillfinish\endgroup}% + \indexfonts + \lisp +} + +% @display: same as @lisp except keep current font. +% +\def\display{\begingroup + \nonfillstart + \let\Edisplay = \nonfillfinish + \gobble +} + +% @smalldisplay (when @smallbook): @display plus smaller fonts. +% +\def\smalldisplayx{\begingroup + \def\Esmalldisplay{\nonfillfinish\endgroup}% + \indexfonts \rm + \display +} + +% @format: same as @display except don't narrow margins. +% +\def\format{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eformat = \nonfillfinish + \gobble +} + +% @smallformat (when @smallbook): @format plus smaller fonts. +% +\def\smallformatx{\begingroup + \def\Esmallformat{\nonfillfinish\endgroup}% + \indexfonts \rm + \format +} + +% @flushleft (same as @format). +% +\def\flushleft{\begingroup \def\Eflushleft{\nonfillfinish\endgroup}\format} + +% @flushright. +% +\def\flushright{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushright = \nonfillfinish + \advance\leftskip by 0pt plus 1fill + \gobble +} + +% @quotation does normal linebreaking (hence we can't use \nonfillstart) +% and narrows the margins. +% +\def\quotation{% + \begingroup\inENV %This group ends at the end of the @quotation body + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \singlespace + \parindent=0pt + % We have retained a nonzero parskip for the environment, since we're + % doing normal filling. So to avoid extra space below the environment... + \def\Equotation{\parskip = 0pt \nonfillfinish}% + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \advance\rightskip by \lispnarrowing + \exdentamount = \lispnarrowing + \let\nonarrowing = \relax + \fi +} + + +\message{defuns,} +% Define formatter for defuns +% First, allow user to change definition object font (\df) internally +\def\setdeffont #1 {\csname DEF#1\endcsname} + +\newskip\defbodyindent \defbodyindent=.4in +\newskip\defargsindent \defargsindent=50pt +\newskip\deftypemargin \deftypemargin=12pt +\newskip\deflastargmargin \deflastargmargin=18pt + +\newcount\parencount +% define \functionparens, which makes ( and ) and & do special things. +% \functionparens affects the group it is contained in. +\def\activeparens{% +\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active +\catcode`\[=\active \catcode`\]=\active} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +{\activeparens % Now, smart parens don't turn on until &foo (see \amprm) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +\global\let(=\lparen \global\let)=\rparen +\global\let[=\lbrack \global\let]=\rbrack + +\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 } +\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} +% This is used to turn on special parens +% but make & act ordinary (given that it's active). +\gdef\boldbraxnoamp{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb\let&=\ampnr} + +% Definitions of (, ) and & used in args for functions. +% This is the definition of ( outside of all parentheses. +\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested + \global\advance\parencount by 1 +} +% +% This is the definition of ( when already inside a level of parens. +\gdef\opnested{\char`\(\global\advance\parencount by 1 } +% +\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0. + % also in that case restore the outer-level definition of (. + \ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi + \global\advance \parencount by -1 } +% If we encounter &foo, then turn on ()-hacking afterwards +\gdef\amprm#1 {{\rm\}\let(=\oprm \let)=\clrm\ } +% +\gdef\normalparens{\boldbrax\let&=\ampnr} +} % End of definition inside \activeparens +%% These parens (in \boldbrax) actually are a little bolder than the +%% contained text. This is especially needed for [ and ] +\def\opnr{{\sf\char`\(}\global\advance\parencount by 1 } +\def\clnr{{\sf\char`\)}\global\advance\parencount by -1 } +\def\ampnr{\&} +\def\lbrb{{\bf\char`\[}} +\def\rbrb{{\bf\char`\]}} + +% First, defname, which formats the header line itself. +% #1 should be the function name. +% #2 should be the type of definition, such as "Function". + +\def\defname #1#2{% +% Get the values of \leftskip and \rightskip as they were +% outside the @def... +\dimen2=\leftskip +\advance\dimen2 by -\defbodyindent +\noindent +\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}% +\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line +\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations +\parshape 2 0in \dimen0 \defargsindent \dimen1 +% Now output arg 2 ("Function" or some such) +% ending at \deftypemargin from the right margin, +% but stuck inside a box of width 0 so it does not interfere with linebreaking +{% Adjust \hsize to exclude the ambient margins, +% so that \rightline will obey them. +\advance \hsize by -\dimen2 +\rlap{\rightline{{\rm #2}\hskip -1.25pc }}}% +% Make all lines underfull and no complaints: +\tolerance=10000 \hbadness=10000 +\advance\leftskip by -\defbodyindent +\exdentamount=\defbodyindent +{\df #1}\enskip % Generate function name +} + +% Actually process the body of a definition +% #1 should be the terminating control sequence, such as \Edefun. +% #2 should be the "another name" control sequence, such as \defunx. +% #3 should be the control sequence that actually processes the header, +% such as \defunheader. + +\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\activeparens\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % 61 is `=' +\obeylines\activeparens\spacesplit#3} + +% #1 is the \E... control sequence to end the definition (which we define). +% #2 is the \...x control sequence for consecutive fns (which we define). +% #3 is the control sequence to call to resume processing. +% #4, delimited by the space, is the class name. +% +\def\defmethparsebody#1#2#3#4 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#4}}} + +% @deftypemethod has an extra argument that nothing else does. Sigh. +% #1 is the \E... control sequence to end the definition (which we define). +% #2 is the \...x control sequence for consecutive fns (which we define). +% #3 is the control sequence to call to resume processing. +% #4, delimited by the space, is the class name. +% #5 is the method's return type. +% +\def\deftypemethparsebody#1#2#3#4 #5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#4}{#5}}} + +\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#5}}} + +% These parsing functions are similar to the preceding ones +% except that they do not make parens into active characters. +% These are used for "variables" since they have no arguments. + +\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % +\obeylines\spacesplit#3} + +% This is used for \def{tp,vr}parsebody. It could probably be used for +% some of the others, too, with some judicious conditionals. +% +\def\parsebodycommon#1#2#3{% + \begingroup\inENV % + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines +} + +\def\defvrparsebody#1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{#3{#4}}% +} + +% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the +% type is just `struct', because we lose the braces in `{struct +% termios}' when \spacesplit reads its undelimited argument. Sigh. +% \let\deftpparsebody=\defvrparsebody +% +% So, to get around this, we put \empty in with the type name. That +% way, TeX won't find exactly `{...}' as an undelimited argument, and +% won't strip off the braces. +% +\def\deftpparsebody #1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{\parsetpheaderline{#3{#4}}}\empty +} + +% Fine, but then we have to eventually remove the \empty *and* the +% braces (if any). That's what this does. +% +\def\removeemptybraces\empty#1\relax{#1} + +% After \spacesplit has done its work, this is called -- #1 is the final +% thing to call, #2 the type name (which starts with \empty), and #3 +% (which might be empty) the arguments. +% +\def\parsetpheaderline#1#2#3{% + #1{\removeemptybraces#2\relax}{#3}% +}% + +\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\spacesplit{#3{#5}}} + +% Split up #2 at the first space token. +% call #1 with two arguments: +% the first is all of #2 before the space token, +% the second is all of #2 after that space token. +% If #2 contains no space token, all of it is passed as the first arg +% and the second is passed as empty. + +{\obeylines +\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}% +\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{% +\ifx\relax #3% +#1{#2}{}\else #1{#2}{#3#4}\fi}} + +% So much for the things common to all kinds of definitions. + +% Define @defun. + +% First, define the processing that is wanted for arguments of \defun +% Use this to expand the args and terminate the paragraph they make up + +\def\defunargs #1{\functionparens \sl +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +\hyphenchar\tensl=0 +#1% +\hyphenchar\tensl=45 +\ifnum\parencount=0 \else \errmessage{Unbalanced parentheses in @def}\fi% +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\nobreak\vskip -\parskip\nobreak +} + +\def\deftypefunargs #1{% +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +% Use \boldbraxnoamp, not \functionparens, so that & is not special. +\boldbraxnoamp +\tclose{#1}% avoid \code because of side effects on active chars +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\nobreak\vskip -\parskip\nobreak +} + +% Do complete processing of one @defun or @defunx line already parsed. + +% @deffn Command forward-char nchars + +\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader} + +\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}% +\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defun == @deffn Function + +\def\defun{\defparsebody\Edefun\defunx\defunheader} + +\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{\putwordDeffunc}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefun int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader} + +% #1 is the data type. #2 is the name and args. +\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax} +% #1 is the data type, #2 the name, #3 the args. +\def\deftypefunheaderx #1#2 #3\relax{% +\doind {fn}{\code{#2}}% Make entry in function index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{\putwordDeftypefun}% +\deftypefunargs {#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader} + +% \defheaderxcond#1\relax$$$ +% puts #1 in @code, followed by a space, but does nothing if #1 is null. +\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi} + +% #1 is the classification. #2 is the data type. #3 is the name and args. +\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax} +% #1 is the classification, #2 the data type, #3 the name, #4 the args. +\def\deftypefnheaderx #1#2#3 #4\relax{% +\doind {fn}{\code{#3}}% Make entry in function index +\begingroup +\normalparens % notably, turn off `&' magic, which prevents +% at least some C++ text from working +\defname {\defheaderxcond#2\relax$$$#3}{#1}% +\deftypefunargs {#4}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defmac == @deffn Macro + +\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader} + +\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{\putwordDefmac}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defspec == @deffn Special Form + +\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader} + +\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{\putwordDefspec}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% This definition is run if you use @defunx +% anywhere other than immediately after a @defun or @defunx. + +\def\deffnx #1 {\errmessage{@deffnx in invalid context}} +\def\defunx #1 {\errmessage{@defunx in invalid context}} +\def\defmacx #1 {\errmessage{@defmacx in invalid context}} +\def\defspecx #1 {\errmessage{@defspecx in invalid context}} +\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}} +\def\deftypemethodx #1 {\errmessage{@deftypemethodx in invalid context}} +\def\deftypefunx #1 {\errmessage{@deftypefunx in invalid context}} + +% @defmethod, and so on + +% @defop CATEGORY CLASS OPERATION ARG... + +\def\defop #1 {\def\defoptype{#1}% +\defopparsebody\Edefop\defopx\defopheader\defoptype} + +\def\defopheader #1#2#3{% +\dosubind {fn}{\code{#2}}{\putwordon\ #1}% Make entry in function index +\begingroup\defname {#2}{\defoptype{}\putwordon\ #1}% +\defunargs {#3}\endgroup % +} + +% @deftypemethod CLASS RETURN-TYPE METHOD ARG... +% +\def\deftypemethod{% + \deftypemethparsebody\Edeftypemethod\deftypemethodx\deftypemethodheader} +% +% #1 is the class name, #2 the data type, #3 the method name, #4 the args. +\def\deftypemethodheader#1#2#3#4{% + \dosubind{fn}{\code{#3}}{\putwordon\ \code{#1}}% entry in function index + \begingroup + \defname{\defheaderxcond#2\relax$$$#3}{\putwordMethodon\ \code{#1}}% + \deftypefunargs{#4}% + \endgroup +} + +% @defmethod == @defop Method +% +\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader} +% +% #1 is the class name, #2 the method name, #3 the args. +\def\defmethodheader#1#2#3{% + \dosubind{fn}{\code{#2}}{\putwordon\ \code{#1}}% entry in function index + \begingroup + \defname{#2}{\putwordMethodon\ \code{#1}}% + \defunargs{#3}% + \endgroup +} + +% @defcv {Class Option} foo-class foo-flag + +\def\defcv #1 {\def\defcvtype{#1}% +\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype} + +\def\defcvarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{\putwordof\ #1}% Make entry in var index +\begingroup\defname {#2}{\defcvtype\ \putwordof\ #1}% +\defvarargs {#3}\endgroup % +} + +% @defivar == @defcv {Instance Variable} + +\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader} + +\def\defivarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{\putwordof\ #1}% Make entry in var index +\begingroup\defname {#2}{\putwordDefivar\ \putwordof\ #1}% +\defvarargs {#3}\endgroup % +} + +% These definitions are run if you use @defmethodx, etc., +% anywhere other than immediately after a @defmethod, etc. + +\def\defopx #1 {\errmessage{@defopx in invalid context}} +\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}} +\def\defcvx #1 {\errmessage{@defcvx in invalid context}} +\def\defivarx #1 {\errmessage{@defivarx in invalid context}} + +% Now @defvar + +% First, define the processing that is wanted for arguments of @defvar. +% This is actually simple: just print them in roman. +% This must expand the args and terminate the paragraph they make up +\def\defvarargs #1{\normalparens #1% +\interlinepenalty=10000 +\endgraf\nobreak\vskip -\parskip\nobreak} + +% @defvr Counter foo-count + +\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader} + +\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}% +\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup} + +% @defvar == @defvr Variable + +\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader} + +\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{\putwordDefvar}% +\defvarargs {#2}\endgroup % +} + +% @defopt == @defvr {User Option} + +\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader} + +\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{\putwordDefopt}% +\defvarargs {#2}\endgroup % +} + +% @deftypevar int foobar + +\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader} + +% #1 is the data type. #2 is the name, perhaps followed by text that +% is actually part of the data type, which should not be put into the index. +\def\deftypevarheader #1#2{% +\dovarind#2 \relax% Make entry in variables index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{\putwordDeftypevar}% +\interlinepenalty=10000 +\endgraf\nobreak\vskip -\parskip\nobreak +\endgroup} +\def\dovarind#1 #2\relax{\doind{vr}{\code{#1}}} + +% @deftypevr {Global Flag} int enable + +\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader} + +\def\deftypevrheader #1#2#3{\dovarind#3 \relax% +\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1} +\interlinepenalty=10000 +\endgraf\nobreak\vskip -\parskip\nobreak +\endgroup} + +% This definition is run if you use @defvarx +% anywhere other than immediately after a @defvar or @defvarx. + +\def\defvrx #1 {\errmessage{@defvrx in invalid context}} +\def\defvarx #1 {\errmessage{@defvarx in invalid context}} +\def\defoptx #1 {\errmessage{@defoptx in invalid context}} +\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}} +\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}} + +% Now define @deftp +% Args are printed in bold, a slight difference from @defvar. + +\def\deftpargs #1{\bf \defvarargs{#1}} + +% @deftp Class window height width ... + +\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader} + +\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}% +\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup} + +% This definition is run if you use @deftpx, etc +% anywhere other than immediately after a @deftp, etc. + +\def\deftpx #1 {\errmessage{@deftpx in invalid context}} + + +\message{macros,} +% @macro. + +% To do this right we need a feature of e-TeX, \scantokens, +% which we arrange to emulate with a temporary file in ordinary TeX. +\ifx\eTeXversion\undefined + \newwrite\macscribble + \def\scanmacro#1{% + \begingroup \newlinechar`\^^M + % Undo catcode changes of \startcontents and \doprintindex + \catcode`\@=0 \catcode`\\=12 \escapechar=`\@ + % Append \endinput to make sure that TeX does not see the ending newline. + \toks0={#1\endinput}% + \immediate\openout\macscribble=\jobname.tmp + \immediate\write\macscribble{\the\toks0}% + \immediate\closeout\macscribble + \let\xeatspaces\eatspaces + \input \jobname.tmp + \endgroup +} +\else +\def\scanmacro#1{% +\begingroup \newlinechar`\^^M +% Undo catcode changes of \startcontents and \doprintindex +\catcode`\@=0 \catcode`\\=12 \escapechar=`\@ +\let\xeatspaces\eatspaces\scantokens{#1\endinput}\endgroup} +\fi + +\newcount\paramno % Count of parameters +\newtoks\macname % Macro name +\newif\ifrecursive % Is it recursive? +\def\macrolist{} % List of all defined macros in the form + % \do\macro1\do\macro2... + +% Utility routines. +% Thisdoes \let #1 = #2, except with \csnames. +\def\cslet#1#2{% +\expandafter\expandafter +\expandafter\let +\expandafter\expandafter +\csname#1\endcsname +\csname#2\endcsname} + +% Trim leading and trailing spaces off a string. +% Concepts from aro-bend problem 15 (see CTAN). +{\catcode`\@=11 +\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }} +\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@} +\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} +\def\unbrace#1{#1} +\unbrace{\gdef\trim@@@ #1 } #2@{#1} +} + +% Trim a single trailing ^^M off a string. +{\catcode`\^^M=12\catcode`\Q=3% +\gdef\eatcr #1{\eatcra #1Q^^MQ}% +\gdef\eatcra#1^^MQ{\eatcrb#1Q}% +\gdef\eatcrb#1Q#2Q{#1}% +} + +% Macro bodies are absorbed as an argument in a context where +% all characters are catcode 10, 11 or 12, except \ which is active +% (as in normal texinfo). It is necessary to change the definition of \. + +% It's necessary to have hard CRs when the macro is executed. This is +% done by making ^^M (\endlinechar) catcode 12 when reading the macro +% body, and then making it the \newlinechar in \scanmacro. + +\def\macrobodyctxt{% + \catcode`\~=12 + \catcode`\^=12 + \catcode`\_=12 + \catcode`\|=12 + \catcode`\<=12 + \catcode`\>=12 + \catcode`\+=12 + \catcode`\{=12 + \catcode`\}=12 + \catcode`\@=12 + \catcode`\^^M=12 + \usembodybackslash} + +\def\macroargctxt{% + \catcode`\~=12 + \catcode`\^=12 + \catcode`\_=12 + \catcode`\|=12 + \catcode`\<=12 + \catcode`\>=12 + \catcode`\+=12 + \catcode`\@=12 + \catcode`\\=12} + +% \mbodybackslash is the definition of \ in @macro bodies. +% It maps \foo\ => \csname macarg.foo\endcsname => #N +% where N is the macro parameter number. +% We define \csname macarg.\endcsname to be \realbackslash, so +% \\ in macro replacement text gets you a backslash. + +{\catcode`@=0 @catcode`@\=@active + @gdef@usembodybackslash{@let\=@mbodybackslash} + @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname} +} +\expandafter\def\csname macarg.\endcsname{\realbackslash} + +\def\macro{\recursivefalse\parsearg\macroxxx} +\def\rmacro{\recursivetrue\parsearg\macroxxx} + +\def\macroxxx#1{% + \getargs{#1}% now \macname is the macname and \argl the arglist + \ifx\argl\empty % no arguments + \paramno=0% + \else + \expandafter\parsemargdef \argl;% + \fi + \if1\csname ismacro.\the\macname\endcsname + \message{Warning: redefining \the\macname}% + \else + \expandafter\ifx\csname \the\macname\endcsname \relax + \else \errmessage{The name \the\macname\space is reserved}\fi + \global\cslet{macsave.\the\macname}{\the\macname}% + \global\expandafter\let\csname ismacro.\the\macname\endcsname=1% + % Add the macroname to \macrolist + \toks0 = \expandafter{\macrolist\do}% + \xdef\macrolist{\the\toks0 + \expandafter\noexpand\csname\the\macname\endcsname}% + \fi + \begingroup \macrobodyctxt + \ifrecursive \expandafter\parsermacbody + \else \expandafter\parsemacbody + \fi} + +\def\unmacro{\parsearg\unmacroxxx} +\def\unmacroxxx#1{% + \if1\csname ismacro.#1\endcsname + \global\cslet{#1}{macsave.#1}% + \global\expandafter\let \csname ismacro.#1\endcsname=0% + % Remove the macro name from \macrolist + \begingroup + \edef\tempa{\expandafter\noexpand\csname#1\endcsname}% + \def\do##1{% + \def\tempb{##1}% + \ifx\tempa\tempb + % remove this + \else + \toks0 = \expandafter{\newmacrolist\do}% + \edef\newmacrolist{\the\toks0\expandafter\noexpand\tempa}% + \fi}% + \def\newmacrolist{}% + % Execute macro list to define \newmacrolist + \macrolist + \global\let\macrolist\newmacrolist + \endgroup + \else + \errmessage{Macro #1 not defined}% + \fi +} + +% This makes use of the obscure feature that if the last token of a +% is #, then the preceding argument is delimited by +% an opening brace, and that opening brace is not consumed. +\def\getargs#1{\getargsxxx#1{}} +\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} +\def\getmacname #1 #2\relax{\macname={#1}} +\def\getmacargs#1{\def\argl{#1}} + +% Parse the optional {params} list. Set up \paramno and \paramlist +% so \defmacro knows what to do. Define \macarg.blah for each blah +% in the params list, to be ##N where N is the position in that list. +% That gets used by \mbodybackslash (above). + +% We need to get `macro parameter char #' into several definitions. +% The technique used is stolen from LaTeX: let \hash be something +% unexpandable, insert that wherever you need a #, and then redefine +% it to # just before using the token list produced. +% +% The same technique is used to protect \eatspaces till just before +% the macro is used. + +\def\parsemargdef#1;{\paramno=0\def\paramlist{}% + \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,} +\def\parsemargdefxxx#1,{% + \if#1;\let\next=\relax + \else \let\next=\parsemargdefxxx + \advance\paramno by 1% + \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname + {\xeatspaces{\hash\the\paramno}}% + \edef\paramlist{\paramlist\hash\the\paramno,}% + \fi\next} + +% These two commands read recursive and nonrecursive macro bodies. +% (They're different since rec and nonrec macros end differently.) + +\long\def\parsemacbody#1@end macro% +{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% +\long\def\parsermacbody#1@end rmacro% +{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% + +% This defines the macro itself. There are six cases: recursive and +% nonrecursive macros of zero, one, and many arguments. +% Much magic with \expandafter here. +% \xdef is used so that macro definitions will survive the file +% they're defined in; @include reads the file inside a group. +\def\defmacro{% + \let\hash=##% convert placeholders to macro parameter chars + \ifrecursive + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\scanmacro{\temp}}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup\noexpand\scanmacro{\temp}}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\csname\the\macname xx\endcsname}% + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{\egroup\noexpand\scanmacro{\temp}}% + \fi + \else + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \expandafter\noexpand\csname\the\macname xx\endcsname}% + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \fi + \fi} + +\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} + +% \braceorline decides whether the next nonwhitespace character is a +% {. If so it reads up to the closing }, if not, it reads the whole +% line. Whatever was read is then fed to the next control sequence +% as an argument (by \parsebrace or \parsearg) +\def\braceorline#1{\let\next=#1\futurelet\nchar\braceorlinexxx} +\def\braceorlinexxx{% + \ifx\nchar\bgroup\else + \expandafter\parsearg + \fi \next} + +% We mant to disable all macros during \shipout so that they are not +% expanded by \write. +\def\turnoffmacros{\begingroup \def\do##1{\let\noexpand##1=\relax}% + \edef\next{\macrolist}\expandafter\endgroup\next} + + +% @alias. +\def\alias#1=#2{\gdef#1{#2}} + + +\message{cross references,} +\newwrite\auxfile + +\newif\ifhavexrefs % True if xref values are known. +\newif\ifwarnedxrefs % True if we warned once that they aren't known. + +% @inforef is relatively simple. +\def\inforef #1{\inforefzzz #1,,,,**} +\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + +% @node's job is to define \lastnode. +\def\node{\ENVcheck\parsearg\nodezzz} +\def\nodezzz#1{\nodexxx [#1,]} +\def\nodexxx[#1,#2]{\gdef\lastnode{#1}} +\let\nwnode=\node +\let\lastnode=\relax + +% The sectioning commands (@chapter, etc.) call these. +\def\donoderef{% + \ifx\lastnode\relax\else + \expandafter\expandafter\expandafter\setref{\lastnode}% + {Ysectionnumberandtype}% + \global\let\lastnode=\relax + \fi +} +\def\unnumbnoderef{% + \ifx\lastnode\relax\else + \expandafter\expandafter\expandafter\setref{\lastnode}{Ynothing}% + \global\let\lastnode=\relax + \fi +} +\def\appendixnoderef{% + \ifx\lastnode\relax\else + \expandafter\expandafter\expandafter\setref{\lastnode}% + {Yappendixletterandtype}% + \global\let\lastnode=\relax + \fi +} + + +% @anchor{NAME} -- define xref target at arbitrary point. +% +\def\anchor#1{\setref{#1}{Ynothing}} + + +% \setref{NAME}{SNT} defines a cross-reference point NAME, namely +% NAME-title, NAME-pg, and NAME-SNT. Called from \foonoderef. We have +% to set \indexdummies so commands such as @code in a section title +% aren't expanded. It would be nicer not to expand the titles in the +% first place, but there's so many layers that that is hard to do. +% +\def\setref#1#2{{% + \indexdummies + \dosetq{#1-title}{Ytitle}% + \dosetq{#1-pg}{Ypagenumber}% + \dosetq{#1-snt}{#2}% +}} + +% @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is +% the node name, #2 the name of the Info cross-reference, #3 the printed +% node name, #4 the name of the Info file, #5 the name of the printed +% manual. All but the node name can be omitted. +% +\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} +\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} +\def\ref#1{\xrefX[#1,,,,,,,]} +\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup + \def\printedmanual{\ignorespaces #5}% + \def\printednodename{\ignorespaces #3}% + \setbox1=\hbox{\printedmanual}% + \setbox0=\hbox{\printednodename}% + \ifdim \wd0 = 0pt + % No printed node name was explicitly given. + \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax + % Use the node name inside the square brackets. + \def\printednodename{\ignorespaces #1}% + \else + % Use the actual chapter/section title appear inside + % the square brackets. Use the real section title if we have it. + \ifdim \wd1 > 0pt + % It is in another manual, so we don't have it. + \def\printednodename{\ignorespaces #1}% + \else + \ifhavexrefs + % We know the real title if we have the xref values. + \def\printednodename{\refx{#1-title}{}}% + \else + % Otherwise just copy the Info node name. + \def\printednodename{\ignorespaces #1}% + \fi% + \fi + \fi + \fi + % + % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not + % insert empty discretionaries after hyphens, which means that it will + % not find a line break at a hyphen in a node names. Since some manuals + % are best written with fairly long node names, containing hyphens, this + % is a loss. Therefore, we give the text of the node name again, so it + % is as if TeX is seeing it for the first time. + \ifdim \wd1 > 0pt + \putwordsection{} ``\printednodename'' in \cite{\printedmanual}% + \else + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\normalturnoffactive + % Only output a following space if the -snt ref is nonempty; for + % @unnumbered and @anchor, it won't be. + \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% + \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi + }% + % [mynode], + [\printednodename],\space + % page 3 + \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + \fi +\endgroup} + +% \dosetq is the interface for calls from other macros + +% Use \normalturnoffactive so that punctuation chars such as underscore +% and backslash work in node names. (\turnoffactive doesn't do \.) +\def\dosetq#1#2{% + {\let\folio=0 + \normalturnoffactive + \edef\next{\write\auxfile{\internalsetq{#1}{#2}}}% + \iflinks + \next + \fi + }% +} + +% \internalsetq {foo}{page} expands into +% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...} +% When the aux file is read, ' is the escape character + +\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}} + +% Things to be expanded by \internalsetq + +\def\Ypagenumber{\folio} + +\def\Ytitle{\thissection} + +\def\Ynothing{} + +\def\Ysectionnumberandtype{% +\ifnum\secno=0 \putwordChapter\xreftie\the\chapno % +\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\def\Yappendixletterandtype{% +\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}% +\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\gdef\xreftie{'tie} + +% Use TeX 3.0's \inputlineno to get the line number, for better error +% messages, but if we're using an old version of TeX, don't do anything. +% +\ifx\inputlineno\thisisundefined + \let\linenumber = \empty % Non-3.0. +\else + \def\linenumber{\the\inputlineno:\space} +\fi + +% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. +% If its value is nonempty, SUFFIX is output afterward. + +\def\refx#1#2{% + \expandafter\ifx\csname X#1\endcsname\relax + % If not defined, say something at least. + \angleleft un\-de\-fined\angleright + \iflinks + \ifhavexrefs + \message{\linenumber Undefined cross reference `#1'.}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \fi + \else + % It's defined, so just use it. + \csname X#1\endcsname + \fi + #2% Output the suffix in any case. +} + +% This is the macro invoked by entries in the aux file. +% +\def\xrdef#1{\begingroup + % Reenable \ as an escape while reading the second argument. + \catcode`\\ = 0 + \afterassignment\endgroup + \expandafter\gdef\csname X#1\endcsname +} + +% Read the last existing aux file, if any. No error if none exists. +\def\readauxfile{\begingroup + \catcode`\^^@=\other + \catcode`\^^A=\other + \catcode`\^^B=\other + \catcode`\^^C=\other + \catcode`\^^D=\other + \catcode`\^^E=\other + \catcode`\^^F=\other + \catcode`\^^G=\other + \catcode`\^^H=\other + \catcode`\^^K=\other + \catcode`\^^L=\other + \catcode`\^^N=\other + \catcode`\^^P=\other + \catcode`\^^Q=\other + \catcode`\^^R=\other + \catcode`\^^S=\other + \catcode`\^^T=\other + \catcode`\^^U=\other + \catcode`\^^V=\other + \catcode`\^^W=\other + \catcode`\^^X=\other + \catcode`\^^Z=\other + \catcode`\^^[=\other + \catcode`\^^\=\other + \catcode`\^^]=\other + \catcode`\^^^=\other + \catcode`\^^_=\other + \catcode`\@=\other + \catcode`\^=\other + % It was suggested to define this as 7, which would allow ^^e4 etc. + % in xref tags, i.e., node names. But since ^^e4 notation isn't + % supported in the main text, it doesn't seem desirable. Furthermore, + % that is not enough: for node names that actually contain a ^ + % character, we would end up writing a line like this: 'xrdef {'hat + % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first + % argument, and \hat is not an expandable control sequence. It could + % all be worked out, but why? Either we support ^^ or we don't. + % + % The other change necessary for this was to define \auxhat: + % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter + % and then to call \auxhat in \setq. + % + \catcode`\~=\other + \catcode`\[=\other + \catcode`\]=\other + \catcode`\"=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\$=\other + \catcode`\#=\other + \catcode`\&=\other + \catcode`+=\other % avoid \+ for paranoia even though we've turned it off + % Make the characters 128-255 be printing characters + {% + \count 1=128 + \def\loop{% + \catcode\count 1=\other + \advance\count 1 by 1 + \ifnum \count 1<256 \loop \fi + }% + }% + % The aux file uses ' as the escape (for now). + % Turn off \ as an escape so we do not lose on + % entries which were dumped with control sequences in their names. + % For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^ + % Reference to such entries still does not work the way one would wish, + % but at least they do not bomb out when the aux file is read in. + \catcode`\{=1 + \catcode`\}=2 + \catcode`\%=\other + \catcode`\'=0 + \catcode`\\=\other + % + \openin 1 \jobname.aux + \ifeof 1 \else + \closein 1 + \input \jobname.aux + \global\havexrefstrue + \global\warnedobstrue + \fi + % Open the new aux file. TeX will close it automatically at exit. + \openout\auxfile=\jobname.aux +\endgroup} + + +% Footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. (Generally, numeric constants should always be followed by a +% space to prevent strange expansion errors.) +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for info output only. +\let\footnotestyle=\comment + +\let\ptexfootnote=\footnote + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \footnotezzz +}% + +% Don't bother with the trickery in plain.tex to not require the +% footnote text as a parameter. Our footnotes don't need to be so general. +% +% Oh yes, they do; otherwise, @ifset and anything else that uses +% \parseargline fail inside footnotes because the tokens are fixed when +% the footnote is read. --karl, 16nov96. +% +\long\gdef\footnotezzz{\insert\footins\bgroup + % We want to typeset this text as a normal paragraph, even if the + % footnote reference occurs in (for example) a display environment. + % So reset some parameters. + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip + \rightskip\z@skip + \spaceskip\z@skip + \xspaceskip\z@skip + \parindent\defaultparindent + % + % Hang the footnote text off the number. + \hang + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + \futurelet\next\fo@t +} +\def\fo@t{\ifcat\bgroup\noexpand\next \let\next\f@@t + \else\let\next\f@t\fi \next} +\def\f@@t{\bgroup\aftergroup\@foot\let\next} +\def\f@t#1{#1\@foot} +\def\@foot{\strut\egroup} + +}%end \catcode `\@=11 + +% Set the baselineskip to #1, and the lineskip and strut size +% correspondingly. There is no deep meaning behind these magic numbers +% used as factors; they just match (closely enough) what Knuth defined. +% +\def\lineskipfactor{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} +% +\def\setleading#1{% + \normalbaselineskip = #1\relax + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% change spans more than two lines of output. To handle that, we would +% have adopt a much more difficult approach (putting marks into the main +% vertical list for the beginning and end of each change). +% +\def\|{% + % \vadjust can only be used in horizontal mode. + \leavevmode + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% For a final copy, take out the rectangles +% that mark overfull boxes (in case you have decided +% that the text looks ok even though it passes the margin). +% +\def\finalout{\overfullrule=0pt} + +% @image. We use the macros from epsf.tex to support this. +% If epsf.tex is not installed and @image is used, we complain. +% +% Check for and read epsf.tex up front. If we read it only at @image +% time, we might be inside a group, and then its definitions would get +% undone and the next image would fail. +\openin 1 = epsf.tex +\ifeof 1 \else + \closein 1 + % Do not bother showing banner with post-v2.7 epsf.tex (available in + % doc/epsf.tex until it shows up on ctan). + \def\epsfannounce{\toks0 = }% + \input epsf.tex +\fi +% +\newif\ifwarnednoepsf +\newhelp\noepsfhelp{epsf.tex must be installed for images to + work. It is also included in the Texinfo distribution, or you can get + it from ftp://tug.org/tex/epsf.tex.} +% +% Only complain once about lack of epsf.tex. +\def\image#1{% + \ifx\pdfoutput\undefined + \ifx\epsfbox\undefined + \ifwarnednoepsf \else + \errhelp = \noepsfhelp + \errmessage{epsf.tex not found, images will be ignored}% + \global\warnednoepsftrue + \fi + \else + \imagexxx #1,,,\finish + \fi + \else + \centerline{\pdfimage #1.pdf}% + \fi +} +% +% Arguments to @image: +% #1 is (mandatory) image filename; we tack on .eps extension. +% #2 is (optional) width, #3 is (optional) height. +% #4 is just the usual extra ignored arg for parsing this stuff. +\def\imagexxx#1,#2,#3,#4\finish{% + % \epsfbox itself resets \epsf?size at each figure. + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi + \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi + % If the image is by itself, center it. + \ifvmode + \nobreak\medskip + \nobreak + \centerline{\epsfbox{#1.eps}}% + \bigbreak + \else + % In the middle of a paragraph, no extra space. + \epsfbox{#1.eps}% + \fi +} + + +\message{localization,} + +% @documentlanguage is usually given very early, just after +% @setfilename. If done too late, it may not override everything +% properly. Single argument is the language abbreviation. +% It would be nice if we could set up a hyphenation file here. +% +\def\documentlanguage{\parsearg\dodocumentlanguage} +\def\dodocumentlanguage#1{% + \tex % read txi-??.tex file in plain TeX. + % Read the file if it exists. + \openin 1 txi-#1.tex + \ifeof1 + \errhelp = \nolanghelp + \errmessage{Cannot read language file txi-#1.tex}% + \let\temp = \relax + \else + \def\temp{\input txi-#1.tex }% + \fi + \temp + \endgroup +} +\newhelp\nolanghelp{The given language definition file cannot be found or +is empty. Maybe you need to install it? In the current directory +should work if nowhere else does.} + + +% @documentencoding should change something in TeX eventually, most +% likely, but for now just recognize it. +\let\documentencoding = \comment + + +% Page size parameters. +% +\newdimen\defaultparindent \defaultparindent = 15pt + +\chapheadingskip = 15pt plus 4pt minus 2pt +\secheadingskip = 12pt plus 3pt minus 2pt +\subsecheadingskip = 9pt plus 2pt minus 2pt + +% Prevent underfull vbox error messages. +\vbadness = 10000 + +% Don't be so finicky about underfull hboxes, either. +\hbadness = 2000 + +% Following George Bush, just get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% Use TeX 3.0's \emergencystretch to help line breaking, but if we're +% using an old version of TeX, don't do anything. We want the amount of +% stretch added to depend on the line length, hence the dependence on +% \hsize. We call this whenever the paper size is set. +% +\def\setemergencystretch{% + \ifx\emergencystretch\thisisundefined + % Allow us to assign to \emergencystretch anyway. + \def\emergencystretch{\dimen0}% + \else + \emergencystretch = \hsize + \divide\emergencystretch by 40 + \fi +} + +% Parameters in order: 1) textheight; 2) textwidth; 3) voffset; +% 4) hoffset; 5) binding offset; 6) topskip. Then whoever calls us can +% set \parskip and call \setleading for \baselineskip. +% +\def\internalpagesizes#1#2#3#4#5#6{% + \voffset = #3\relax + \topskip = #6\relax + \splittopskip = \topskip + % + \vsize = #1\relax + \advance\vsize by \topskip + \outervsize = \vsize + \advance\outervsize by 2\topandbottommargin + \pageheight = \vsize + % + \hsize = #2\relax + \outerhsize = \hsize + \advance\outerhsize by 0.5in + \pagewidth = \hsize + % + \normaloffset = #4\relax + \bindingoffset = #5\relax + % + \parindent = \defaultparindent + \setemergencystretch +} + +% @letterpaper (the default). +\def\letterpaper{{\globaldefs = 1 + \parskip = 3pt plus 2pt minus 1pt + \setleading{13.2pt}% + % + % If page is nothing but text, make it come out even. + \internalpagesizes{46\baselineskip}{6in}{\voffset}{.25in}{\bindingoffset}{36pt}% +}} + +% Use @smallbook to reset parameters for 7x9.5 (or so) format. +\def\smallbook{{\globaldefs = 1 + \parskip = 2pt plus 1pt + \setleading{12pt}% + % + \internalpagesizes{7.5in}{5.in}{\voffset}{.25in}{\bindingoffset}{16pt}% + % + \lispnarrowing = 0.3in + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \deftypemargin = 0pt + \defbodyindent = .5cm + % + \let\smalldisplay = \smalldisplayx + \let\smallexample = \smalllispx + \let\smallformat = \smallformatx + \let\smalllisp = \smalllispx +}} + +% Use @afourpaper to print on European A4 paper. +\def\afourpaper{{\globaldefs = 1 + \setleading{12pt}% + \parskip = 3pt plus 2pt minus 1pt + % + \internalpagesizes{53\baselineskip}{160mm}{\voffset}{4mm}{\bindingoffset}{44pt}% + % + \tolerance = 700 + \hfuzz = 1pt +}} + +% A specific text layout, 24x15cm overall, intended for A4 paper. Top margin +% 29mm, hence bottom margin 28mm, nominal side margin 3cm. +\def\afourlatex{{\globaldefs = 1 + \setleading{13.6pt}% + % + \afourpaper + \internalpagesizes{237mm}{150mm}{3.6mm}{3.6mm}{3mm}{7mm}% + % + \globaldefs = 0 +}} + +% Use @afourwide to print on European A4 paper in wide format. +\def\afourwide{% + \afourpaper + \internalpagesizes{9.5in}{6.5in}{\hoffset}{\normaloffset}{\bindingoffset}{7mm}% + % + \globaldefs = 0 +} + +% @pagesizes TEXTHEIGHT[,TEXTWIDTH] +% Perhaps we should allow setting the margins, \topskip, \parskip, +% and/or leading, also. Or perhaps we should compute them somehow. +% +\def\pagesizes{\parsearg\pagesizesxxx} +\def\pagesizesxxx#1{\pagesizesyyy #1,,\finish} +\def\pagesizesyyy#1,#2,#3\finish{{% + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi + \globaldefs = 1 + % + \parskip = 3pt plus 2pt minus 1pt + \setleading{13.2pt}% + % + \internalpagesizes{#1}{\hsize}{\voffset}{\normaloffset}{\bindingoffset}{44pt}% +}} + +% Set default to letter. +% +\letterpaper + +\message{and turning on texinfo input format.} + +% Define macros to output various characters with catcode for normal text. +\catcode`\"=\other +\catcode`\~=\other +\catcode`\^=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode`\+=\other +\def\normaldoublequote{"} +\def\normaltilde{~} +\def\normalcaret{^} +\def\normalunderscore{_} +\def\normalverticalbar{|} +\def\normalless{<} +\def\normalgreater{>} +\def\normalplus{+} + +% This macro is used to make a character print one way in ttfont +% where it can probably just be output, and another way in other fonts, +% where something hairier probably needs to be done. +% +% #1 is what to print if we are indeed using \tt; #2 is what to print +% otherwise. Since all the Computer Modern typewriter fonts have zero +% interword stretch (and shrink), and it is reasonable to expect all +% typewriter fonts to have this, we can check that font parameter. +% +\def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi} + +% Turn off all special characters except @ +% (and those which the user can use as if they were ordinary). +% Most of these we simply print from the \tt font, but for some, we can +% use math or other variants that look better in normal text. + +\catcode`\"=\active +\def\activedoublequote{{\tt\char34}} +\let"=\activedoublequote +\catcode`\~=\active +\def~{{\tt\char126}} +\chardef\hat=`\^ +\catcode`\^=\active +\def^{{\tt \hat}} + +\catcode`\_=\active +\def_{\ifusingtt\normalunderscore\_} +% Subroutine for the previous macro. +\def\_{\leavevmode \kern.06em \vbox{\hrule width.3em height.1ex}} + +\catcode`\|=\active +\def|{{\tt\char124}} +\chardef \less=`\< +\catcode`\<=\active +\def<{{\tt \less}} +\chardef \gtr=`\> +\catcode`\>=\active +\def>{{\tt \gtr}} +\catcode`\+=\active +\def+{{\tt \char 43}} +%\catcode 27=\active +%\def^^[{$\diamondsuit$} + +% Set up an active definition for =, but don't enable it most of the time. +{\catcode`\==\active +\global\def={{\tt \char 61}}} + +\catcode`+=\active +\catcode`\_=\active + +% If a .fmt file is being used, characters that might appear in a file +% name cannot be active until we have parsed the command line. +% So turn them off again, and have \everyjob (or @setfilename) turn them on. +% \otherifyactive is called near the end of this file. +\def\otherifyactive{\catcode`+=\other \catcode`\_=\other} + +\catcode`\@=0 + +% \rawbackslashxx output one backslash character in current font +\global\chardef\rawbackslashxx=`\\ +%{\catcode`\\=\other +%@gdef@rawbackslashxx{\}} + +% \rawbackslash redefines \ as input to do \rawbackslashxx. +{\catcode`\\=\active +@gdef@rawbackslash{@let\=@rawbackslashxx }} + +% \normalbackslash outputs one backslash in fixed width font. +\def\normalbackslash{{\tt\rawbackslashxx}} + +% Say @foo, not \foo, in error messages. +\escapechar=`\@ + +% \catcode 17=0 % Define control-q +\catcode`\\=\active + +% Used sometimes to turn off (effectively) the active characters +% even after parsing them. +@def@turnoffactive{@let"=@normaldoublequote +@let\=@realbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +@def@normalturnoffactive{@let"=@normaldoublequote +@let\=@normalbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +% Make _ and + \other characters, temporarily. +% This is canceled by @fixbackslash. +@otherifyactive + +% If a .fmt file is being used, we don't want the `\input texinfo' to show up. +% That is what \eatinput is for; after that, the `\' should revert to printing +% a backslash. +% +@gdef@eatinput input texinfo{@fixbackslash} +@global@let\ = @eatinput + +% On the other hand, perhaps the file did not have a `\input texinfo'. Then +% the first `\{ in the file would cause an error. This macro tries to fix +% that, assuming it is called before the first `\' could plausibly occur. +% Also back turn on active characters that might appear in the input +% file name, in case not using a pre-dumped format. +% +@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi + @catcode`+=@active @catcode`@_=@active} + +% These look ok in all fonts, so just make them not special. The @rm below +% makes sure that the current font starts out as the newly loaded cmr10 +@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other + +@textfonts +@rm + +@c Local variables: +@c eval: (add-hook 'write-file-hooks 'time-stamp) +@c page-delimiter: "^\\\\message" +@c time-stamp-start: "def\\\\texinfoversion{" +@c time-stamp-format: "%:y-%02m-%02d.%H" +@c time-stamp-end: "}" +@c End: diff --git a/doc/vtysh.1 b/doc/vtysh.1 new file mode 100644 index 00000000..302e0166 --- /dev/null +++ b/doc/vtysh.1 @@ -0,0 +1,68 @@ +.TH VTYSH 1 "July 2000" "Zebra Beast - VTY shell" "Version 0.88" + +.SH NAME +vtysh \- a integrated shell for Zebra routing software + +.SH SYNOPSIS +.B vtysh +[ +.B \-e command +] + +.SH DESCBGPTION +.B vtysh +is a integrated shell for +.B Zebra +routing engine. + + +.SH OPTIONS + +.TP +\fB\-e +Specify command to be executed under batch mode. + + +.SH COMMANDS + +\fB Almost Zebra commands. + +\fB ping +\fB traceroute +\fB telnnet + +\fB start-shell +\fB start-shell bash +\fB start-shell zsh + + +.SH FILES + +.TP +.BI /usr/local/etc/Zebra.conf +The default location of the +.B vtysh +config file. + + +.SH WARNING +This man page is intended as a quick reference for command line +options, and for config file commands. The definitive document is the +Info file \fBZebra\fR. + + +.SH "SEE ALSO" +References to other related man pages: + +bgpd(8), ripd(8), ripngd(8), ospfd(8), ospf6d(8), zebra(8) + + +.SH BUGS +.B vtysh +eats bugs for breakfast. If you have food for the maintainers try +.BI + + +.SH AUTHOR[S] +See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors. + diff --git a/doc/vtysh.texi b/doc/vtysh.texi new file mode 100644 index 00000000..72490dba --- /dev/null +++ b/doc/vtysh.texi @@ -0,0 +1,27 @@ +@node VTY shell +@comment node-name, next, previous, up +@chapter VTY shell + +@command{vtysh} is integrated shell of Zebra software. + +To use vtysh please specify ---enable-vtysh to configure script. To use +PAM for authentication use ---with-libpam option to configure script. + +vtysh only searches @value{INSTALL_PREFIX_ETC} path for vtysh.conf which +is the vtysh configuration file. Vtysh does not search current +directory for configuration file because the file includes user +authentication settings. + +Currently, vtysh.conf has only one command. + +@example +! +username foo nopassword +! +@end example + +With this set, user foo does not need password authentication for user vtysh. +With PAM vtysh uses PAM authentication mechanism. + +If vtysh is compiled without PAM authentication, every user can use vtysh +without authentication. diff --git a/doc/zebra.8 b/doc/zebra.8 new file mode 100644 index 00000000..190f4a62 --- /dev/null +++ b/doc/zebra.8 @@ -0,0 +1,146 @@ +.TH ZEBRA 8 "July 2000" "Zebra" "Version 0.88" + +.SH NAME +zebra \- a routing manager for use with associated components + +.SH SYNOPSIS +.B zebra +[ +.B \-bdhklrv +] +[ +.B \-f config-file +] +[ +.B \-i pid-file +] +[ +.B \-P port-number +] + +.SH DESCRIPTION +.B zebra +is a routing manager that implements the +.B zebra +route engine. +.B zebra +supports RIPv1, RIPv2, RIPng, OSPF, OSPF6, BGP4+, and BGP4-. + + +.SH OPTIONS + +.TP +\fB\-b\fR, \fB\-\-batch\fR +Runs in batch mode, \fBzebra\fR parses its config and exits. + +.TP +\fB\-d\fR, \fB\-\-daemon\fR +Runs in daemon mode, forking and exiting from tty. + +.TP +\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR +Specifies the config file to use for startup. If not specified this option will likely default to \fB\fI/usr/local/etc/zebra.conf\fR. + +.TP +\fB\-h\fR, \fB\-\-help\fR +A brief message. + +.TP +\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR +When zebra starts its process idenifier is written to +\fB\fIpid-file\fR. The init system uses the recorded PID to stop or +restart zebra. The likely default is \fB\fI/var/run/zebra.pid\fR. + +.TP +\fB\-k\fR, \fB\-\-keep_kernel\fR +On startup, don't delete self inserted routes. + +.TP +\fB\-l\fR, \fB\-\-log_mode\fR +Turn verbose logging on. + +.TP +\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR +Specify the port that the zebra VTY will listen on. This defaults to +2602, as specified in \fB\fI/etc/services\fR. + +.TP +\fB\-r\fR, \fB\-\-retain\fR +When the program terminates, retain routes added by \fBzebra\fR. + +.TP +\fB\-v\fR, \fB\-\-version\fR +Print the version and exit. + + +.SH COMMANDS + +\fB table [TABLENO] \fR -- for use with multi-table kernels + +\fB ip route [NETWORK] [GATEWAY] \fR +\fB ipv6 route [NETWORK] [GATEWAY] \fR + +\fB show ip route \fR +\fB show ipv6 route \fR +\fB show interface \fR +\fB show ipforward \fR +\fB show ipv6forward \fR + +.TP +\fB interface [IFNAME] \fR +\fB shutdown \fR +\fB no shutdown \fR +\fB ip address [IP-ADDRESS] \fR +\fB description [DESCRIPTION] \fR +\fB multicast \fR +\fB no multicast \fR + + +.SH FILES + +.TP +.BI /usr/local/sbin/zebra +The default location of the +.B zebra +binary. + +.TP +.BI /usr/local/etc/zebra.conf +The default location of the +.B zebra +config file. + +.TP +.BI $(PWD)/zebra.log +If the +.B zebra +process is config'd to output logs to a file, then you will find this +file in the directory where you started \fBzebra\fR. + + +.SH WARNING +This man page is intended as a quick reference for command line options, and for config file commands. The definitive document is the Info file \fBzebra\fR. + + +.SH DIAGNOSTICS +The zebra process may log to standard output, to a VTY, to a log file, or through syslog to the system logs. +.B zebra +supports many debugging options, see the Info file, or the source for details. + + +.SH "SEE ALSO" +References to other related man pages: + +ripngd(8), ospfd(8), ospf6d(8), bgpd(8), zebra(8), vtysh(1) + + + +.SH BUGS +.B zebra +eats bugs for breakfast. If you have food for the maintainers try +.BI + + +.SH AUTHOR[S] +See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors. + diff --git a/doc/zebra.info b/doc/zebra.info new file mode 100644 index 00000000..ca805e12 --- /dev/null +++ b/doc/zebra.info @@ -0,0 +1,170 @@ +This is zebra.info, produced by makeinfo version 4.2 from zebra.texi. + +INFO-DIR-SECTION Routing Software: +START-INFO-DIR-ENTRY +* Zebra: (zebra). The GNU Zebra routing software +END-INFO-DIR-ENTRY + + This file documents the GNU Zebra software which manages common +TCP/IP routing protocols. + + This is Edition 0.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. + + +Indirect: +zebra.info-1: 1121 +zebra.info-2: 48818 +zebra.info-3: 95581 +zebra.info-4: 143934 + +Tag Table: +(Indirect) +Node: Top1121 +Node: Overview1646 +Node: About Zebra3063 +Node: System Architecture5332 +Node: Supported Platforms8330 +Node: Supported RFC9317 +Node: How to get Zebra11119 +Node: Mailing List11824 +Node: Bug Reports12491 +Node: Installation13336 +Node: Configure the Software13767 +Ref: Configure the Software-Footnote-116134 +Node: Build the Software17776 +Node: Install the Software18318 +Node: Basic commands19689 +Node: Config Commands20402 +Node: Basic Config Commands21284 +Node: Sample Config File23682 +Node: Common Invocation Options24442 +Node: Virtual Terminal Interfaces25564 +Node: VTY Overview26069 +Node: VTY Modes27353 +Node: VTY View Mode27793 +Node: VTY Enable Mode28047 +Node: VTY Other Modes28311 +Node: VTY CLI Commands28473 +Node: CLI Movement Commands28923 +Node: CLI Editing Commands29456 +Node: CLI Advanced Commands30029 +Node: Zebra30780 +Node: Invoking zebra31287 +Node: Interface Commands31873 +Node: Static Route Commands32703 +Node: zebra Terminal Mode Commands34790 +Node: RIP35751 +Node: Starting and Stopping ripd36686 +Node: RIP netmask38107 +Node: RIP Configuration39229 +Node: How to Announce RIP route43124 +Node: Filtering RIP Routes45653 +Node: RIP Metric Manipulation47112 +Node: RIP distance48015 +Node: RIP route-map48818 +Node: RIP Authentication51320 +Node: RIP Timers52410 +Node: Show RIP Information53685 +Node: RIP Debug Commands55048 +Node: RIPng56032 +Node: Invoking ripngd56350 +Node: ripngd Configuration56607 +Node: ripngd Terminal Mode Commands57346 +Node: ripngd Filtering Commands57696 +Node: OSPFv258195 +Node: Configuring ospfd58752 +Node: OSPF router59229 +Node: OSPF area60960 +Node: OSPF interface63174 +Node: Redistribute routes to OSPF65956 +Node: Showing OSPF information68072 +Node: Debugging OSPF69292 +Node: OSPFv370303 +Node: OSPF6 router70621 +Node: OSPF6 area70978 +Node: OSPF6 interface71150 +Node: Redistribute routes to OSPF672002 +Node: Showing OSPF6 information72306 +Node: BGP73111 +Node: Starting BGP73972 +Node: BGP router74557 +Node: BGP distance75793 +Node: BGP decision process76234 +Node: BGP network76490 +Node: BGP route76671 +Node: Route Aggregation77232 +Node: Redistribute to BGP77784 +Node: BGP Peer78293 +Node: Defining Peer78471 +Node: BGP Peer commands79087 +Node: Peer filtering81458 +Node: BGP Peer Group81949 +Node: BGP Address Family82251 +Node: Autonomous System82396 +Node: AS Path Regular Expression83227 +Node: Display BGP Routes by AS Path84490 +Node: AS Path Access List84919 +Node: Using AS Path in Route Map85373 +Node: Private AS Numbers85639 +Node: BGP Communities Attribute85784 +Node: BGP Community Lists88245 +Node: Numbered BGP Community Lists90926 +Node: BGP Community in Route Map92500 +Node: Display BGP Routes by Community94427 +Node: Using BGP Communities Attribute95581 +Node: BGP Extended Communities Attribute99139 +Node: BGP Extended Community Lists100905 +Node: BGP Extended Communities in Route Map102806 +Node: Displaying BGP routes103249 +Node: Show IP BGP103475 +Node: More Show IP BGP104197 +Node: Capability Negotiation105317 +Node: Route Reflector108605 +Node: Route Server108870 +Node: Multiple instance109928 +Node: BGP instance and view111741 +Node: Routing policy113107 +Node: Viewing the view113863 +Node: How to set up a 6-Bone connection114135 +Node: Dump BGP packets and table115507 +Node: VTY shell116037 +Node: Filtering116877 +Node: IP Access List117225 +Node: IP Prefix List117616 +Node: ip prefix-list description120785 +Node: ip prefix-list sequential number control121318 +Node: Showing ip prefix-list121843 +Node: Clear counter of ip prefix-list122926 +Node: Route Map123347 +Node: Route Map Command123848 +Node: Route Map Match Command124051 +Node: Route Map Set Command124659 +Node: IPv6 Support125517 +Node: Router Advertisement126082 +Node: Kernel Interface126413 +Node: SNMP Support128363 +Node: How to get ucd-snmp128992 +Node: SMUX configuration130040 +Node: Zebra Protocol130473 +Node: Packet Binary Dump Format132367 +Node: Command Index143934 +Node: VTY Key Index173652 + +End Tag Table diff --git a/doc/zebra.texi b/doc/zebra.texi new file mode 100644 index 00000000..d09ff4d6 --- /dev/null +++ b/doc/zebra.texi @@ -0,0 +1,150 @@ +\input texinfo @c -*- texinfo -*- +@c %**start of header +@setchapternewpage odd +@settitle GNU Zebra +@setfilename zebra.info +@defcodeindex op +@synindex pg cp +@c %**end of header + +@c Set variables +@set EDITION 0.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 index 00000000..bdcccd62 --- /dev/null +++ b/guile/.cvsignore @@ -0,0 +1,3 @@ +Makefile +*.o +zebra-guile diff --git a/guile/ChangeLog b/guile/ChangeLog new file mode 100644 index 00000000..751e952c --- /dev/null +++ b/guile/ChangeLog @@ -0,0 +1,26 @@ +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 is released. + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 is released. + +1999-04-18 Kunihiro Ishiguro + + * 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 + + * guile/Makefile.am (INCLUDES): Use @GUILE_CFLAGS@ and + @GUILE_LDFLAGS@ + +1999-04-14 Kunihiro Ishiguro + + * zebra-guile work restarted. diff --git a/guile/Makefile.am b/guile/Makefile.am new file mode 100644 index 00000000..58b0547f --- /dev/null +++ b/guile/Makefile.am @@ -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 index 00000000..2773029b --- /dev/null +++ b/guile/Makefile.in @@ -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 index 00000000..8e18fae5 --- /dev/null +++ b/guile/README @@ -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 index 00000000..fbd01ba0 --- /dev/null +++ b/guile/guile-bgp.c @@ -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 +#include + +#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 ("#', 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 index 00000000..f618dbc5 --- /dev/null +++ b/guile/zebra-guile.c @@ -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 +#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 index 00000000..f43e287d --- /dev/null +++ b/guile/zebra-guile.h @@ -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 index 00000000..9a6ef814 --- /dev/null +++ b/guile/zebra-support.c @@ -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 index 00000000..282522db --- /dev/null +++ b/init/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/init/ChangeLog b/init/ChangeLog new file mode 100644 index 00000000..90d3d248 --- /dev/null +++ b/init/ChangeLog @@ -0,0 +1,39 @@ +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-02-01 Kunihiro Ishiguro + + * zebra-0.91 is released. + +2001-01-09 Kunihiro Ishiguro + + * zebra-0.90 is released. + +2000-11-06 Lennert Buytenhek + + * 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 + + * 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 + + * 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 index 00000000..91d2aebb --- /dev/null +++ b/init/redhat/bgpd.init @@ -0,0 +1,45 @@ +#!/bin/bash +# +# chkconfig: - 16 84 +# description: A BGPv4, BGPv4+, BGPv4- routing engine for use with Zebra +# +# processname: bgpd +# config: /etc/bgpd.conf + +# source function library +. /etc/rc.d/init.d/functions + +RETVAL=0 + +[ -f /etc/bgpd.conf ] || exit 0 + +case "$1" in + start) + echo -n "Starting bgpd: " + daemon /usr/sbin/bgpd -d + RETVAL=$? + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/bgpd + echo + ;; + stop) + echo -n "Shutting down bgpd: " + killproc bgpd + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/bgpd + echo + ;; + restart) + $0 stop + $0 start + RETVAL=$? + ;; + status) + status bgpd + RETVAL=$? + ;; + *) + echo "Usage: bgpd {start|stop|restart|status}" + exit 1 +esac + +exit $RETVAL diff --git a/init/redhat/ospf6d.init b/init/redhat/ospf6d.init new file mode 100644 index 00000000..4d89f8a2 --- /dev/null +++ b/init/redhat/ospf6d.init @@ -0,0 +1,45 @@ +#!/bin/bash +# +# chkconfig: - 16 84 +# description: An OSPF routing engine for use with Zebra and IPv6 +# +# processname: ospf6d +# config: /etc/ospf6d.conf + +# source function library +. /etc/rc.d/init.d/functions + +RETVAL=0 + +[ -f /etc/ospf6d.conf ] || exit 0 + +case "$1" in + start) + echo -n "Starting ospf6d: " + daemon /usr/sbin/ospf6d -d + RETVAL=$? + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ospf6d + echo + ;; + stop) + echo -n "Shutting down ospf6d: " + killproc ospf6d + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ospf6d + echo + ;; + restart) + $0 stop + $0 start + RETVAL=$? + ;; + status) + status ospf6d + RETVAL=$? + ;; + *) + echo "Usage: ospf6d {start|stop|restart|status}" + exit 1 +esac + +exit $RETVAL diff --git a/init/redhat/ospfd.init b/init/redhat/ospfd.init new file mode 100644 index 00000000..d7453b6e --- /dev/null +++ b/init/redhat/ospfd.init @@ -0,0 +1,45 @@ +#!/bin/bash +# +# chkconfig: - 16 84 +# description: An OSPF v2 routing engine for use with Zebra +# +# processname: ospfd +# config: /etc/ospfd.conf + +# source function library +. /etc/rc.d/init.d/functions + +RETVAL=0 + +[ -f /etc/ospfd.conf ] || exit 0 + +case "$1" in + start) + echo -n "Starting ospfd: " + daemon /usr/sbin/ospfd -d + RETVAL=$? + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ospfd + echo + ;; + stop) + echo -n "Shutting down ospfd: " + killproc ospfd + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ospfd + echo + ;; + restart) + $0 stop + $0 start + RETVAL=$? + ;; + status) + status ospfd + RETVAL=$? + ;; + *) + echo "Usage: ospfd {start|stop|restart|status}" + exit 1 +esac + +exit $RETVAL diff --git a/init/redhat/ripd.init b/init/redhat/ripd.init new file mode 100644 index 00000000..d87f498d --- /dev/null +++ b/init/redhat/ripd.init @@ -0,0 +1,45 @@ +#!/bin/bash +# +# chkconfig: - 16 84 +# description: A RIP routing engine for use with Zebra +# +# processname: ripd +# config: /etc/ripd.conf + +# source function library +. /etc/rc.d/init.d/functions + +RETVAL=0 + +[ -f /etc/ripd.conf ] || exit 0 + +case "$1" in + start) + echo -n "Starting ripd: " + daemon /usr/sbin/ripd -d + RETVAL=$? + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ripd + echo + ;; + stop) + echo -n "Shutting down ripd: " + killproc ripd + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ripd + echo + ;; + restart) + $0 stop + $0 start + RETVAL=$? + ;; + status) + status ripd + RETVAL=$? + ;; + *) + echo "Usage: ripd {start|stop|restart|status}" + exit 1 +esac + +exit $RETVAL diff --git a/init/redhat/ripngd.init b/init/redhat/ripngd.init new file mode 100644 index 00000000..26c153bf --- /dev/null +++ b/init/redhat/ripngd.init @@ -0,0 +1,45 @@ +#!/bin/bash +# +# chkconfig: - 16 84 +# description: A RIP routing engine for use with Zebra and IPv6 +# +# processname: ripngd +# config: /etc/ripngd.conf + +# source function library +. /etc/rc.d/init.d/functions + +RETVAL=0 + +[ -f /etc/ripngd.conf ] || exit 0 + +case "$1" in + start) + echo -n "Starting ripngd: " + daemon /usr/sbin/ripngd -d + RETVAL=$? + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ripngd + echo + ;; + stop) + echo -n "Shutting down ripngd: " + killproc ripngd + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ripngd + echo + ;; + restart) + $0 stop + $0 start + RETVAL=$? + ;; + status) + status ripngd + RETVAL=$? + ;; + *) + echo "Usage: ripngd {start|stop|restart|status}" + exit 1 +esac + +exit $RETVAL diff --git a/init/redhat/zebra.init b/init/redhat/zebra.init new file mode 100644 index 00000000..b09918ad --- /dev/null +++ b/init/redhat/zebra.init @@ -0,0 +1,45 @@ +#!/bin/bash +# +# chkconfig: - 15 85 +# description: GNU Zebra routing manager +# +# processname: zebra +# config: /etc/zebra.conf + +# source function library +. /etc/rc.d/init.d/functions + +RETVAL=0 + +[ -f /etc/zebra.conf ] || exit 0 + +case "$1" in + start) + echo -n "Starting zebra: " + daemon /usr/sbin/zebra -d + RETVAL=$? + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/zebra + echo + ;; + stop) + echo -n "Shutting down zebra: " + killproc zebra + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/zebra + echo + ;; + restart) + $0 stop + $0 start + RETVAL=$? + ;; + status) + status zebra + RETVAL=$? + ;; + *) + echo "Usage: zebra {start|stop|restart|status}" + exit 1 +esac + +exit $RETVAL diff --git a/init/redhat/zebra.logrotate b/init/redhat/zebra.logrotate new file mode 100644 index 00000000..0d13baf7 --- /dev/null +++ b/init/redhat/zebra.logrotate @@ -0,0 +1,47 @@ +/var/log/zebra/zebra.log { + notifempty + missingok + postrotate + /usr/bin/killall -USR1 zebra + endscript +} + +/var/log/zebra/bgpd.log { + notifempty + missingok + postrotate + /usr/bin/killall -USR1 bgpd + endscript +} + +/var/log/zebra/ospf.log { + notifempty + missingok + postrotate + /usr/bin/killall -USR1 ospfd + endscript +} + +/var/log/zebra/ospf6.log { + notifempty + missingok + postrotate + /usr/bin/killall -USR1 ospf6d + endscript +} + +/var/log/zebra/rip.log { + notifempty + missingok + postrotate + /usr/bin/killall -USR1 ripd + endscript +} + +/var/log/zebra/ripng.log { + notifempty + missingok + postrotate + /usr/bin/killall -USR1 ripng + endscript +} diff --git a/init/redhat/zebra.spec.in b/init/redhat/zebra.spec.in new file mode 100644 index 00000000..e517a46f --- /dev/null +++ b/init/redhat/zebra.spec.in @@ -0,0 +1,128 @@ +%define version @VERSION@ + +Summary: Zebra routing engine +Name: zebra +Version: %{version} +Release: 1 +Source: zebra-%{version}.tar.gz +URL: http://www.zebra.org +Copyright: GPL +Group: System Environment/Daemons +BuildRoot: /tmp/zebra-%{version}-root + +%description +GNU Zebra is free software (distributed under GNU Generic Public License) +that manages TCP/IP based routing protocols. It supports BGP-4 protocol as +described in RFC1771 (A Border Gateway Protocol 4) as well as RIPv1, RIPv2 +and OSPFv2. Unlike traditional, Gated based, monolithic architectures and +even the so-called "new modular architectures" that remove the burden of +processing routing functions from the cpu and utilize special ASIC chips +instead, Zebra software offers true modularity. + +%prep +%setup + +%build +#./configure --enable-snmp --prefix=/usr --sysconfdir=/etc +./configure --prefix=/usr --sysconfdir=/etc +make + +%install +rm -rf $RPM_BUILD_ROOT +make DESTDIR=$RPM_BUILD_ROOT install +rm -f $RPM_BUILD_ROOT/usr/info/dir +rm -f $RPM_BUILD_ROOT/usr/man/man8/ospf6* +rm -f $RPM_BUILD_ROOT/usr/man/man8/ripng* +rm -f $RPM_BUILD_ROOT/usr/sbin/ospf6d +rm -f $RPM_BUILD_ROOT/usr/sbin/ripngd +strip $RPM_BUILD_ROOT/usr/sbin/* + +mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d +install -m755 init/redhat/bgpd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/bgpd +#install -m755 init/redhat/ospf6d.init $RPM_BUILD_ROOT/etc/rc.d/init.d/ospf6d +install -m755 init/redhat/ospfd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/ospfd +install -m755 init/redhat/ripd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/ripd +#install -m755 init/redhat/ripngd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/ripngd +install -m755 init/redhat/zebra.init $RPM_BUILD_ROOT/etc/rc.d/init.d/zebra + +mkdir -p $RPM_BUILD_ROOT/etc/logrotate.d +install -m644 init/redhat/zebra.logrotate $RPM_BUILD_ROOT/etc/logrotate.d/zebra + + +%post +# zebra_spec_add_service +# e.g. zebra_spec_add_service zebrasrv 2600/tcp "zebra service" + +zebra_spec_add_service () +{ + # Add port /etc/services entry if it isn't already there + if [ -f /etc/services ] && ! grep -q "^$1[^a-zA-Z0-9]" /etc/services ; then + echo "$1 $2 # $3" >> /etc/services + fi +} + +zebra_spec_add_service zebrasrv 2600/tcp "zebra service" +zebra_spec_add_service zebra 2601/tcp "zebra vty" +zebra_spec_add_service ripd 2602/tcp "RIPd vty" +zebra_spec_add_service ripngd 2603/tcp "RIPngd vty" +zebra_spec_add_service ospfd 2604/tcp "OSPFd vty" +zebra_spec_add_service bgpd 2605/tcp "BGPd vty" +zebra_spec_add_service ospf6d 2606/tcp "OSPF6d vty" + +#Install info +/sbin/install-info /usr/info/zebra.info /usr/info/dir + +if [ -x /sbin/chkconfig ]; then + chkconfig --add bgpd +# chkconfig --add ospf6d + chkconfig --add ospfd + chkconfig --add ripd +# chkconfig --add ripngd + chkconfig --add zebra +fi + + +%preun +if [ "$1" = 0 ] ; then + /sbin/install-info --delete /usr/info/zebra.info /usr/info/dir + + if [ -x /sbin/chkconfig ]; then + chkconfig --del bgpd +# chkconfig --del ospf6d + chkconfig --del ospfd + chkconfig --del ripd +# chkconfig --del ripngd + chkconfig --del zebra + fi +fi + +%clean +rm -rf $RPM_BUILD_ROOT +rm -rf $RPM_BUILD_DIR/%{name}-%{version} + +%files +%attr(-,root,root) %doc AUTHORS COPYING ChangeLog INSTALL NEWS README SERVICES TODO bgpd/bgpd.conf.sample ospfd/ospfd.conf.sample ripd/ripd.conf.sample zebra/zebra.conf.sample +%attr(-,root,root) %config /etc/rc.d/init.d/* +%attr(-,root,root) %config /etc/logrotate.d/* +%attr(-,root,root) /usr/info/* +#%attr(-,root,root) /usr/man/* # Not man1 to exclude vtysh man page as + # it is not build by default (for now) +%attr(-,root,root) /usr/man/man8/* +%attr(-,root,root) /usr/sbin/* + +%changelog +* Mon Nov 6 2000 Lennert Buytenhek +- Don't include ospf6d and ripngd in package. +- Fix logrotate file (add ospf.log). +* Mon Oct 2 2000 Horms +- Install and uninstall info in %post and %preun respectively +- Moved chkconfig --del operations from %postun to %preun, as + chkconfig needs to run while the init files are still present on + the system. +- Don't install vtysh man page as vtysh is not build by default +- Added logrotate script so logs won't grow without bound +* Wed Sep 27 2000 Horms +- Add ports to /etc/services if they aren't there +- forcibly remove $RPM_BUILD_ROOT/usr/info/dir and friends so + there is no error if it does not exist when rm is run. +- Clean up the zebra build dir diff --git a/install-sh b/install-sh new file mode 100755 index 00000000..398a88e1 --- /dev/null +++ b/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + : +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=$mkdirprog + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + : + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + : + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + : + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' + ' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + : + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + : + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/lib/.cvsignore b/lib/.cvsignore new file mode 100644 index 00000000..051b8e4f --- /dev/null +++ b/lib/.cvsignore @@ -0,0 +1,4 @@ +Makefile +*.o +version.c +.deps diff --git a/lib/ChangeLog b/lib/ChangeLog new file mode 100644 index 00000000..b4d0ae12 --- /dev/null +++ b/lib/ChangeLog @@ -0,0 +1,1926 @@ +2002-09-28 Yasuhiro Ohara + + * vty.c (vty_flush): One line more on vty. + +2002-09-27 Kunihiro Ishiguro + + * vector.c (vector_lookup): Add new function. + +2002-08-19 Kunihiro Ishiguro + + * thread.c (timeval_adjust): Fix unconditional crush due to + FreeBSD's select() system call timeval value check. + +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2002-06-21 Kunihiro Ishiguro + + * if.c (ifc_pointopoint): Add ifc_pointopoint() accoding to Frank + van Maarseveen's suggestion. + +2002-06-18 Kunihiro Ishiguro + + * command.c: Change bcopy() to memcpy(). + +2001-12-12 Kunihiro Ishiguro + + * command.c (config_password): Fix host.password clear bug. + Reported by Wang Jian . + +2001-08-29 Kunihiro Ishiguro + + * thread.c (thread_should_yield): New function to check thread + should yeild it's execution to other thread. Suggested by: Rick + Payne + +2001-08-20 Kunihiro Ishiguro + + * thread.c (thread_timer_cmp): Rewrite function. + + * hash.c: Add hash_get(). Change hash_pull() to hash_release(). + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-08-12 Akihiro Mizutani + + * prefix.c (netmask_str2prefix_str): Convert "1.1.0.0 255.255.0.0" + string to "1.1.0.0/16". + +2001-08-10 Kunihiro Ishiguro + + * filter.c (access_list_lookup): access_list_lookup's first + argument is changed from address family to AFI. + + * plist.c: (prefix_list_lookup): Likewise. + +2001-07-27 Akihiro Mizutani + + * plist.c: ge and le display order is changed. Old compatible + rule (len <= ge-value <= le-value) is removed. + +2001-07-08 Kunihiro Ishiguro + + * prefix.h: Temporary fix for alignment of prefix problem. + +2001-06-21 Kunihiro Ishiguro + + * prefix.h (struct prefix): Remove safi and padding field. + (struct prefix_ipv4): Likewise. + (struct prefix_ipv6): Likewise. + (struct prefix_ls): Likewise. + (struct prefix_rd): Likewise. + + * command.h (enum node_type): Preparation for BGP new config. + + * vty.c (vty_end_config): Likewise. + +2001-06-17 Kunihiro Ishiguro + + * routemap.c (route_map_rule_delete): Call func_free when + route-map rule is deleted. + +2001-06-14 "Akihiro Mizutani" + + * routemap.c (route_map_index_lookup): Prevent to use deny and + permit for same route-map sequence. + +2001-04-12 Kunihiro Ishiguro + + * vty.c (vty_read_config): Fix warning. + +2001-03-08 Kunihiro Ishiguro + + * command.c (IPV6_PREFIX_STR): Add '.' and '%' for IPv6 address + strings. + +2001-03-07 Kunihiro Ishiguro + + * zebra.h (_XPG4_2): Define _XPG4_2 and __EXTENSIONS__ for + CMSG_FIRSTHDR. + +2001-03-07 Michael Rozhavsky + + * zebra.h (struct in_pktinfo): structure in_pktinfo declaration. + +2001-02-19 Kunihiro Ishiguro + + * memory.c (memory_list_lib): Add MTYPE_NEXTHOP for "show memory + lib" member. + +2001-02-13 Matthew Grant + + * vty.c (vty_read_config): Revert check of integrate_default when + VTYSH is defined. + +2001-02-13 Kunihiro Ishiguro + + * vty.c (vty_read_config): Do not check integrate_default. That + should be used only by vtysh. + +2001-02-08 Matthew Grant + + * vty.c (vty_serv_un): Set umask 0077. + (vty_read_config): Stat for vtysh Zebra.conf, if found startup and + wait for boot configuration. + + * if.c (if_lookup_address): Make it smart implementation. + + * sockopt.c (setsockopt_multicast_ipv4): Set up a multicast socket + options for IPv4 This is here so that people only have to do their + OS multicast mess in one place rather than all through zebra, + ospfd, and ripd . + +2001-02-04 Akihiro Mizutani + + * plist.c (vty_prefix_list_install): Even when argument is + invalid, new memory is allocated. Now memory allocation is done + after argument check. + +2001-02-01 Kunihiro Ishiguro + + * zebra-0.91 is released. + +2001-01-31 Akihiro Mizutani + + * vty.c (vty_login): Add vty login command. + +2001-01-31 Kunihiro Ishiguro + + * vty.c (vty_reset): Close accept socket. + +2001-01-30 Kunihiro Ishiguro + + * memory.h (enum): MTYPE_ATTR_TRANSIT is added for unknown transit + attribute. + +2001-01-22 Kunihiro Ishiguro + + * zclient.c (zebra_interface_address_add_read): Fetch interface + address flag. + (zebra_interface_address_delete_read): Likewise. + +2001-01-16 Kunihiro Ishiguro + + * table.c (route_node_match_ipv4): Utility function for IPv4 + address lookup. + (route_node_match_ipv6): Utility function for IPv4 address lookup. + +2001-01-15 Kunihiro Ishiguro + + * if.c: Delete RIP_API part until new implementation comes out. + +2001-01-13 Kunihiro Ishiguro + + * hash.h (struct Hash): Rename alloc to count. Change type to + unsigned long. + + * stream.c (stream_getc_from): New function. + (stream_getw_from): Likewise. + + * zebra.h (ZEBRA_FLAG_STATIC): Add new flag for persistent route. + +2001-01-11 Kunihiro Ishiguro + + * flap.c: File is removed. + + * flap.c: Likewise. + + * roken.h: Likewise. + + * buffer.c (buffer_new): Remove type option to buffer_new(). + +2001-01-10 Kunihiro Ishiguro + + * zclient.c (zapi_ipv4_delete): Remove OLD_RIB part. + +2001-01-09 Kunihiro Ishiguro + + * zebra-0.90 is released. + + * command.c: Update Copyright year. + +2001-01-09 Matthew Grant + + * if.c (if_create): Register connected_free() function for + deletion. + (if_delete): Free connected information when the interface is + deleted. + (if_lookup_by_index): Fix argument type from int to unsigned int. + (connected_add): Keep list in order if old info found, essential + for repeatable operation in some daemons. + +2001-01-09 endo@suri.co.jp (Masahiko Endo) + + * vty.c (vty_flush): When vty->statis is VTY_CLOSE do not add vty + read thread. + +2001-01-08 Kunihiro Ishiguro + + * filter.c (access_list_delete): Access-list name is not freed. + + * plist.c (prefix_list_delete): Prefix-list name is not freed. + +2000-12-29 Kunihiro Ishiguro + + * zclient.c (zclient_start): Change to use UNIX domain + socket for zebra communication. + + * vector.c (vector_init): vector_alloc and vector_data_alloc is + removed. All memory allocation count should be maintained by + XMALLOC and XFREE macros. + +2000-12-28 Kunihiro Ishiguro + + * zebra.h (ZEBRA_NEXTHOP_IFINDEX): Define ZEBRA_NEXTHOP_* values. + +2000-12-27 Kunihiro Ishiguro + + * zebra.h (ZEBRA_ERR_RTEXIST): Make zebra error code to negative + value. + +2000-12-25 "Wataru Uno" + + * vty.c (vtysh_read): Don't allocate new buffer because buffer is + allocated in vty_new (). + +2000-12-14 Kunihiro Ishiguro + + * memory.h (enum): Add MTYPE_AS_FILTER_STR. + + * command.c (config_write_terminal): Display "end" at the end of + configuration. + + * plist.c (vty_prefix_list_install): Use AF_INET to determine + lenum length. + +2000-12-13 "Wataru Uno" + + * buffer.c (buffer_flush_vty): If IOV_MAX defined in the System, + then all lines write by IOV_MAX. + +2000-12-12 Michael Rozhavsky + + * command.c (config_write_file): Robust method for writing + configuration file and recover from backing up config file. + +2000-11-29 Kunihiro Ishiguro + + * smux.c (smux_connect): More fail check. + (smux_trap): When SMUX connection is not established, do nothing. + +2000-11-28 Gleb Natapov + + * thread.c (thread_fetch): Execut event list first. Old event + list is renamed to ready list. With this change, event thread is + executed before any other thread. + + * thread.h (struct thread_master): Add ready list. + +2000-11-28 Kunihiro Ishiguro + + * linklist.c (listnode_add_after): Add node right after the + listnode pointer. + +2000-11-27 Kunihiro Ishiguro + + * smux.h: Pass struct variable to WriteMethod. + +2000-11-25 Frank van Maarseveen + + * if.c (if_lookup_address): When looking up interface with IP + address, Sometimes multiple interfaces will match. Now PtP + interfaces prevail in such a case which seem the right thing to + do: There will probably also be host routes which usually prevail + over network routes. + +2000-11-25 Kunihiro Ishiguro + + * smux.c (smux_trap): SMUX trap implementation. + +2000-11-19 Akihiro Mizutani + + * plist.c: Add automatic conversion function of an old rule. + ex.) 10.0.0.0/8 ge 8 -> 10.0.0.0/8 le 32 + +2000-11-16 Yon Uriarte + + * zclient.c (zebra_interface_add_read): Read hardware address when + hw_addr_len is greater than 0. + +2000-11-15 Akihiro Mizutani + + * plist.c: The rule of "len <= ge-value <= le-value" + was changed to "len < ge-value <= le-value". + +2000-11-09 Yasuhiro Ohara + + * memory.[ch]: Added #define and functions for ospf6d. + + * log.[ch]: some platform says that the data of used va_list + is undefined. Changed to hold list of va_list for each + vsnprintf. + +2000-11-07 Rick Payne + + * memory.h (enum): Add MTYPE_COMMUNITY_REGEXP. + +2000-11-06 Kunihiro Ishiguro + + * command.c (config_exit): Fix bug of missing break after case + BGP_VPNV4_NODE. + +2000-10-30 Kunihiro Ishiguro + + * vector.c (vector_unset): Check i is not nevative. + +2000-10-24 Arkadiusz Miskiewicz + + * smux.c (smux_sock): Set terminating '\0'. Check address family. + + * vty.c (vty_serv_sock_addrinfo): Set terminating '\0'. Use + gai_strerror. Check address family. + +2000-10-23 Jochen Friedrich + + * smux.c: Use linklist rather than vector. + (smux_getnext): A SMUX subagent has to behave as if it manages the + whole SNMP MIB tree itself. It's the duty of the master agent to + collect the best answer and return it to the manager. See RFC 1227 + chapter 3.1.6 for the glory details :-). ucd-snmp really behaves + bad here as it actually might ask multiple times for the same + GETNEXT request as it throws away the answer when it expects it in + a different subtree and might come back later with the very same + request. + +2000-10-23 Kunihiro Ishiguro + + * command.c (cmd_init): Log related command are only installed for + terminal mode. + +2000-10-21 Kunihiro Ishiguro + + * Makefile.am (libzebra_a_SOURCES): Remove duplicated buffer.c. + + * zebra.h: Remove #warn directive. + +2000-10-20 Kunihiro Ishiguro + + * keychain.c (keychain_init): Register "key chain" command to + KEYCHAIN_NODE and KEYCHAIN_KEY_NODE. + + * vty.c (vty_end_config): Fix missing vty_cinfig_unlock for other + CONFIG_NODE. + + * command.c (config_end): Likewise. + + * keychain.c (keychain_get): Key is sorted by it's identifier + value. + +2000-10-19 Kunihiro Ishiguro + + * linklist.c (list_delete_all_node): Call delete function if it is + defined. + + * command.c (cmd_execute_command_strict): Add modification for + vtysh. + (cmd_execute_command_strict): Remove first argument cmdvec because + it is global varibale in command.c. + +2000-10-18 Kunihiro Ishiguro + + * command.c (cmd_init): Install + copy_runningconfig_startupconfig_cmd only in terminal mode. + + * linklist.c (list_delete_node): Simplify the function. + (listnode_lookup): Renamed from list_lookup_node. + +2000-10-17 Kunihiro Ishiguro + + * stream.h: Undef stream_read and stream_write without + parenthesis. + + * newlist.c: File removed. + + * newlist.h: Likewise. + + * linklist.c (list_new): Remove list_init(). To allocate new + linked list, please use list_new(). + (listnode_add): Remove list_add_node(). To add new node to linked + list, please use listnode_add(). + (list_delete_by_val): Revemove fucntion. + +2000-10-16 Nobuaki Tanaka + + * table.c (route_table_free): Reimplement route_table_free(). + +2000-10-11 Kunihiro Ishiguro + + * keychain.c (keychain_get): Register key_delete_func to key + list's delete function. Use linklist.c instead of newlist.c. + +2000-10-04 Akihiro Mizutani + + * filter.c (access_list_remark): Add access-list's remark command. + (no_access_list): "no access-list 100 permit any" error message + bug is fixed. + +2000-10-03 Kunihiro Ishiguro + + * memory.h (enum): Add MTYPE_SOCKUNION. + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 is released. + +2000-10-01 Kunihiro Ishiguro + + * linklist.c (list_add_node_head): Delete unused function. + (list_add_node_tail): Likewise. + +2000-09-26 Kunihiro Ishiguro + + * stream.c (stream_read_unblock): Add new function for unblocking + read. + +2000-09-26 Jochen Friedrich + + * smux.c (smux_register): Fix bug of can't register more than one + MIB with SMUX. + +2000-09-26 Makoto Otsuka + + * vty.c (vty_close): Fix memory leak of sb_buffer. + (vty_new): Likewise. + +2000-09-21 steve@Watt.COM (Steve Watt) + + * log.h: Do not declare zlog_priority[0] variable. + +2000-09-12 Kunihiro Ishiguro + + * linklist.h (struct _list ): Add member cmp for compare function. + (struct _list ): Member up is deleted + +2000-09-12 David Lipovkov + + * if.c: Include RIP_API header when RIP API is enabled. + +2000-09-10 Kunihiro Ishiguro + + * prefix.c (prefix_free): Siplify prefix_free(). + + * keychain.c (key_match_for_accept): strncmp check bug is fixed. + +2000-09-07 Kunihiro Ishiguro + + * zebra.h: Merge roken.h into zebra.h. + +2000-09-05 Akihiro Mizutani + + * routemap.c (route_map_init_vty): Install route-map command to + RMAP_NODE. + +2000-08-22 Kunihiro Ishiguro + + * thread.c (thread_get_id): Remove pthread related garbage. + + * command.h (struct host): Likewise. + + * zebra.h: Likewise. + +2000-08-20 Kunihiro Ishiguro + + * command.h (node_type ): Add AAA node for authentication. + + * vty.c (vty_close): Do not close stdout. + +2000-08-18 Kunihiro Ishiguro + + * vty.c (vty_init_vtysh): Added for vtysh. + + * distribute.c (districute_list_prefix_all): Interface independent + filter can be set. + (distribute_list_all): Likewise. + (config_show_distribute): Display current distribute-list status + for "show ip protocols". + +2000-08-18 Akihiro Mizutani + + * command.c (config_terminal_no_length): no terminal monitor -> + terminal no monitor + (cmd_init): Do not install service_terminal_length_cmd into + ENABLE_NODE. + + * vty.c (terminal_no_monitor): no terminal length -> terminal no + length. + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 is released. + +2000-08-17 Magnus Ahltorp + + * vty.h (struct vty ): Add iac_sb_in_progress and sb_buffer for + better IAC handling. + + * vty.c (vty_telnet_option): Change telnet option handling. + +2000-08-15 Gleb Natapov + + * zclient.c (zclient_redistribute_unset): New function added. + +2000-08-14 Kunihiro Ishiguro + + * zclient.c (zebra_interface_add_read): Change ifindex restore + size from two octet to four. + (zebra_interface_state_read): Likewise. + (zebra_interface_address_add_read): Likewise. + +2000-08-13 Kunihiro Ishiguro + + * vty.c (vty_event): Use vector_set_index() instead of + vector_set(). + +2000-08-07 Kunihiro Ishiguro + + * zebra.h (ZEBRA_XXX_DISTANCE_DEFAULT): Define Default + Administrative Distance of each protocol. + +2000-08-07 Matthew Grant + + * if.h (struct interface ): Add new member bandwidth to struct + interface. + + * zclient.c (zebra_interface_add_read): Fetch bandwidth value. + (zebra_interface_state_read): Likewise. + +2000-08-07 Gleb Natapov + + * routemap.c (route_map_event_hook): New hook route_map_event_hook + is added. This hook is called when route-map is changed. The + parameters passed to the hook are 'event' and 'route-map name' + + * routemap.h: Add prototype for route_map_event_hook(). + +2000-08-06 Kunihiro Ishiguro + + * zclient.c (zebra_ipv4_route): zebra_ipv4_route(), + zebra_ipv4_add(), zebra_ipv4_delete() are removed. + + * routemap.c (route_map_empty): Add new function. + (route_map_delete): Use route_map_index_delete() instead of + route_map_index_free(). + (route_map_index_free): Function removed. + +2000-08-06 Gleb Natapov + + * routemap.c (route_map_index_delete): Add check for route-map is + empty or not. + +2000-08-03 Kunihiro Ishiguro + + * zclient.c (zebra_ipv4_add): Change socket arguemnt with struct + zclient. + +2000-08-02 Kunihiro Ishiguro + + * zclient.h (struct zebra): Add obuf for output buffer. + + * if.c: Remove #ifdef NRL enclosing if_nametoindex() and + if_indextoname(). + +2000-08-02 David Lipovkov + + * if.h (IF_PSEUDO_UNSET): IF_PSEUDO related macro added. + (IF_UNKNOWN_SET): IF_UNKNOWN related macro deleted. + + * if.c (interface_pseudo): Add "pseudo" command to interface node. + (no_interface_pseudo): Add "no pseudo" command to interface node. + + * zclient.c (zebra_interface_add_read): Set pseudo flag when it is + send from zebra. + +2000-08-01 Kunihiro Ishiguro + + * zebra.h (ZEBRA_IPV4_NEXTHOP_LOOKUP): Add new message. + (ZEBRA_IPV6_NEXTHOP_LOOKUP): Likewise. + + * vty.c (vty_serv_un): Use AF_UNIX for backward compatibility. + +2000-07-31 Kunihiro Ishiguro + + * vty.c: Use vector for VTY server thread listing instead of + single value. + +2000-07-30 Kunihiro Ishiguro + + * keychain.c (no_key_chain): "no key chain WORD" command is added. + +2000-07-29 Kunihiro Ishiguro + + * command.c (config_from_file): If command fail in + KEYCHAIN_KEY_NODE, down to KEYCHAIN_NODE. + + * vty.h (struct vty ): Add index_sub member. + +2000-07-27 Akihiro Mizutani + + * if.c: Help strings updates. + +2000-07-11 Akihiro Mizutani + + * command.c (no_config_enable_password): Add "no enable password" + command. + (config_write_host): Display password string. + + * routemap.c (route_map_delete_match): Add support for delete + match without argument. + (route_map_delete_set): Likewise. + +2000-07-09 Kunihiro Ishiguro + + * command.h (node_type ): Change KEYCHAIN_NODE and + KEYCHAIN_KEY_NODE place just before INTERFACE_NODE. + +2000-07-09 Jochen Friedrich + + * smux.c (config_write_smux): Fixes the option to override OID and + password for SMUX. + +2000-07-09 Kunihiro Ishiguro + + * command.h (node_type ): Add SMUX_NODE for SMUX configuration. + +2000-07-09 Toshiaki Takada + + * command.c: Sort descvec command's help. + + * vty.c (vty_describe_command): Display '' at the end of + descriptions. + +2000-07-05 Toshiaki Takada + + * command.c (cmd_ipv6_match), (cmd_ipv6_prefix_match): Fix bug + treatment of double colon. + +2000-07-04 Kunihiro Ishiguro + + * zclient.h: Add zclient_redistribute_default_{set,unset}(). + + * keychain.c: New file for authentication key management. + * keychain.h: Likewise. + + * tcpfilter.c: New file for TCP/UDP base filtering using ipfw or + ipchains. + * tcpfilter.h: Likewise. + + * flap.h: New file for route flap dampening. + * flap.c: Likewise. + +2000-07-04 Toshiaki Takada + + * filter.c (struct filter): Add exact flag. + (access_list): Add exact-match command. + (ipv6_access_list): Add exact-match command. + +2000-07-03 Kunihiro Ishiguro + + * zebra.h (ZEBRA_REDISTRIBUTE_DEFAULT_ADD): New message for + request default route. + +2000-07-01 Hideaki YOSHIFUJI ($B5HF#1QL@(B) + + * smux.c: Add IPv6 smux connection code. + +2000-06-15 Kunihiro Ishiguro + + * vty.c (vty_complete_command): To cooperate readline library, + returned string is newly allocated. So some match function case + need, free of memory. + +2000-06-12 Akihiro Mizutani + + * distribute.c: Fix help strings. + +2000-06-11 Kunihiro Ishiguro + + * command.c (cmd_complete_command): Add check for vector_slot + (vline, index) is not NULL when calculating lcd. + (cmd_entry_function): First check variable arguemnt to prevent it + from completion. + +2000-06-10 Kunihiro Ishiguro + + * vty.h (struct vty ): Add output_count member for displaying + output route count. Remove arugment arg from output_func because + the value is passed by vty argument. Change output to output_rn. + Add output_clean function pointer member. Add output_type member. + +2000-06-10 Toshiaki Takada + + * command.c (show_startup_config): Add "show startup-config" + command. + +2000-06-06 Akihiro Mizutani + + * filter.c: Fix help strings. + +2000-06-05 Kunihiro Ishiguro + + * prefix.h (struct prefix_rd): New prefix structure for routing + distinguisher. + (struct prefix): Add padding to every prefix structure. + + + * routemap.c (route_map_add_match): When completely same match + statement exists, don't duplicate it. + +2000-06-05 Akihiro Mizutani + + * routemap.c: Change NAME to WORD. + + * plist.c: Fix help strings. + +2000-06-02 Akihiro Mizutani + + * routemap.c: Fix route-map help strings. + +2000-06-01 Kunihiro Ishiguro + + * command.c (cmd_filter_by_completion): Fix CMD_VARARG treatment + to filter other non vararg commands. + + * routemap.c (route_map_init_vty): Use install_default() for + install common commands into route-map node.. + +2000-06-01 Akihiro Mizutani + + * command.h (OSPF_STR): Macro added. + +2000-05-31 Kunihiro Ishiguro + + * command.c (cmd_complete_command): LCD completion must not modify + installed command string. + + * plist.c (ipv6_prefix_list): Fix wrong syntax definition. Change + X:X::X:X to X:X::X:X/M. + +2000-05-31 Toshiaki Takada + + * vty.c (show_history): New defun added. + +2000-05-30 Kunihiro Ishiguro + + * command.h (CMD_COMPLETE_LIST_MATCH): New define for completion + list. CMD_COMPLETE_MATCH is used for LCD completion. + + * vty.c (vty_complete_command): Matched string's LCD is completed. + + * command.c (cmd_lcd): New function for calculate LCD of matched + strings. + +2000-05-26 Kunihiro Ishiguro + + * command.c (install_default): config_write_terminal_cmd, + config_write_file_cmd, config_write_memory_cmd are added to + default node. + + * memory.c (memory_init): Divide show memory command into each + sort. + + * command.c (cmd_init): config_write_terminal_cmd, + config_write_file_cmd, config_write_memory_cmd are added to + CONFIG_NODE. + + * routemap.c (route_map_index_free): New function. + (no_route_map_all): New DEFUN for "no route-map NAME". + + * filter.c (no_access_list_all): New DEFUN for delete access-list + with NAME. + (no_ipv6_access_list_all): Likewise. + +2000-05-23 Kunihiro Ishiguro + + * plist.c: Change IPV6_PREFIX to X:X::X:X. When "any" is + specified, user can not use "ge" and "le" statement. + +2000-05-22 Thomas Molkenbur + + * routemap.c (route_map_add_set): Fix bug of next pointer missing. + + * table.c (route_table_free): Like wise. + +2000-05-22 Toshiaki Takada + + * vty.c (vty_stop_input): Set history pointer to the latest one. + + * vty.c (vty_hist_add): Do not add command line history when input + is as same as previous one. + +2000-05-14 Kunihiro Ishiguro + + * memory.h (enum): Add MTYPE_ECOMMUNITY and MTYPE_ECOMMUNITY_VAL. + +2000-05-13 Kunihiro Ishiguro + + * command.h (node_type ): Add BGP_VPNV4_NODE. + +2000-05-08 Kunihiro Ishiguro + + * vty.c (vtysh_accept): Add cast of struct sockaddr * to bind + argument. Reported by: Vesselin Mladenov . + + * filter.c (ipv6_access_list): Add IPv6 prefix example instead of + IPv4 example. Reported by: Love . + + * command.c (cmd_complete_command): Make it sure last element of + matchvec is NULL. This fix problem which cause crush in + vty_complete_command(). Reported by: JINMEI Tatuya + . + +2000-04-28 Love + + * prefix.h (struct prefix): Add padding. + +2000-04-28 Kunihiro Ishiguro + + * command.c (show_version): Update copyright year. + +2000-04-27 Kunihiro Ishiguro + + * routemap.c (route_map_apply): When map is NULL, return deny. + +2000-04-26 Kunihiro Ishiguro + + * filter.c (access_list_apply): When access is NULL, return deny. + + * plist.c (prefix_list_apply): When plist is NULL, return deny. + +2000-04-23 Kunihiro Ishiguro + + * command.h (node_type ): Change RDISC_NODE to IRDP_NODE. + +2000-04-18 Toshiaki Takada + + * filter.[ch] (access_list_add_hook), (access_list_delete_hook): + Add argument for hook function to give struct access_list *. + +2000-04-17 Kunihiro Ishiguro + + * plist.c (prefix_list_entry_match): In case of le nor ge is + specified, exact match is performed. + (prefix_list_entry_match): Add any entry matching check. + +2000-04-09 Kunihiro Ishiguro + + * vty.c (exec_timeout): Separate timeout setting to minutes and + seconds. + (no_exec_timeout): Add "no exec-timeout" command. + + * vty.h (VTY_TIMEOUT_DEFAULT): Change default value from 300 to + 600. + +2000-03-31 Jochen Friedrich + + * smux.h (SMUX_CLOSE): The SMUX_CLOSE PDU is implicit integer, so + it is a primitive encoding and not constructed. + +2000-03-28 Toshiaki Takada + + * memory.[ch] (enum): Add MTYPE_OSPF_EXTERNAL_INFO. + +2000-03-26 Love + + * zclient.c (zclient_read): Add nbytes size check for + ZEBRA_HEADER_SIZE. Check return value of steam_read (). + +2000-03-26 Rick Payne + + * routemap.c: Add flexible route-map commands such as on-match + next, on-match goto N. + + * routemap.h: Likewise + +2000-03-23 Adrian Bool + + * command.c (config_log_trap): Add new command "log trap + PRIORITY". + +2000-03-14 Toshiaki Takada + + * memory.c (struct memory_list): Add Link List and Link Node + to view. + + * memory.h (enum): Remove MTYPE_OSPF_EXTERNAL_ROUTE. + +2000-01-20 Hideto Yamakawa + + * str.c (snprintf): Fix bug of calling sprintf instead of + vsprintf. + +2000-01-16 Kunihiro Ishiguro + + * memory.h (enum): Add MTYPE_RIP_PEER. + +2000-01-15 Toshiaki Takada + + * memory.h (enum): Add MTYPE_OSPF_CRYPT_KEY. + +2000-01-15 Kunihiro Ishiguro + + * command.h (node_type ): Add MASC_NODE for masc. + +2000-01-09 Wang Jianliang + + * routemap.c (route_map_index_add): When route_map_index is not + empty and insert new item at the head, it can cause core dump. + Fix "if (index == map->head)" to "if (point == map->head). + (route_map_add_set): If there is an old set command, override old + set command with new one. + (route_map_index_delete): Use while() instead of for for() for + logical correctness. + +1999-12-26 Kunihiro Ishiguro + + * memory.h (enum): Add MTYPE_BGP_STATIC. + +1999-12-23 Alex Zinin + * zebra.h, zclient.*: dynamic int up/down message + support + +1999-12-10 Kunihiro Ishiguro + + * thread.c (thread_cancel_event): Add a function for clean up + events. + +1999-12-09 Kunihiro Ishiguro + + * dropline.c: Delete file. + dropline.h: Linewise. + +1999-12-14 Kunihiro Ishiguro + + * filter.c (access_list_filter_delete): Wrong pointer + access->master was pointed out after access is freed. I store + master value at the beginning of the function. + +1999-12-08 Kunihiro Ishiguro + + * vty.c (exec_timeout): Change of VTY timeout affect to current + VTY connection. + (vty_accept): Instead of immediate exit() return -1. + +1999-12-07 Kunihiro Ishiguro + + * vty.c (vty_configure_lock): Configuration lock function added. + Only one VTY can use CONFI_NODE at the same time. + + * log.c: Delete zvlog_* functions. Now zlog_* does the same + thing. + + * log.c (log_init): Function removed. + (log_close): Likewise. + (log_flush): Likewise. + (log_open): Likewise. + + * vty.c (terminal_monitor): Add new command. + (no_terminal_monitor): Likewise. + + * log.c (old_log): Function removed. + (old_log2): Likewise. + (old_log_warn): Likewise. + +1999-12-04 Toshiaki Takada + + * command.c (cmd_ipv6_match): New function added. + (cmd_ipv6_prefix_match): Likewise. + +1999-12-04 Kunihiro Ishiguro + + * command.c (cmd_ipv6_match): + + * table.c: Delete #ifdef HAVE_MBGPV4. + + * prefix.h (struct prefix): Add safi member. + (struct prefix_ipv4): Likewise. + (struct prefix_ipv6): Likewise. + +1999-12-04 Rumen Svobodnikov + + * memory.c (struct mstat): Revert to support MEMORY_LOG. + +1999-11-25 Kunihiro Ishiguro + + * version.h: Bump up to 0.81c for testing new kernel codes. + +1999-11-21 Kunihiro Ishiguro + + * thread.h (struct thread): Pthread support is disabled all + platform. + +1999-11-21 Michael Handler + + * Include and under SUNOS_5. + +1999-11-21 Kunihiro Ishiguro + + * sockunion.c (in6addr_cmp): Enclosed by #define HAVE_IPV6 +1999-11-13 Kunihiro Ishiguro + + * command.h (node_type ): Add BGP_IPV4_NODE and BGP_IPV6_NODE. + +1999-11-12 Kunihiro Ishiguro + + * command.c (disable): Add `disable' command. + +1999-11-09 Kunihiro Ishiguro + + * plist.c (vty_prefix_list_install): Add any check. + +1999-11-04 Kunihiro Ishiguro + + * command.h (node_type ): Add DUMP_NODE. + +1999-11-03 Kunihiro Ishiguro + + * smux.c: Change default SMUX oid to compatible with gated. + +1999-10-30 Kunihiro Ishiguro + + * if_rmap.c: New file added. + + * if_rmap.h: New file added. + +1999-10-29 Alex Zinin + + * hash.c: add hash_free() function + +1999-10-25 Kunihiro Ishiguro + + * hash.c (hash_clean): Add clean function. + + * plist.c (prefix_list_reset): Add reset function. + + * filter.c (access_list_reset): Add reset function. + +1999-10-17 Kunihiro Ishiguro + + * client.c: Merged with zclient.c. + * client.h: Merged with zclient.h. + +1999-10-15 Jordan Mendelson + + * md5.c: Imported from GNU C Library. + * md5-gnu.h: Likewise. + +1999-10-15 Jochen Friedrich + + * smux.c (smux_getresp_send): SMUX_GETRSP codes improvement. + +1999-10-06 Kunihiro Ishiguro + + * smux.h: New file added. + + * snmp.c: Rename to smux.c. + +1999-10-02 Kunihiro Ishiguro + + * command.c (cmd_execute_command_strict): Filter ambious commands. + (cmd_filter_by_string): Change to return enum match_type. + +1999-10-01 Toshiaki Takada + + * vty.c (vty_describe_fold): New function which does VTY + description line fold. + * vty.c (vty_describe_command): Set description column. + +1999-09-30 Kunihiro Ishiguro + + * plist.c (prefix_list_init_ipv4): VTY user interface is improved. + +1999-09-26 Kunihiro Ishiguro + + * command.c (cmd_filter_by_string): Fix bug of CMD_IPV4 and + CMD_IPV4_PREFIX check. Both return type must be exact_match. + +1999-09-24 Toshiaki Takada + + * command.c (cmd_filter_by_completion), + (is_cmd_ambiguous): Check IPv4 address, IPv4 prefix and range + parameter matches range. + +1999-09-22 Kunihiro Ishiguro + + * routemap.c (route_map_apply): Returm RM_DENYMATCH when no match + is performed. + +1999-09-21 Kunihiro Ishiguro + + * vty.c (vty_read): Control-C stop VTY_MORE mode. + +1999-09-20 Kunihiro Ishiguro + + * command.h (node_type ): Add ACCESS_IPV6_NODE and + PREFIX_IPV6_NODE. + + * distribute.h: New file added. + + * command.h (node_type ): Delete DISTRIBUTE_NODE. + +1999-09-18 Kunihiro Ishiguro + + * vty.c (vty_terminate_all): New function added for reload + support. + +1999-09-06 Kunihiro Ishiguro + + * memory.h (enum): Add new type MTYPE_OSPF_EXTERNAL_ROUTE. + +1999-08-31 Janos Farkas + + * vty.c (vty_read): Handle also 0x7f (alt-backspace), just like + esc-ctrl-h (delete word backwards). + +1999-08-24 Kunihiro Ishiguro + + * if.h: Add if_nametoindex for NRL. + +1999-08-23 Kunihiro Ishiguro + + * if.c (if_create): New function. + +1999-08-22 Kunihiro Ishiguro + + * snmp.c: New file. + +1999-08-21 Kunihiro Ishiguro + + * stream.c (stream_put): stream_memcpy () is changed to stream_put + (). stream_get () is added. + +1999-08-18 Toshiaki Takada + + * memory.h (enum): Add MTYPE_OSPF_LSA_DATA. + +1999-08-18 Yasuhiro Ohara + + * table.c (route_table_finish): add function frees table. + +1999-08-12 Kunihiro Ishiguro + + * memory.h (enum): Add MTYPE_RTADV_PREFIX. + +1999-08-11 Kunihiro Ishiguro + + * if.h (struct interface ): hw_address, hw_address_len added. + +1999-08-10 Kunihiro Ishiguro + + * if.h (struct interface ): Change structure member if_data to + info, index to ifindex. + +1999-08-08 Rick Payne + + * routemap.c: Multi protocol route-map modification. + + * routemap.c (route_map_apply): Route match process bug is fixed. + +1999-08-05 Kunihiro Ishiguro + + * thread.c (thread_fetch): When signal comes, goto retry point. + +1999-08-04 Kunihiro Ishiguro + + * Makefile.am: Add sockopt.c and sockopt.h + * sockopt.c: New file. + * sockopt.h: New file. + +1999-08-02 Kunihiro Ishiguro + + * version.h (ZEBRA_VERSION): Release zebra-0.75 + +1999-08-01 Kunihiro Ishiguro + + * memory.h (enum): Add MTYPE_RIPNG_AGGREGATE. + +1999-07-31 Kunihiro Ishiguro + + * sockunion.h: Add sockunion_getpeername (). + +1999-07-27 Kunihiro Ishiguro + + * version.h: Release zebra-0.74 + +1999-07-26 Kunihiro Ishiguro + + * command.h (struct host): Delete lines from struct host. Add + lines to struct vty. + + * command.c: Delete `lines LINES'. Terminal display line settings + should be done by `terminal length' command. + +1999-07-24 Kunihiro Ishiguro + + * memory.h (enum): MTYPE_OSPF_PATH are added. + +1999-07-22 Toshiaki Takada + + * memory.h (enum): MTYPE_OSPF_NEXTHOP is added. + +1999-07-21 Toshiaki Takada + + * linklist.c (list_add_node_prev), (list_add_node_next), + (list_add_list): New function added. + + * table.c (route_table_free): New function added. + +1999-07-21 Kunihiro Ishiguro + + * plist.c (config_write_prefix): Set write flag when configuration + is written. + +1999-07-15 Yasuhiro Ohara + + * prefix.c : prefix_cmp() added. change apply_mask() to + apply_mask_ipv4(), and new apply_mask() added. + +1999-07-14 Yasuhiro Ohara + + * prefix.c (prefix2str): append prefixlen. + +1999-07-13 Kunihiro Ishiguro + + * command.c (config_terminal): Change "config terminal" to + "configure terminal". Reported by Georg Hitsch + . + (config_terminal_length): `terminal length <0-512>' is added. At + this moment this command is only usef for vty interface. + Suggested by Georg Hitsch . + +1999-07-12 Kunihiro Ishiguro + + * routemap.c (rulecmp): Add wrapper function of strcmp. + +1999-07-08 Rick Payne + + * sockunion.c (inet_aton): Fix bug of inet_aton. + +1999-07-08 Kunihiro Ishiguro + + * version.h (ZEBRA_VERSION): Start zebra-0.73 + +1999-07-06 Kunihiro Ishiguro + + * version.h: Bump up to 0.72. + +1999-07-05 Kunihiro Ishiguro + + * command.c (install_default): New function for install default + commands to the node. + + * memory.h (enum): MTYPE_NEXTHOP is added. + +1999-07-01 + + * command.c (no_banner_motd): `no banner motd' command added. + +1999-06-30 Kunihiro Ishiguro + + * regex.c: Update to glibc-2.1.1's posix/regex.c + + * regex-gnu.h: Update to glibc-2.1.1's posix/regex.h + + * prefix.h (IPV4_ADDR_SAME): Macro added. + (IPV6_ADDR_SAME): Likewise. + +1999-06-29 Kunihiro Ishiguro + + * memory.h (enum): Add MTYPE_OSPF_VERTEX + + * version.h: Bump up to 0.71. + + * vty.c (vty_serv_sock_addrinfo): Use addrinfo function to bind + VTY socket when IPv6 is enabled. + +1999-06-28 Kunihiro Ishiguro + + * vty.c (vty_serv_sock): Change vty_serv_sock determine which + address family to bind. + + * command.c: Add quit command. + +1999-06-26 NOGUCHI kay + + * vty.c (vty_read_config): Fix bug of configuration file path + detection. + +1999-06-25 Kunihiro Ishiguro + + * version.h: Bump up to 0.70. + +1999-06-17 Kunihiro Ishiguro + + * buffer.h (GETL): Remove GETL macro. + + * version.h: Bump up to 0.69. + +1999-06-14 Kunihiro Ishiguro + + * if.c (connected_add): Commented out connected_log. + +1999-06-13 Kunihiro Ishiguro + + * command.h (struct cmd_element ): strvec and descvec is combined + into newstrvec. + + * command.c (desc_make): Function removed. + (desc_next): Function removed. + + * command.h (struct cmd_element ): docvec is removed from struct + cmd_element. + +1999-06-12 Kunihiro Ishiguro + + * command.c (cmd_execute_command): Remove command NULL check. + + * command.h (struct cmd_element ): Add newstrvec entry to struct + cmd_element. + (DEFUN2): DEFUN2 macro is removed. DEFUN is extended to support + (a|b|c) statement. + (DESC): DESC macro is removed. + + * vty.c (vty_complete_command): When return value is + CMD_ERR_NO_MATCH, don't display error message. + +1999-06-08 Kunihiro Ishiguro + + * table.c (route_next_until): New function. + + * version.h: Bump up to 0.68. + +1999-06-06 Kunihiro Ishiguro + + * vty.c (vty_close): Free vty->buf when vty is closed. + + * memory.h (enum): Add MTYPE_COMMUNITY_ENTRY and + MTYPE_COMMUNITY_LIST. + + * vty.h (struct vty ): Change buf from static length buffer to + variable length buffer. + + * vty.c (vty_ensure): New function added. + +1999-06-04 Kunihiro Ishiguro + + * command.h (node_type ): Add COMMUNITY_LIST_NODE. + + * command.c (config_enable_password): Freeing host.enable bug is + fixed. + (config_enable_password): Add argc count check. + +1999-05-31 Kunihiro Ishiguro + + * version.h: Bump up to 0.67. + +1999-05-30 Kunihiro Ishiguro + + * command.c (zencrypt): New function for encrypt password. + + * command.h (struct host): Add password_encrypt and + enable_encrypt. + +1999-05-30 Jochen Friedrich + + * command.h (struct host): New member encrypt is added for + encrypted password. + +1999-05-30 Kunihiro Ishiguro + + * vty.c: Remove all_digit_check function. Instead use all_digit. + + * prefix.c (all_digit): New function for checking string is made + from digit character. + +1999-05-25 Kunihiro Ishiguro + + * Makefile.am (libzebra_a_SOURCES): Add zclient.c. + (noinst_HEADERS): Add zclient.h + + * zclient.[ch]: New file for zebra client routine. + + * memory.h (enum): Add MTYPE_ZEBRA. + +1999-05-19 Kunihiro Ishiguro + + * version.h (ZEBRA_VERSION): Update to 0.66. + +1999-05-15 Kunihiro Ishiguro + + * buffer.h (GETC,GETW): Macro deleted. + +1999-05-15 Carlos Alberto Barcenilla + + * prefix.h (IPV4_NET0, IPV4_NET127): Macro added. + +1999-05-15 Kunihiro Ishiguro + + * vty.c (service_advanced_vty): New command added. + (no_service_advanced_vty): Likewise. + +1999-05-14 Kunihiro Ishiguro + + * vty.c (vty_auth): If advanced flag is set and enable password is + not set, directly login to the ENABLE_NODE. This feature is + originally designed and implemented by Stephen R. van den Berg + . + + * command.h (host): Add advanced flag to struct host for advanced + vty terminal interface. + + * version.h (ZEBRA_VERSION): Update to 0.65 for next beta release. + +1999-05-14 Stephen R. van den Berg + + * command.h (node_type ): Add TABLE_NODE. + + * vty.c (vty_telnet_option): Check host.lines value. + + * command.c (config_lines): DEFUN for 'lines LINES' command. + + * zebra.h: Include for uname(). + (RT_TABLE_MAIN): Defined as 0 if OS does not support multiple + routing table. + + * vty.c (vty_auth): Directly login to the ENABLE_NODE when enable + password is not set. + (vty_prompt): Get machine's hostname when hostname is not set. + +1999-05-11 James Willard + + * command.c (config_exit): Close connection when `exit' command is + executed at ENABLE_NODE. + +1999-05-10 Kunihiro Ishiguro + + * vty.c (vty_stop_input): `C-c' key change node to ENABLE_NODE. + + * command.c (cmd_execute_command_strict): Matched command size + check added. + (cmd_make_desc_line): New function for DEFUN2. + + * command.h (struct cmd_element ): Add descsize. + +1999-05-09 Kunihiro Ishiguro + + * command.h (struct cmd_element ): Remame descvec to docvec. + (struct cmd_element ): Add descvec for new description system. + + * command.c (desc_make): Check cmd->descvec. + +1999-05-06 Kunihiro Ishiguro + + * memory.h (enum): Add MTYPE_CLUSTER, MTYPE_CLUSTER_VAL. + +1999-05-05 Kunihiro Ishiguro + + * version.h (ZEBRA_VERSION): Bump up to 0.64 for next beta + release. + +1999-05-04 Yasuhiro Ohara + + * linklist.c (list_delete_all_node): bug fix. + previous code loses current position when node + is deleted. + +1999-05-03 Kunihiro Ishiguro + + * command.h (DESC): Macro added. + (struct cmd_element2): Delete struct cmd_element2. + + * plist.c (prefix_list): Sequential number option check is added. + +1999-05-02 Yasuhiro Ohara + + * log.c (zvlog_{debug,info,notice,warn,err}): have been + added. now we can log both console and file, but still + need some fix about config write. + +1999-05-02 Kunihiro Ishiguro + + * log.c (zvlog_debug): Fix yasu's change. + +1999-05-01 Kunihiro Ishiguro + + * plist.c (prefix_list): Fix typo. + +1999-04-30 Kunihiro Ishiguro + + * Set version to 0.63 for first beta package. + +1999-04-27 Carlos Barcenilla + + * prefix.c (str2prefix_ipv4): Fix prefix length check. + (str2prefix_ipv6): Likewise. + +1999-04-25 Kunihiro Ishiguro + + * memory.h (enum): Add MTPYE_PREFIX_LIST and + MTYPE_PREFIX_LIST_ENTRY. + + * command.h (node_type ): Add PREFIX_NODE. + +1999-04-25 Carlos Barcenilla + + * command.c: ALIAS (config_write_memory_cmd) and ALIAS + (copy_runningconfig_startupconfig_cmd) is added. + + * table.c (route_node_lookup): Unused match variable deletion. + +1999-04-24 Kunihiro Ishiguro + + * Makefile.am (libzebra_a_SOURCES): plist.c added. + (noinst_HEADERS): plist.h added. + + * plist.c, plist.h: New file added. + + * memory.h (enum): Rename MTYPE_AS_PASN to MTYPE_AS_STR. + * memory.c: Likewise. + +1999-04-19 Carlos Alberto Barcenilla + + * command.c (show_version): `show version' command added. + +1999-04-19 Kunihiro Ishiguro + + * prefix.c (str2prefix_ipv6): Prefix length overflow check. + +1999-04-19 Carlos Alberto Barcenilla + + * prefix.c (str2prefix_ipv4): Prefix length overflow check. + +1999-04-19 Alex Bligh + + * prefix.c (sockunion2hostprefix): Function added. + (sockunion2prefix): Address family was not set. Now it is set. + + * vty.c: VTY access-class command is added. + +1999-04-18 Kunihiro Ishiguro + + * memory.c: Change xmalloc to zmalloc. xcalloc, xrealloc, xfree, + xstrdup are likewise. + +1999-04-18 Yasuhiro Ohara + + * thread.c: Add thread_execute for other routing daemon. + OSPF tasks need to be generated by "sheduled" and "executed". + +1999-04-13 Kunihiro Ishiguro + + * buffer.c: Rewrite buffer_write and buffer_flush related + functions for fixing bugs. Reason of the problem and fix is + suggested by Alex Bligh . + +1999-04-12 Alex Bligh + + * command.c (cmd_entry_function_descr): Added for variable + argument help display. + +1999-04-07 Kunihiro Ishiguro + + * regex.c, regex-gnu.h: Imported from GNU sed-3.02 distribution. + +1999-03-24 Kunihiro Ishiguro + + * stream.c: stream_fifo_free bug is fixed. + +1999-03-19 Toshiaki Takada + + * stream.c (stream_strncpy): Added for getting any length bytes + from stream. + +1999-03-16 Kunihiro Ishiguro + + * version.h (ZEBRA_BUG_ADDRESS): New macro added. + +1999-03-14 Kunihiro Ishiguro + + * buffer.c (buffer_flush_window): If ep is same as buffer's size + length and lp is overrun one octet. + +1999-03-13 Kunihiro Ishiguro + + * vty.h: add VTY's timeout function. + +1999-03-05 + + * command.h (node_type ): Add OSPF6_node. + +1999-03-04 Kunihiro Ishiguro + + * zebra.h: Check HAVE_SYS_SELECT_H when include + +1999-03-03 Jeroen Ruigrok/Asmodai + + * zebra.h: Include if it exists. + +1999-03-02 Kunihiro Ishiguro + + * getopt.[ch],getopt1.c: Sync with glibc-2.1. + + * log.c (zlog): Tempolary ZLOG_STDOUT feature added. + + * command.h: Include vector.h and vty.h + +1999-02-25 Kunihiro Ishiguro + + * routemap.h (struct route_map_rule_cmd): Add prefix arguemnt. + + * routemap.c (route_map_apply_index): Add prefix argument. + (route_map_apply): Likewise. + + * memory.h (enum): Add MTYPE_ROUTE_MAP_COMPILED. + + * stream.c: Add stream_fifo related functions. + +1999-02-24 Kunihiro Ishiguro + + * daemon.c: Return integer value. File descriptor close is added. + + * memory.h (enum): add MTYPE_OSPF_LSA. + +1999-02-23 Kunihiro Ishiguro + + * rsh.c: Remove empty file. + +1999-02-22 + + * routemap.c: Add add/delete hook to route_map_master. + +1999-02-19 Peter Galbavy + + * str.[ch] added to supply wrappers for snprintf(), strlcat() and + strlcpy on system without these. + +1999-02-18 Peter Galbavy + + * syslog support added + +1999-02-02 Kunihiro Ishiguro + + * filter.c (access_list_add_hook): added for hook function management. + * filter.c (access_list_delete_hook): Likewise. + +1999-01-19 Kunihiro Ishiguro + + * stream.c: New file. + * stream.h: New file. + * Divide stream related fucntions from buffer.[ch] into stream.[ch]. + +1999-01-14 Kunihiro Ishiguro + + * memory.h (enum): add MTYPE_STREAM, MTYPE_STREAM_DATA + + * buffer.c (stream_new): Set MTYPE_STREAM to XMALLOC argument. + +1998-12-23 Kunihiro Ishiguro + + * routemap.c: route_map_index_delete() added. + +1998-12-22 Kunihiro Ishiguro + + * buffer.c (buffer_empty): check cp instead of sp. + +1998-12-17 Kunihiro Ishiguro + + * radix.[ch]: Deleted. + +1998-12-15 Magnus Ahltorp + + * buffer.c: Prototype fixes. + * prefix.c: Likewise. + * sockunion.c: Likewise. + * sockunion.h: Likewise. + +1998-12-14 Kunihiro Ishiguro + + * vty.c (vty_read): DELETE key works as vty_delete_char. + +1998-12-13 Kunihiro Ishiguro + + * log.c (time_print): chane %y to %Y. + +1998-12-10 Kunihiro Ishiguro + + * distribute.c: new file. + +1998-12-09 Kunihiro Ishiguro + + * filter.c: Remove all of struct prefix_{ipv4,ipv6} and add + complete support of IPv6 access list. + + * command.c (config_write_element): function delete. + (config_write_host): function add. password and enable password + isn't printed to vty interface. + +1998-12-08 Kunihiro Ishiguro + + * filter.c: Change prefix_ipv4 to prefix and add support of + prefix_ipv6 filtering. + +1998-12-07 Kunihiro Ishiguro + + * Makefile.am (INCLUDES): add @INCLUDES@ for Linux IPv6 inet6-apps + header includes. + +1998-12-05 Kunihiro Ishiguro + + * log.c (log_flush): fix function name typo. + +1998-12-04 Yasuhiro Ohara + + * memory.h: OSPF memory type is added. + +1998-11-15 Kunihiro Ishiguro + + * command.c (sort_node): add sort_node() for pretty printing of + command on vty interface. + (config_password): delete the restriction of charaster of password + string. + +1998-09-05 Kunihiro Ishiguro + + * prefix.c (prefix_ipv4_any): add prefix_ipv4_any(). + +1998-08-25 Kunihiro Ishiguro + + * network.h: New file. + +1998-08-24 Kunihiro Ishiguro + + * vty.c (vty_will_echo): function name change from vty_off_echo. + +1998-08-18 Kunihiro Ishiguro + + * buffer.h: add PUTC,PUTW,PUTL macros. + +1998-07-22 Kunihiro Ishiguro + + * route.[ch]: renamed to prefix.[ch] + +1998-06-09 Kunihiro Ishiguro + + * prefix_in, prefix_in6 is replaced by prefix_ipv4, prefix_ipv6. + + * Makefile.am: @INCLUDES@ is deleted from INCLUDES. + +1998-06-07 Kunihiro Ishiguro + + * host.[ch]: merged with command.[ch] + +1998-05-08 Kunihiro Ishiguro + + * Makefile.am (libzebra_a_SOURCES): add route.c to libzebra_a_SOURCES. + +1998-05-07 Kunihiro Ishiguro + + * route.c (str2prefix): str2prefix () is gone. + +1998-05-03 Kunihiro Ishiguro + + * vty.c (vty_read_config): change CONDIR to SYSCONFDIR. + + * .cvsignore: add file. + + * memory.c (xerror): add arguent `type' and `size'. + + * socket.c: deleted. + +1998-05-02 Kunihiro Ishiguro + + * vector.c: malloc,free,realloc -> XMALLOC,XFREE,XREALLOC. + * linklist.c: same as above. + +1998-04-30 Kunihiro Ishiguro + + * filter.[ch]: added. + +1998-04-01 Kunihiro Ishiguro + + * vty.c (config_who): return CMD_SUCCESS + +1998-04-01 Jochen Friedrich + + * table.c (route_dump_node): route_dump_node is IPv6 specific + function so move #ifdef to the end of route_dump_node (). + +1998-03-05 "Hannes R. Boehm" + + * if.c: DEFUN(interface_desc) added. + +1998-03-05 Kunihiro Ishiguro + + * if.c: separated from ripd/rip_interface.c + +1998-03-04 Kunihiro Ishiguro + + * thread.[ch] : added. + +1998-02-14 Kunihiro Ishiguro + + * vty.c (vty_delete_char): fix size bug. + (vty_backward_pure_word): function added. + (vty_read): ESC + 'f' perform vty_forward_word. + (vty_read): ESC + 'b' perform vty_backward_word. + +1998-02-11 Kunihiro Ishiguro + + * radix.c (radix_lookup_rt): add mask check. + (radix_delete_duproute): add mask check. + +1998-02-10 Kunihiro Ishiguro + + * command.c (config_write_file): fix vty -> file_vty. + +1998-02-06 Kunihiro Ishiguro + + * command.c (cmd_filter_ambiguous): add complex type treatment. + +1998-02-05 Kunihiro Ishiguro + + * vty.c (vty_time_print): function added. + (vty_complete_command): now [...] element isn't shown by completion. + +1998-01-26 Kunihiro Ishiguro + + * command.c : change from cmd_install_node() to install_node(). + +1998-01-16 Kunihiro Ishiguro + + * route.[ch]: struct rt{} is replaced by struct prefix{}. + +1998-01-06 Kunihiro Ishiguro + + * command.c (cmd_execute_command): check command length. + + * timer.c (zebra_timer_set): add zebra_timer_set. + +1998-01-05 Kunihiro Ishiguro + + * command.h (node_type ): add ZEBRA_NODE. + + * command.c (config_exit): add RIP_NODE. + (config_write_file): add RIP_NODE. + +1998-01-04 Kunihiro Ishiguro + + * print_version.c (print_version): Now Copyright is 1996-1998. + + * sockunion.c (sockunion_log): moved from ../zebra/route.c + +1997-12-30 Kunihiro Ishiguro + + * host.c (config_logfile): change 'log PATH' to 'logfile PATH'. + + * sockunion.c (sockunion_sameprefix): add same prefix for + sockunion. + +1997-12-29 Kunihiro Ishiguro + + * radix.[ch] : are moved from ../zebra directroy. + + * command.c (config_from_file): if command execution failed down + level to CONFIG_NODE. + + * host.c: config_log function which enable 'log FILENAME' command. + +1997-12-23 Kunihiro Ishiguro + + * vty.c: add vty_transpose_chars (). Now you can use '^T' to + transpose character. + + * command.c: cmd_cmdsize add, this is useful to check incomplete + command. + +1997-12-07 Kunihiro Ishiguro + + * fd.h: add family for address family + +1997-12-06 Kunihiro Ishiguro + + * command.o + * vty.o + * host.o is moved from ../zebra + +1997-08-14 Kunihiro Ishiguro + + * make library directory. + diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 00000000..81f1e41e --- /dev/null +++ b/lib/Makefile.am @@ -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 index 00000000..d821f238 --- /dev/null +++ b/lib/Makefile.in @@ -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 index 00000000..de51ee3e --- /dev/null +++ b/lib/buffer.c @@ -0,0 +1,568 @@ +/* + * Buffering of output and input. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "memory.h" +#include "buffer.h" + +/* Make buffer data. */ +struct buffer_data * +buffer_data_new (size_t size) +{ + struct buffer_data *d; + + d = XMALLOC (MTYPE_BUFFER_DATA, sizeof (struct buffer_data)); + memset (d, 0, sizeof (struct buffer_data)); + d->data = XMALLOC (MTYPE_BUFFER_DATA, size); + + return d; +} + +void +buffer_data_free (struct buffer_data *d) +{ + if (d->data) + XFREE (MTYPE_BUFFER_DATA, d->data); + XFREE (MTYPE_BUFFER_DATA, d); +} + +/* Make new buffer. */ +struct buffer * +buffer_new (size_t size) +{ + struct buffer *b; + + b = XMALLOC (MTYPE_BUFFER, sizeof (struct buffer)); + memset (b, 0, sizeof (struct buffer)); + + b->size = size; + + return b; +} + +/* Free buffer. */ +void +buffer_free (struct buffer *b) +{ + struct buffer_data *d; + struct buffer_data *next; + + d = b->head; + while (d) + { + next = d->next; + buffer_data_free (d); + d = next; + } + + d = b->unused_head; + while (d) + { + next = d->next; + buffer_data_free (d); + d = next; + } + + XFREE (MTYPE_BUFFER, b); +} + +/* Make string clone. */ +char * +buffer_getstr (struct buffer *b) +{ + return strdup ((char *)b->head->data); +} + +/* Return 1 if buffer is empty. */ +int +buffer_empty (struct buffer *b) +{ + if (b->tail == NULL || b->tail->cp == b->tail->sp) + return 1; + else + return 0; +} + +/* Clear and free all allocated data. */ +void +buffer_reset (struct buffer *b) +{ + struct buffer_data *data; + struct buffer_data *next; + + for (data = b->head; data; data = next) + { + next = data->next; + buffer_data_free (data); + } + b->head = b->tail = NULL; + b->alloc = 0; + b->length = 0; +} + +/* Add buffer_data to the end of buffer. */ +void +buffer_add (struct buffer *b) +{ + struct buffer_data *d; + + d = buffer_data_new (b->size); + + if (b->tail == NULL) + { + d->prev = NULL; + d->next = NULL; + b->head = d; + b->tail = d; + } + else + { + d->prev = b->tail; + d->next = NULL; + + b->tail->next = d; + b->tail = d; + } + + b->alloc++; +} + +/* Write data to buffer. */ +int +buffer_write (struct buffer *b, u_char *ptr, size_t size) +{ + struct buffer_data *data; + + data = b->tail; + b->length += size; + + /* We use even last one byte of data buffer. */ + while (size) + { + /* If there is no data buffer add it. */ + if (data == NULL || data->cp == b->size) + { + buffer_add (b); + data = b->tail; + } + + /* Last data. */ + if (size <= (b->size - data->cp)) + { + memcpy ((data->data + data->cp), ptr, size); + + data->cp += size; + size = 0; + } + else + { + memcpy ((data->data + data->cp), ptr, (b->size - data->cp)); + + size -= (b->size - data->cp); + ptr += (b->size - data->cp); + + data->cp = b->size; + } + } + return 1; +} + +/* Insert character into the buffer. */ +int +buffer_putc (struct buffer *b, u_char c) +{ + buffer_write (b, &c, 1); + return 1; +} + +/* Insert word (2 octets) into ther buffer. */ +int +buffer_putw (struct buffer *b, u_short c) +{ + buffer_write (b, (char *)&c, 2); + return 1; +} + +/* Put string to the buffer. */ +int +buffer_putstr (struct buffer *b, u_char *c) +{ + size_t size; + + size = strlen ((char *)c); + buffer_write (b, c, size); + return 1; +} + +/* Flush specified size to the fd. */ +void +buffer_flush (struct buffer *b, int fd, size_t size) +{ + int iov_index; + struct iovec *iovec; + struct buffer_data *data; + struct buffer_data *out; + struct buffer_data *next; + + iovec = malloc (sizeof (struct iovec) * b->alloc); + iov_index = 0; + + for (data = b->head; data; data = data->next) + { + iovec[iov_index].iov_base = (char *)(data->data + data->sp); + + if (size <= (data->cp - data->sp)) + { + iovec[iov_index++].iov_len = size; + data->sp += size; + if (data->sp == data->cp) + data = data->next; + break; + } + else + { + iovec[iov_index++].iov_len = data->cp - data->sp; + size -= data->cp - data->sp; + data->sp = data->cp; + } + } + + /* Write buffer to the fd. */ + writev (fd, iovec, iov_index); + + /* Free printed buffer data. */ + for (out = b->head; out && out != data; out = next) + { + next = out->next; + if (next) + next->prev = NULL; + else + b->tail = next; + b->head = next; + + buffer_data_free (out); + b->alloc--; + } + + free (iovec); +} + +/* Flush all buffer to the fd. */ +int +buffer_flush_all (struct buffer *b, int fd) +{ + int ret; + struct buffer_data *d; + int iov_index; + struct iovec *iovec; + + if (buffer_empty (b)) + return 0; + + iovec = malloc (sizeof (struct iovec) * b->alloc); + iov_index = 0; + + for (d = b->head; d; d = d->next) + { + iovec[iov_index].iov_base = (char *)(d->data + d->sp); + iovec[iov_index].iov_len = d->cp - d->sp; + iov_index++; + } + ret = writev (fd, iovec, iov_index); + + free (iovec); + + buffer_reset (b); + + return ret; +} + +/* Flush all buffer to the fd. */ +int +buffer_flush_vty_all (struct buffer *b, int fd, int erase_flag, + int no_more_flag) +{ + int nbytes; + int iov_index; + struct iovec *iov; + struct iovec small_iov[3]; + char more[] = " --More-- "; + char erase[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}; + struct buffer_data *data; + struct buffer_data *out; + struct buffer_data *next; + + /* For erase and more data add two to b's buffer_data count.*/ + if (b->alloc == 1) + iov = small_iov; + else + iov = XCALLOC (MTYPE_TMP, sizeof (struct iovec) * (b->alloc + 2)); + + data = b->head; + iov_index = 0; + + /* Previously print out is performed. */ + if (erase_flag) + { + iov[iov_index].iov_base = erase; + iov[iov_index].iov_len = sizeof erase; + iov_index++; + } + + /* Output data. */ + for (data = b->head; data; data = data->next) + { + iov[iov_index].iov_base = (char *)(data->data + data->sp); + iov[iov_index].iov_len = data->cp - data->sp; + iov_index++; + } + + /* In case of `more' display need. */ + if (! buffer_empty (b) && !no_more_flag) + { + iov[iov_index].iov_base = more; + iov[iov_index].iov_len = sizeof more; + iov_index++; + } + + /* We use write or writev*/ + nbytes = writev (fd, iov, iov_index); + + /* Error treatment. */ + if (nbytes < 0) + { + if (errno == EINTR) + ; + if (errno == EWOULDBLOCK) + ; + } + + /* Free printed buffer data. */ + for (out = b->head; out && out != data; out = next) + { + next = out->next; + if (next) + next->prev = NULL; + else + b->tail = next; + b->head = next; + + buffer_data_free (out); + b->alloc--; + } + + if (iov != small_iov) + XFREE (MTYPE_TMP, iov); + + return nbytes; +} + +/* Flush buffer to the file descriptor. Mainly used from vty + interface. */ +int +buffer_flush_vty (struct buffer *b, int fd, int size, + int erase_flag, int no_more_flag) +{ + int nbytes; + int iov_index; + struct iovec *iov; + struct iovec small_iov[3]; + char more[] = " --More-- "; + char erase[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}; + struct buffer_data *data; + struct buffer_data *out; + struct buffer_data *next; + +#ifdef IOV_MAX + int iov_size; + int total_size; + struct iovec *c_iov; + int c_nbytes; +#endif /* IOV_MAX */ + + /* For erase and more data add two to b's buffer_data count.*/ + if (b->alloc == 1) + iov = small_iov; + else + iov = XCALLOC (MTYPE_TMP, sizeof (struct iovec) * (b->alloc + 2)); + + data = b->head; + iov_index = 0; + + /* Previously print out is performed. */ + if (erase_flag) + { + iov[iov_index].iov_base = erase; + iov[iov_index].iov_len = sizeof erase; + iov_index++; + } + + /* Output data. */ + for (data = b->head; data; data = data->next) + { + iov[iov_index].iov_base = (char *)(data->data + data->sp); + + if (size <= (data->cp - data->sp)) + { + iov[iov_index++].iov_len = size; + data->sp += size; + if (data->sp == data->cp) + data = data->next; + break; + } + else + { + iov[iov_index++].iov_len = data->cp - data->sp; + size -= (data->cp - data->sp); + data->sp = data->cp; + } + } + + /* In case of `more' display need. */ + if (!buffer_empty (b) && !no_more_flag) + { + iov[iov_index].iov_base = more; + iov[iov_index].iov_len = sizeof more; + iov_index++; + } + + /* We use write or writev*/ + +#ifdef IOV_MAX + /* IOV_MAX are normally defined in , Posix.1g. + example: Solaris2.6 are defined IOV_MAX size at 16. */ + c_iov = iov; + total_size = iov_index; + nbytes = 0; + + while( total_size > 0 ) + { + /* initialize write vector size at once */ + iov_size = ( total_size > IOV_MAX ) ? IOV_MAX : total_size; + + c_nbytes = writev (fd, c_iov, iov_size ); + + if( c_nbytes < 0 ) + { + if(errno == EINTR) + ; + ; + if(errno == EWOULDBLOCK) + ; + ; + nbytes = c_nbytes; + break; + + } + + nbytes += c_nbytes; + + /* move pointer io-vector */ + c_iov += iov_size; + total_size -= iov_size; + } +#else /* IOV_MAX */ + nbytes = writev (fd, iov, iov_index); + + /* Error treatment. */ + if (nbytes < 0) + { + if (errno == EINTR) + ; + if (errno == EWOULDBLOCK) + ; + } +#endif /* IOV_MAX */ + + /* Free printed buffer data. */ + for (out = b->head; out && out != data; out = next) + { + next = out->next; + if (next) + next->prev = NULL; + else + b->tail = next; + b->head = next; + + buffer_data_free (out); + b->alloc--; + } + + if (iov != small_iov) + XFREE (MTYPE_TMP, iov); + + return nbytes; +} + +/* Calculate size of outputs then flush buffer to the file + descriptor. */ +int +buffer_flush_window (struct buffer *b, int fd, int width, int height, + int erase, int no_more) +{ + unsigned long cp; + unsigned long size; + int lp; + int lineno; + struct buffer_data *data; + + if (height >= 2) + height--; + + /* We have to calculate how many bytes should be written. */ + lp = 0; + lineno = 0; + size = 0; + + for (data = b->head; data; data = data->next) + { + cp = data->sp; + + while (cp < data->cp) + { + if (data->data[cp] == '\n' || lp == width) + { + lineno++; + if (lineno == height) + { + cp++; + size++; + goto flush; + } + lp = 0; + } + cp++; + lp++; + size++; + } + } + + /* Write data to the file descriptor. */ + flush: + + return buffer_flush_vty (b, fd, size, erase, no_more); +} diff --git a/lib/buffer.h b/lib/buffer.h new file mode 100644 index 00000000..7449aa77 --- /dev/null +++ b/lib/buffer.h @@ -0,0 +1,77 @@ +/* + * Buffering to output and input. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_BUFFER_H +#define _ZEBRA_BUFFER_H + +/* Buffer master. */ +struct buffer +{ + /* Data list. */ + struct buffer_data *head; + struct buffer_data *tail; + + /* Current allocated data. */ + unsigned long alloc; + + /* Total length of buffer. */ + unsigned long size; + + /* For allocation. */ + struct buffer_data *unused_head; + struct buffer_data *unused_tail; + + /* Current total length of this buffer. */ + unsigned long length; +}; + +/* Data container. */ +struct buffer_data +{ + struct buffer *parent; + struct buffer_data *next; + struct buffer_data *prev; + + /* Acctual data stream. */ + unsigned char *data; + + /* Current pointer. */ + unsigned long cp; + + /* Start pointer. */ + unsigned long sp; +}; + +/* Buffer prototypes. */ +struct buffer *buffer_new (size_t); +int buffer_write (struct buffer *, u_char *, size_t); +void buffer_free (struct buffer *); +char *buffer_getstr (struct buffer *); +int buffer_putc (struct buffer *, u_char); +int buffer_putstr (struct buffer *, u_char *); +void buffer_reset (struct buffer *); +int buffer_flush_all (struct buffer *, int); +int buffer_flush_vty_all (struct buffer *, int, int, int); +int buffer_flush_window (struct buffer *, int, int, int, int, int); +int buffer_empty (struct buffer *); + +#endif /* _ZEBRA_BUFFER_H */ diff --git a/lib/checksum.c b/lib/checksum.c new file mode 100644 index 00000000..6a29cbac --- /dev/null +++ b/lib/checksum.c @@ -0,0 +1,47 @@ +/* + * Checksum routine for Internet Protocol family headers (C Version). + * + * Refer to "Computing the Internet Checksum" by R. Braden, D. Borman and + * C. Partridge, Computer Communication Review, Vol. 19, No. 2, April 1989, + * pp. 86-101, for additional details on computing this checksum. + */ + +#include + +int /* return checksum in low-order 16 bits */ +in_cksum(ptr, nbytes) +register u_short *ptr; +register int nbytes; +{ + register long sum; /* assumes long == 32 bits */ + u_short oddbyte; + register u_short answer; /* assumes u_short == 16 bits */ + + /* + * Our algorithm is simple, using a 32-bit accumulator (sum), + * we add sequential 16-bit words to it, and at the end, fold back + * all the carry bits from the top 16 bits into the lower 16 bits. + */ + + sum = 0; + while (nbytes > 1) { + sum += *ptr++; + nbytes -= 2; + } + + /* mop up an odd byte, if necessary */ + if (nbytes == 1) { + oddbyte = 0; /* make sure top half is zero */ + *((u_char *) &oddbyte) = *(u_char *)ptr; /* one byte only */ + sum += oddbyte; + } + + /* + * Add back carry outs from top 16 bits to low 16 bits. + */ + + sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */ + sum += (sum >> 16); /* add carry */ + answer = ~sum; /* ones-complement, then truncate to 16 bits */ + return(answer); +} diff --git a/lib/command.c b/lib/command.c new file mode 100644 index 00000000..8cbecce1 --- /dev/null +++ b/lib/command.c @@ -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 + +#include "command.h" +#include "memory.h" +#include "log.h" +#include "version.h" + +/* Command vector which includes some level of command lists. Normally + each daemon maintains each own cmdvec. */ +vector cmdvec; + +/* Host information structure. */ +struct host host; + +/* Default motd string. */ +char *default_motd = +"\r\n\ +Hello, this is zebra (version " ZEBRA_VERSION ").\r\n\ +Copyright 1996-2002 Kunihiro Ishiguro.\r\n\ +\r\n"; + +/* Standard command node structures. */ +struct cmd_node auth_node = +{ + AUTH_NODE, + "Password: ", +}; + +struct cmd_node view_node = +{ + VIEW_NODE, + "%s> ", +}; + +struct cmd_node auth_enable_node = +{ + AUTH_ENABLE_NODE, + "Password: ", +}; + +struct cmd_node enable_node = +{ + ENABLE_NODE, + "%s# ", +}; + +struct cmd_node config_node = +{ + CONFIG_NODE, + "%s(config)# ", + 1 +}; + +/* Utility function to concatenate argv argument into a single string + with inserting ' ' character between each argument. */ +char * +argv_concat (char **argv, int argc, int shift) +{ + int i; + int len; + int index; + char *str; + + str = NULL; + index = 0; + + for (i = shift; i < argc; i++) + { + len = strlen (argv[i]); + + if (i == shift) + { + str = XSTRDUP (MTYPE_TMP, argv[i]); + index = len; + } + else + { + str = XREALLOC (MTYPE_TMP, str, (index + len + 2)); + str[index++] = ' '; + memcpy (str + index, argv[i], len); + index += len; + str[index] = '\0'; + } + } + return str; +} + +/* Install top node of command vector. */ +void +install_node (struct cmd_node *node, + int (*func) (struct vty *)) +{ + vector_set_index (cmdvec, node->node, node); + node->func = func; + node->cmd_vector = vector_init (VECTOR_MIN_SIZE); +} + +/* Compare two command's string. Used in sort_node (). */ +int +cmp_node (const void *p, const void *q) +{ + struct cmd_element *a = *(struct cmd_element **)p; + struct cmd_element *b = *(struct cmd_element **)q; + + return strcmp (a->string, b->string); +} + +int +cmp_desc (const void *p, const void *q) +{ + struct desc *a = *(struct desc **)p; + struct desc *b = *(struct desc **)q; + + return strcmp (a->cmd, b->cmd); +} + +/* Sort each node's command element according to command string. */ +void +sort_node () +{ + int i, j; + struct cmd_node *cnode; + vector descvec; + struct cmd_element *cmd_element; + + for (i = 0; i < vector_max (cmdvec); i++) + if ((cnode = vector_slot (cmdvec, i)) != NULL) + { + vector cmd_vector = cnode->cmd_vector; + qsort (cmd_vector->index, cmd_vector->max, sizeof (void *), cmp_node); + + for (j = 0; j < vector_max (cmd_vector); j++) + if ((cmd_element = vector_slot (cmd_vector, j)) != NULL) + { + descvec = vector_slot (cmd_element->strvec, + vector_max (cmd_element->strvec) - 1); + qsort (descvec->index, descvec->max, sizeof (void *), cmp_desc); + } + } +} + +/* Breaking up string into each command piece. I assume given + character is separated by a space character. Return value is a + vector which includes char ** data element. */ +vector +cmd_make_strvec (char *string) +{ + char *cp, *start, *token; + int strlen; + vector strvec; + + if (string == NULL) + return NULL; + + cp = string; + + /* Skip white spaces. */ + while (isspace ((int) *cp) && *cp != '\0') + cp++; + + /* Return if there is only white spaces */ + if (*cp == '\0') + return NULL; + + if (*cp == '!' || *cp == '#') + return NULL; + + /* Prepare return vector. */ + strvec = vector_init (VECTOR_MIN_SIZE); + + /* Copy each command piece and set into vector. */ + while (1) + { + start = cp; + while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') && + *cp != '\0') + cp++; + strlen = cp - start; + token = XMALLOC (MTYPE_STRVEC, strlen + 1); + memcpy (token, start, strlen); + *(token + strlen) = '\0'; + vector_set (strvec, token); + + while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') && + *cp != '\0') + cp++; + + if (*cp == '\0') + return strvec; + } +} + +/* Free allocated string vector. */ +void +cmd_free_strvec (vector v) +{ + int i; + char *cp; + + if (!v) + return; + + for (i = 0; i < vector_max (v); i++) + if ((cp = vector_slot (v, i)) != NULL) + XFREE (MTYPE_STRVEC, cp); + + vector_free (v); +} + +/* Fetch next description. Used in cmd_make_descvec(). */ +char * +cmd_desc_str (char **string) +{ + char *cp, *start, *token; + int strlen; + + cp = *string; + + if (cp == NULL) + return NULL; + + /* Skip white spaces. */ + while (isspace ((int) *cp) && *cp != '\0') + cp++; + + /* Return if there is only white spaces */ + if (*cp == '\0') + return NULL; + + start = cp; + + while (!(*cp == '\r' || *cp == '\n') && *cp != '\0') + cp++; + + strlen = cp - start; + token = XMALLOC (MTYPE_STRVEC, strlen + 1); + memcpy (token, start, strlen); + *(token + strlen) = '\0'; + + *string = cp; + + return token; +} + +/* New string vector. */ +vector +cmd_make_descvec (char *string, char *descstr) +{ + int multiple = 0; + char *sp; + char *token; + int len; + char *cp; + char *dp; + vector allvec; + vector strvec = NULL; + struct desc *desc; + + cp = string; + dp = descstr; + + if (cp == NULL) + return NULL; + + allvec = vector_init (VECTOR_MIN_SIZE); + + while (1) + { + while (isspace ((int) *cp) && *cp != '\0') + cp++; + + if (*cp == '(') + { + multiple = 1; + cp++; + } + if (*cp == ')') + { + multiple = 0; + cp++; + } + if (*cp == '|') + { + if (! multiple) + { + fprintf (stderr, "Command parse error!: %s\n", string); + exit (1); + } + cp++; + } + + while (isspace ((int) *cp) && *cp != '\0') + cp++; + + if (*cp == '(') + { + multiple = 1; + cp++; + } + + if (*cp == '\0') + return allvec; + + sp = cp; + + while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0') + cp++; + + len = cp - sp; + + token = XMALLOC (MTYPE_STRVEC, len + 1); + memcpy (token, sp, len); + *(token + len) = '\0'; + + desc = XCALLOC (MTYPE_DESC, sizeof (struct desc)); + desc->cmd = token; + desc->str = cmd_desc_str (&dp); + + if (multiple) + { + if (multiple == 1) + { + strvec = vector_init (VECTOR_MIN_SIZE); + vector_set (allvec, strvec); + } + multiple++; + } + else + { + strvec = vector_init (VECTOR_MIN_SIZE); + vector_set (allvec, strvec); + } + vector_set (strvec, desc); + } +} + +/* Count mandantory string vector size. This is to determine inputed + command has enough command length. */ +int +cmd_cmdsize (vector strvec) +{ + int i; + char *str; + int size = 0; + vector descvec; + + for (i = 0; i < vector_max (strvec); i++) + { + descvec = vector_slot (strvec, i); + + if (vector_max (descvec) == 1) + { + struct desc *desc = vector_slot (descvec, 0); + + str = desc->cmd; + + if (str == NULL || CMD_OPTION (str)) + return size; + else + size++; + } + else + size++; + } + return size; +} + +/* Return prompt character of specified node. */ +char * +cmd_prompt (enum node_type node) +{ + struct cmd_node *cnode; + + cnode = vector_slot (cmdvec, node); + return cnode->prompt; +} + +/* Install a command into a node. */ +void +install_element (enum node_type ntype, struct cmd_element *cmd) +{ + struct cmd_node *cnode; + + cnode = vector_slot (cmdvec, ntype); + + if (cnode == NULL) + { + fprintf (stderr, "Command node %d doesn't exist, please check it\n", + ntype); + exit (1); + } + + vector_set (cnode->cmd_vector, cmd); + + cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc); + cmd->cmdsize = cmd_cmdsize (cmd->strvec); +} + +static unsigned char itoa64[] = +"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +void +to64(char *s, long v, int n) +{ + while (--n >= 0) + { + *s++ = itoa64[v&0x3f]; + v >>= 6; + } +} + +char *zencrypt (char *passwd) +{ + char salt[6]; + struct timeval tv; + char *crypt (const char *, const char *); + + gettimeofday(&tv,0); + + to64(&salt[0], random(), 3); + to64(&salt[3], tv.tv_usec, 3); + salt[5] = '\0'; + + return crypt (passwd, salt); +} + +/* This function write configuration of this host. */ +int +config_write_host (struct vty *vty) +{ + if (host.name) + vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE); + + if (host.encrypt) + { + if (host.password_encrypt) + vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE); + if (host.enable_encrypt) + vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE); + } + else + { + if (host.password) + vty_out (vty, "password %s%s", host.password, VTY_NEWLINE); + if (host.enable) + vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE); + } + + if (host.logfile) + vty_out (vty, "log file %s%s", host.logfile, VTY_NEWLINE); + + if (host.log_stdout) + vty_out (vty, "log stdout%s", VTY_NEWLINE); + + if (host.log_syslog) + vty_out (vty, "log syslog%s", VTY_NEWLINE); + + if (zlog_default->maskpri != LOG_DEBUG) + vty_out (vty, "log trap %s%s", zlog_priority[zlog_default->maskpri], VTY_NEWLINE); + + if (zlog_default->record_priority == 1) + vty_out (vty, "log record-priority%s", VTY_NEWLINE); + + if (host.advanced) + vty_out (vty, "service advanced-vty%s", VTY_NEWLINE); + + if (host.encrypt) + vty_out (vty, "service password-encryption%s", VTY_NEWLINE); + + if (host.lines >= 0) + vty_out (vty, "service terminal-length %d%s", host.lines, + VTY_NEWLINE); + + if (! host.motd) + vty_out (vty, "no banner motd%s", VTY_NEWLINE); + + return 1; +} + +/* Utility function for getting command vector. */ +vector +cmd_node_vector (vector v, enum node_type ntype) +{ + struct cmd_node *cnode = vector_slot (v, ntype); + return cnode->cmd_vector; +} + +/* Filter command vector by symbol */ +int +cmd_filter_by_symbol (char *command, char *symbol) +{ + int i, lim; + + if (strcmp (symbol, "IPV4_ADDRESS") == 0) + { + i = 0; + lim = strlen (command); + while (i < lim) + { + if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/')) + return 1; + i++; + } + return 0; + } + if (strcmp (symbol, "STRING") == 0) + { + i = 0; + lim = strlen (command); + while (i < lim) + { + if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-')) + return 1; + i++; + } + return 0; + } + if (strcmp (symbol, "IFNAME") == 0) + { + i = 0; + lim = strlen (command); + while (i < lim) + { + if (! isalnum ((int) command[i])) + return 1; + i++; + } + return 0; + } + return 0; +} + +/* Completion match types. */ +enum match_type +{ + no_match, + extend_match, + ipv4_prefix_match, + ipv4_match, + ipv6_prefix_match, + ipv6_match, + range_match, + vararg_match, + partly_match, + exact_match +}; + +enum match_type +cmd_ipv4_match (char *str) +{ + char *sp; + int dots = 0, nums = 0; + char buf[4]; + + if (str == NULL) + return partly_match; + + for (;;) + { + memset (buf, 0, sizeof (buf)); + sp = str; + while (*str != '\0') + { + if (*str == '.') + { + if (dots >= 3) + return no_match; + + if (*(str + 1) == '.') + return no_match; + + if (*(str + 1) == '\0') + return partly_match; + + dots++; + break; + } + if (!isdigit ((int) *str)) + return no_match; + + str++; + } + + if (str - sp > 3) + return no_match; + + strncpy (buf, sp, str - sp); + if (atoi (buf) > 255) + return no_match; + + nums++; + + if (*str == '\0') + break; + + str++; + } + + if (nums < 4) + return partly_match; + + return exact_match; +} + +enum match_type +cmd_ipv4_prefix_match (char *str) +{ + char *sp; + int dots = 0; + char buf[4]; + + if (str == NULL) + return partly_match; + + for (;;) + { + memset (buf, 0, sizeof (buf)); + sp = str; + while (*str != '\0' && *str != '/') + { + if (*str == '.') + { + if (dots == 3) + return no_match; + + if (*(str + 1) == '.' || *(str + 1) == '/') + return no_match; + + if (*(str + 1) == '\0') + return partly_match; + + dots++; + break; + } + + if (!isdigit ((int) *str)) + return no_match; + + str++; + } + + if (str - sp > 3) + return no_match; + + strncpy (buf, sp, str - sp); + if (atoi (buf) > 255) + return no_match; + + if (dots == 3) + { + if (*str == '/') + { + if (*(str + 1) == '\0') + return partly_match; + + str++; + break; + } + else if (*str == '\0') + return partly_match; + } + + if (*str == '\0') + return partly_match; + + str++; + } + + sp = str; + while (*str != '\0') + { + if (!isdigit ((int) *str)) + return no_match; + + str++; + } + + if (atoi (sp) > 32) + return no_match; + + return exact_match; +} + +#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%" +#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/" +#define STATE_START 1 +#define STATE_COLON 2 +#define STATE_DOUBLE 3 +#define STATE_ADDR 4 +#define STATE_DOT 5 +#define STATE_SLASH 6 +#define STATE_MASK 7 + +enum match_type +cmd_ipv6_match (char *str) +{ + int state = STATE_START; + int colons = 0, nums = 0, double_colon = 0; + char *sp = NULL; + + if (str == NULL) + return partly_match; + + if (strspn (str, IPV6_ADDR_STR) != strlen (str)) + return no_match; + + while (*str != '\0') + { + switch (state) + { + case STATE_START: + if (*str == ':') + { + if (*(str + 1) != ':' && *(str + 1) != '\0') + return no_match; + colons--; + state = STATE_COLON; + } + else + { + sp = str; + state = STATE_ADDR; + } + + continue; + case STATE_COLON: + colons++; + if (*(str + 1) == ':') + state = STATE_DOUBLE; + else + { + sp = str + 1; + state = STATE_ADDR; + } + break; + case STATE_DOUBLE: + if (double_colon) + return no_match; + + if (*(str + 1) == ':') + return no_match; + else + { + if (*(str + 1) != '\0') + colons++; + sp = str + 1; + state = STATE_ADDR; + } + + double_colon++; + nums++; + break; + case STATE_ADDR: + if (*(str + 1) == ':' || *(str + 1) == '\0') + { + if (str - sp > 3) + return no_match; + + nums++; + state = STATE_COLON; + } + if (*(str + 1) == '.') + state = STATE_DOT; + break; + case STATE_DOT: + state = STATE_ADDR; + break; + default: + break; + } + + if (nums > 8) + return no_match; + + if (colons > 7) + return no_match; + + str++; + } + +#if 0 + if (nums < 11) + return partly_match; +#endif /* 0 */ + + return exact_match; +} + +enum match_type +cmd_ipv6_prefix_match (char *str) +{ + int state = STATE_START; + int colons = 0, nums = 0, double_colon = 0; + int mask; + char *sp = NULL; + char *endptr = NULL; + + if (str == NULL) + return partly_match; + + if (strspn (str, IPV6_PREFIX_STR) != strlen (str)) + return no_match; + + while (*str != '\0' && state != STATE_MASK) + { + switch (state) + { + case STATE_START: + if (*str == ':') + { + if (*(str + 1) != ':' && *(str + 1) != '\0') + return no_match; + colons--; + state = STATE_COLON; + } + else + { + sp = str; + state = STATE_ADDR; + } + + continue; + case STATE_COLON: + colons++; + if (*(str + 1) == '/') + return no_match; + else if (*(str + 1) == ':') + state = STATE_DOUBLE; + else + { + sp = str + 1; + state = STATE_ADDR; + } + break; + case STATE_DOUBLE: + if (double_colon) + return no_match; + + if (*(str + 1) == ':') + return no_match; + else + { + if (*(str + 1) != '\0' && *(str + 1) != '/') + colons++; + sp = str + 1; + + if (*(str + 1) == '/') + state = STATE_SLASH; + else + state = STATE_ADDR; + } + + double_colon++; + nums += 1; + break; + case STATE_ADDR: + if (*(str + 1) == ':' || *(str + 1) == '.' + || *(str + 1) == '\0' || *(str + 1) == '/') + { + if (str - sp > 3) + return no_match; + + for (; sp <= str; sp++) + if (*sp == '/') + return no_match; + + nums++; + + if (*(str + 1) == ':') + state = STATE_COLON; + else if (*(str + 1) == '.') + state = STATE_DOT; + else if (*(str + 1) == '/') + state = STATE_SLASH; + } + break; + case STATE_DOT: + state = STATE_ADDR; + break; + case STATE_SLASH: + if (*(str + 1) == '\0') + return partly_match; + + state = STATE_MASK; + break; + default: + break; + } + + if (nums > 11) + return no_match; + + if (colons > 7) + return no_match; + + str++; + } + + if (state < STATE_MASK) + return partly_match; + + mask = strtol (str, &endptr, 10); + if (*endptr != '\0') + return no_match; + + if (mask < 0 || mask > 128) + return no_match; + +/* I don't know why mask < 13 makes command match partly. + Forgive me to make this comments. I Want to set static default route + because of lack of function to originate default in ospf6d; sorry + yasu + if (mask < 13) + return partly_match; +*/ + + return exact_match; +} + +#define DECIMAL_STRLEN_MAX 10 + +int +cmd_range_match (char *range, char *str) +{ + char *p; + char buf[DECIMAL_STRLEN_MAX + 1]; + char *endptr = NULL; + unsigned long min, max, val; + + if (str == NULL) + return 1; + + val = strtoul (str, &endptr, 10); + if (*endptr != '\0') + return 0; + + range++; + p = strchr (range, '-'); + if (p == NULL) + return 0; + if (p - range > DECIMAL_STRLEN_MAX) + return 0; + strncpy (buf, range, p - range); + buf[p - range] = '\0'; + min = strtoul (buf, &endptr, 10); + if (*endptr != '\0') + return 0; + + range = p + 1; + p = strchr (range, '>'); + if (p == NULL) + return 0; + if (p - range > DECIMAL_STRLEN_MAX) + return 0; + strncpy (buf, range, p - range); + buf[p - range] = '\0'; + max = strtoul (buf, &endptr, 10); + if (*endptr != '\0') + return 0; + + if (val < min || val > max) + return 0; + + return 1; +} + +/* Make completion match and return match type flag. */ +enum match_type +cmd_filter_by_completion (char *command, vector v, int index) +{ + int i; + char *str; + struct cmd_element *cmd_element; + enum match_type match_type; + vector descvec; + struct desc *desc; + + match_type = no_match; + + /* If command and cmd_element string does not match set NULL to vector */ + for (i = 0; i < vector_max (v); i++) + if ((cmd_element = vector_slot (v, i)) != NULL) + { + if (index >= vector_max (cmd_element->strvec)) + vector_slot (v, i) = NULL; + else + { + int j; + int matched = 0; + + descvec = vector_slot (cmd_element->strvec, index); + + for (j = 0; j < vector_max (descvec); j++) + { + desc = vector_slot (descvec, j); + str = desc->cmd; + + if (CMD_VARARG (str)) + { + if (match_type < vararg_match) + match_type = vararg_match; + matched++; + } + else if (CMD_RANGE (str)) + { + if (cmd_range_match (str, command)) + { + if (match_type < range_match) + match_type = range_match; + + matched++; + } + } + else if (CMD_IPV6 (str)) + { + if (cmd_ipv6_match (command)) + { + if (match_type < ipv6_match) + match_type = ipv6_match; + + matched++; + } + } + else if (CMD_IPV6_PREFIX (str)) + { + if (cmd_ipv6_prefix_match (command)) + { + if (match_type < ipv6_prefix_match) + match_type = ipv6_prefix_match; + + matched++; + } + } + else if (CMD_IPV4 (str)) + { + if (cmd_ipv4_match (command)) + { + if (match_type < ipv4_match) + match_type = ipv4_match; + + matched++; + } + } + else if (CMD_IPV4_PREFIX (str)) + { + if (cmd_ipv4_prefix_match (command)) + { + if (match_type < ipv4_prefix_match) + match_type = ipv4_prefix_match; + matched++; + } + } + else + /* Check is this point's argument optional ? */ + if (CMD_OPTION (str) || CMD_VARIABLE (str)) + { + if (match_type < extend_match) + match_type = extend_match; + matched++; + } + else if (strncmp (command, str, strlen (command)) == 0) + { + if (strcmp (command, str) == 0) + match_type = exact_match; + else + { + if (match_type < partly_match) + match_type = partly_match; + } + matched++; + } + } + if (! matched) + vector_slot (v, i) = NULL; + } + } + return match_type; +} + +/* Filter vector by command character with index. */ +enum match_type +cmd_filter_by_string (char *command, vector v, int index) +{ + int i; + char *str; + struct cmd_element *cmd_element; + enum match_type match_type; + vector descvec; + struct desc *desc; + + match_type = no_match; + + /* If command and cmd_element string does not match set NULL to vector */ + for (i = 0; i < vector_max (v); i++) + if ((cmd_element = vector_slot (v, i)) != NULL) + { + /* If given index is bigger than max string vector of command, + set NULL*/ + if (index >= vector_max (cmd_element->strvec)) + vector_slot (v, i) = NULL; + else + { + int j; + int matched = 0; + + descvec = vector_slot (cmd_element->strvec, index); + + for (j = 0; j < vector_max (descvec); j++) + { + desc = vector_slot (descvec, j); + str = desc->cmd; + + if (CMD_VARARG (str)) + { + if (match_type < vararg_match) + match_type = vararg_match; + matched++; + } + else if (CMD_RANGE (str)) + { + if (cmd_range_match (str, command)) + { + if (match_type < range_match) + match_type = range_match; + matched++; + } + } + else if (CMD_IPV6 (str)) + { + if (cmd_ipv6_match (command) == exact_match) + { + if (match_type < ipv6_match) + match_type = ipv6_match; + matched++; + } + } + else if (CMD_IPV6_PREFIX (str)) + { + if (cmd_ipv6_prefix_match (command) == exact_match) + { + if (match_type < ipv6_prefix_match) + match_type = ipv6_prefix_match; + matched++; + } + } + else if (CMD_IPV4 (str)) + { + if (cmd_ipv4_match (command) == exact_match) + { + if (match_type < ipv4_match) + match_type = ipv4_match; + matched++; + } + } + else if (CMD_IPV4_PREFIX (str)) + { + if (cmd_ipv4_prefix_match (command) == exact_match) + { + if (match_type < ipv4_prefix_match) + match_type = ipv4_prefix_match; + matched++; + } + } + else if (CMD_OPTION (str) || CMD_VARIABLE (str)) + { + if (match_type < extend_match) + match_type = extend_match; + matched++; + } + else + { + if (strcmp (command, str) == 0) + { + match_type = exact_match; + matched++; + } + } + } + if (! matched) + vector_slot (v, i) = NULL; + } + } + return match_type; +} + +/* Check ambiguous match */ +int +is_cmd_ambiguous (char *command, vector v, int index, enum match_type type) +{ + int i; + int j; + char *str = NULL; + struct cmd_element *cmd_element; + char *matched = NULL; + vector descvec; + struct desc *desc; + + for (i = 0; i < vector_max (v); i++) + if ((cmd_element = vector_slot (v, i)) != NULL) + { + int match = 0; + + descvec = vector_slot (cmd_element->strvec, index); + + for (j = 0; j < vector_max (descvec); j++) + { + enum match_type ret; + + desc = vector_slot (descvec, j); + str = desc->cmd; + + switch (type) + { + case exact_match: + if (! (CMD_OPTION (str) || CMD_VARIABLE (str)) + && strcmp (command, str) == 0) + match++; + break; + case partly_match: + if (! (CMD_OPTION (str) || CMD_VARIABLE (str)) + && strncmp (command, str, strlen (command)) == 0) + { + if (matched && strcmp (matched, str) != 0) + return 1; /* There is ambiguous match. */ + else + matched = str; + match++; + } + break; + case range_match: + if (cmd_range_match (str, command)) + { + if (matched && strcmp (matched, str) != 0) + return 1; + else + matched = str; + match++; + } + break; + case ipv6_match: + if (CMD_IPV6 (str)) + match++; + break; + case ipv6_prefix_match: + if ((ret = cmd_ipv6_prefix_match (command)) != no_match) + { + if (ret == partly_match) + return 2; /* There is incomplete match. */ + + match++; + } + break; + case ipv4_match: + if (CMD_IPV4 (str)) + match++; + break; + case ipv4_prefix_match: + if ((ret = cmd_ipv4_prefix_match (command)) != no_match) + { + if (ret == partly_match) + return 2; /* There is incomplete match. */ + + match++; + } + break; + case extend_match: + if (CMD_OPTION (str) || CMD_VARIABLE (str)) + match++; + break; + case no_match: + default: + break; + } + } + if (! match) + vector_slot (v, i) = NULL; + } + return 0; +} + +/* If src matches dst return dst string, otherwise return NULL */ +char * +cmd_entry_function (char *src, char *dst) +{ + /* Skip variable arguments. */ + if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) || + CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst)) + return NULL; + + /* In case of 'command \t', given src is NULL string. */ + if (src == NULL) + return dst; + + /* Matched with input string. */ + if (strncmp (src, dst, strlen (src)) == 0) + return dst; + + return NULL; +} + +/* If src matches dst return dst string, otherwise return NULL */ +/* This version will return the dst string always if it is + CMD_VARIABLE for '?' key processing */ +char * +cmd_entry_function_desc (char *src, char *dst) +{ + if (CMD_VARARG (dst)) + return dst; + + if (CMD_RANGE (dst)) + { + if (cmd_range_match (dst, src)) + return dst; + else + return NULL; + } + + if (CMD_IPV6 (dst)) + { + if (cmd_ipv6_match (src)) + return dst; + else + return NULL; + } + + if (CMD_IPV6_PREFIX (dst)) + { + if (cmd_ipv6_prefix_match (src)) + return dst; + else + return NULL; + } + + if (CMD_IPV4 (dst)) + { + if (cmd_ipv4_match (src)) + return dst; + else + return NULL; + } + + if (CMD_IPV4_PREFIX (dst)) + { + if (cmd_ipv4_prefix_match (src)) + return dst; + else + return NULL; + } + + /* Optional or variable commands always match on '?' */ + if (CMD_OPTION (dst) || CMD_VARIABLE (dst)) + return dst; + + /* In case of 'command \t', given src is NULL string. */ + if (src == NULL) + return dst; + + if (strncmp (src, dst, strlen (src)) == 0) + return dst; + else + return NULL; +} + +/* Check same string element existence. If it isn't there return + 1. */ +int +cmd_unique_string (vector v, char *str) +{ + int i; + char *match; + + for (i = 0; i < vector_max (v); i++) + if ((match = vector_slot (v, i)) != NULL) + if (strcmp (match, str) == 0) + return 0; + return 1; +} + +/* Compare string to description vector. If there is same string + return 1 else return 0. */ +int +desc_unique_string (vector v, char *str) +{ + int i; + struct desc *desc; + + for (i = 0; i < vector_max (v); i++) + if ((desc = vector_slot (v, i)) != NULL) + if (strcmp (desc->cmd, str) == 0) + return 1; + return 0; +} + +/* '?' describe command support. */ +vector +cmd_describe_command (vector vline, struct vty *vty, int *status) +{ + int i; + vector cmd_vector; +#define INIT_MATCHVEC_SIZE 10 + vector matchvec; + struct cmd_element *cmd_element; + int index; + static struct desc desc_cr = { "", "" }; + + /* 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 = ""; + 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, ©_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 index 00000000..3009b261 --- /dev/null +++ b/lib/command.h @@ -0,0 +1,308 @@ +/* + * Zebra configuration command interface routine + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_COMMAND_H +#define _ZEBRA_COMMAND_H + +#include "vector.h" +#include "vty.h" + +/* Host configuration variable */ +struct host +{ + /* Host name of this router. */ + char *name; + + /* Password for vty interface. */ + char *password; + char *password_encrypt; + + /* Enable password */ + char *enable; + char *enable_encrypt; + + /* System wide terminal lines. */ + int lines; + + /* Log filename. */ + char *logfile; + + /* Log stdout. */ + u_char log_stdout; + + /* Log syslog. */ + u_char log_syslog; + + /* config file name of this host */ + char *config; + + /* Flags for services */ + int advanced; + int encrypt; + + /* Banner configuration. */ + char *motd; +}; + +/* There are some command levels which called from command node. */ +enum node_type +{ + AUTH_NODE, /* Authentication mode of vty interface. */ + VIEW_NODE, /* View node. Default mode of vty interface. */ + AUTH_ENABLE_NODE, /* Authentication mode for change enable. */ + ENABLE_NODE, /* Enable node. */ + CONFIG_NODE, /* Config node. Default mode of config file. */ + DEBUG_NODE, /* Debug node. */ + AAA_NODE, /* AAA node. */ + KEYCHAIN_NODE, /* Key-chain node. */ + KEYCHAIN_KEY_NODE, /* Key-chain key node. */ + INTERFACE_NODE, /* Interface mode node. */ + ZEBRA_NODE, /* zebra connection node. */ + TABLE_NODE, /* rtm_table selection node. */ + RIP_NODE, /* RIP protocol mode node. */ + RIPNG_NODE, /* RIPng protocol mode node. */ + BGP_NODE, /* BGP protocol mode which includes BGP4+ */ + BGP_VPNV4_NODE, /* BGP MPLS-VPN PE exchange. */ + BGP_IPV4_NODE, /* BGP IPv4 unicast address family. */ + BGP_IPV4M_NODE, /* BGP IPv4 multicast address family. */ + BGP_IPV6_NODE, /* BGP IPv6 address family */ + OSPF_NODE, /* OSPF protocol mode */ + OSPF6_NODE, /* OSPF protocol for IPv6 mode */ + MASC_NODE, /* MASC for multicast. */ + IRDP_NODE, /* ICMP Router Discovery Protocol mode. */ + IP_NODE, /* Static ip route node. */ + ACCESS_NODE, /* Access list node. */ + PREFIX_NODE, /* Prefix list node. */ + ACCESS_IPV6_NODE, /* Access list node. */ + PREFIX_IPV6_NODE, /* Prefix list node. */ + AS_LIST_NODE, /* AS list node. */ + COMMUNITY_LIST_NODE, /* Community list node. */ + RMAP_NODE, /* Route map node. */ + SMUX_NODE, /* SNMP configuration node. */ + DUMP_NODE, /* Packet dump node. */ + FORWARDING_NODE, /* IP forwarding node. */ + VTY_NODE /* Vty node. */ +}; + +/* Node which has some commands and prompt string and configuration + function pointer . */ +struct cmd_node +{ + /* Node index. */ + enum node_type node; + + /* Prompt character at vty interface. */ + char *prompt; + + /* Is this node's configuration goes to vtysh ? */ + int vtysh; + + /* Node's configuration write function */ + int (*func) (struct vty *); + + /* Vector of this node's command list. */ + vector cmd_vector; +}; + +/* Structure of command element. */ +struct cmd_element +{ + char *string; /* Command specification by string. */ + int (*func) (struct cmd_element *, struct vty *, int, char **); + char *doc; /* Documentation of this command. */ + int daemon; /* Daemon to which this command belong. */ + vector strvec; /* Pointing out each description vector. */ + int cmdsize; /* Command index count. */ + char *config; /* Configuration string */ + vector subconfig; /* Sub configuration string */ +}; + +/* Command description structure. */ +struct desc +{ + char *cmd; /* Command string. */ + char *str; /* Command's description. */ +}; + +/* Return value of the commands. */ +#define CMD_SUCCESS 0 +#define CMD_WARNING 1 +#define CMD_ERR_NO_MATCH 2 +#define CMD_ERR_AMBIGUOUS 3 +#define CMD_ERR_INCOMPLETE 4 +#define CMD_ERR_EXEED_ARGC_MAX 5 +#define CMD_ERR_NOTHING_TODO 6 +#define CMD_COMPLETE_FULL_MATCH 7 +#define CMD_COMPLETE_MATCH 8 +#define CMD_COMPLETE_LIST_MATCH 9 +#define CMD_SUCCESS_DAEMON 10 + +/* Argc max counts. */ +#define CMD_ARGC_MAX 25 + +/* Turn off these macros when uisng cpp with extract.pl */ +#ifndef VTYSH_EXTRACT_PL + +/* DEFUN for vty command interafce. Little bit hacky ;-). */ +#define DEFUN(funcname, cmdname, cmdstr, helpstr) \ + int funcname (struct cmd_element *, struct vty *, int, char **); \ + struct cmd_element cmdname = \ + { \ + cmdstr, \ + funcname, \ + helpstr \ + }; \ + int funcname \ + (struct cmd_element *self, struct vty *vty, int argc, char **argv) + +/* DEFUN_NOSH for commands that vtysh should ignore */ +#define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \ + DEFUN(funcname, cmdname, cmdstr, helpstr) + +/* DEFSH for vtysh. */ +#define DEFSH(daemon, cmdname, cmdstr, helpstr) \ + struct cmd_element cmdname = \ + { \ + cmdstr, \ + NULL, \ + helpstr, \ + daemon \ + }; \ + +/* DEFUN + DEFSH */ +#define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \ + int funcname (struct cmd_element *, struct vty *, int, char **); \ + struct cmd_element cmdname = \ + { \ + cmdstr, \ + funcname, \ + helpstr, \ + daemon \ + }; \ + int funcname \ + (struct cmd_element *self, struct vty *vty, int argc, char **argv) + +/* ALIAS macro which define existing command's alias. */ +#define ALIAS(funcname, cmdname, cmdstr, helpstr) \ + struct cmd_element cmdname = \ + { \ + cmdstr, \ + funcname, \ + helpstr \ + }; + +#endif /* VTYSH_EXTRACT_PL */ + +/* Some macroes */ +#define CMD_OPTION(S) ((S[0]) == '[') +#define CMD_VARIABLE(S) (((S[0]) >= 'A' && (S[0]) <= 'Z') || ((S[0]) == '<')) +#define CMD_VARARG(S) ((S[0]) == '.') +#define CMD_RANGE(S) ((S[0] == '<')) + +#define CMD_IPV4(S) ((strcmp ((S), "A.B.C.D") == 0)) +#define CMD_IPV4_PREFIX(S) ((strcmp ((S), "A.B.C.D/M") == 0)) +#define CMD_IPV6(S) ((strcmp ((S), "X:X::X:X") == 0)) +#define CMD_IPV6_PREFIX(S) ((strcmp ((S), "X:X::X:X/M") == 0)) + +/* Common descriptions. */ +#define SHOW_STR "Show running system information\n" +#define IP_STR "IP information\n" +#define IPV6_STR "IPv6 information\n" +#define NO_STR "Negate a command or set its defaults\n" +#define CLEAR_STR "Reset functions\n" +#define RIP_STR "RIP information\n" +#define BGP_STR "BGP information\n" +#define OSPF_STR "OSPF information\n" +#define NEIGHBOR_STR "Specify neighbor router\n" +#define DEBUG_STR "Debugging functions (see also 'undebug')\n" +#define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n" +#define ROUTER_STR "Enable a routing process\n" +#define AS_STR "AS number\n" +#define MBGP_STR "MBGP information\n" +#define MATCH_STR "Match values from routing table\n" +#define SET_STR "Set values in destination routing protocol\n" +#define OUT_STR "Filter outgoing routing updates\n" +#define IN_STR "Filter incoming routing updates\n" +#define V4NOTATION_STR "specify by IPv4 address notation(e.g. 0.0.0.0)\n" +#define OSPF6_NUMBER_STR "Specify by number\n" +#define INTERFACE_STR "Interface infomation\n" +#define IFNAME_STR "Interface name(e.g. ep0)\n" +#define IP6_STR "IPv6 Information\n" +#define OSPF6_STR "Open Shortest Path First (OSPF) for IPv6\n" +#define OSPF6_ROUTER_STR "Enable a routing process\n" +#define OSPF6_INSTANCE_STR "<1-65535> Instance ID\n" +#define SECONDS_STR "<1-65535> Seconds\n" +#define ROUTE_STR "Routing Table\n" +#define PREFIX_LIST_STR "Build a prefix list\n" +#define OSPF6_DUMP_TYPE_LIST \ +"(neighbor|interface|area|lsa|zebra|config|dbex|spf|route|lsdb|redistribute|hook|asbr|prefix|abr)" + +#define CONF_BACKUP_EXT ".sav" + +/* IPv4 only machine should not accept IPv6 address for peer's IP + address. So we replace VTY command string like below. */ +#ifdef HAVE_IPV6 +#define NEIGHBOR_CMD "neighbor (A.B.C.D|X:X::X:X) " +#define NO_NEIGHBOR_CMD "no neighbor (A.B.C.D|X:X::X:X) " +#define NEIGHBOR_ADDR_STR "Neighbor address\nIPv6 address\n" +#define NEIGHBOR_CMD2 "neighbor (A.B.C.D|X:X::X:X|WORD) " +#define NO_NEIGHBOR_CMD2 "no neighbor (A.B.C.D|X:X::X:X|WORD) " +#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" +#else +#define NEIGHBOR_CMD "neighbor A.B.C.D " +#define NO_NEIGHBOR_CMD "no neighbor A.B.C.D " +#define NEIGHBOR_ADDR_STR "Neighbor address\n" +#define NEIGHBOR_CMD2 "neighbor (A.B.C.D|WORD) " +#define NO_NEIGHBOR_CMD2 "no neighbor (A.B.C.D|WORD) " +#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor tag\n" +#endif /* HAVE_IPV6 */ + +/* Prototypes. */ +void install_node (struct cmd_node *, int (*) (struct vty *)); +void install_default (enum node_type); +void install_element (enum node_type, struct cmd_element *); +void sort_node (); + +char *argv_concat (char **, int, int); +vector cmd_make_strvec (char *); +void cmd_free_strvec (vector); +vector cmd_describe_command (); +char **cmd_complete_command (); +char *cmd_prompt (enum node_type); +int config_from_file (struct vty *, FILE *); +int cmd_execute_command (vector, struct vty *, struct cmd_element **); +int cmd_execute_command_strict (vector, struct vty *, struct cmd_element **); +void config_replace_string (struct cmd_element *, char *, ...); +void cmd_init (int); + +/* Export typical functions. */ +extern struct cmd_element config_end_cmd; +extern struct cmd_element config_exit_cmd; +extern struct cmd_element config_quit_cmd; +extern struct cmd_element config_help_cmd; +extern struct cmd_element config_list_cmd; +int config_exit (struct cmd_element *, struct vty *, int, char **); +int config_help (struct cmd_element *, struct vty *, int, char **); +char *host_config_file (); +void host_config_set (char *); + +#endif /* _ZEBRA_COMMAND_H */ diff --git a/lib/daemon.c b/lib/daemon.c new file mode 100644 index 00000000..dfd26b36 --- /dev/null +++ b/lib/daemon.c @@ -0,0 +1,80 @@ +/* + * Daemonize routine + * Copyright (C) 1997, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#ifndef HAVE_DAEMON + +/* Daemonize myself. */ +int +daemon (int nochdir, int noclose) +{ + pid_t pid; + + pid = fork (); + + /* In case of fork is error. */ + if (pid < 0) + { + perror ("fork"); + return -1; + } + + /* In case of this is parent process. */ + if (pid != 0) + exit (0); + + /* Become session leader and get pid. */ + pid = setsid(); + + if (pid < -1) + { + perror ("setsid"); + return -1; + } + + /* Change directory to root. */ + if (! nochdir) + chdir ("/"); + + /* File descriptor close. */ + if (! noclose) + { + int fd; + + fd = open ("/dev/null", O_RDWR, 0); + if (fd != -1) + { + dup2 (fd, STDIN_FILENO); + dup2 (fd, STDOUT_FILENO); + dup2 (fd, STDERR_FILENO); + if (fd > 2) + close (fd); + } + } + + umask (0027); + + return 0; +} + +#endif /* HAVE_DAEMON */ diff --git a/lib/distribute.c b/lib/distribute.c new file mode 100644 index 00000000..d5893a5b --- /dev/null +++ b/lib/distribute.c @@ -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 + +#include "hash.h" +#include "if.h" +#include "filter.h" +#include "command.h" +#include "distribute.h" +#include "memory.h" + +/* Hash of distribute list. */ +struct hash *disthash; + +/* Hook functions. */ +void (*distribute_add_hook) (struct distribute *); +void (*distribute_delete_hook) (struct distribute *); + +struct distribute * +distribute_new () +{ + struct distribute *new; + + new = XMALLOC (MTYPE_DISTRIBUTE, sizeof (struct distribute)); + memset (new, 0, sizeof (struct distribute)); + + return new; +} + +/* Free distribute object. */ +void +distribute_free (struct distribute *dist) +{ + if (dist->ifname) + free (dist->ifname); + + if (dist->list[DISTRIBUTE_IN]) + free (dist->list[DISTRIBUTE_IN]); + if (dist->list[DISTRIBUTE_OUT]) + free (dist->list[DISTRIBUTE_OUT]); + + if (dist->prefix[DISTRIBUTE_IN]) + free (dist->prefix[DISTRIBUTE_IN]); + if (dist->prefix[DISTRIBUTE_OUT]) + free (dist->prefix[DISTRIBUTE_OUT]); + + XFREE (MTYPE_DISTRIBUTE, dist); +} + +/* Lookup interface's distribute list. */ +struct distribute * +distribute_lookup (char *ifname) +{ + struct distribute key; + struct distribute *dist; + + key.ifname = ifname; + + dist = hash_lookup (disthash, &key); + + return dist; +} + +void +distribute_list_add_hook (void (*func) (struct distribute *)) +{ + distribute_add_hook = func; +} + +void +distribute_list_delete_hook (void (*func) (struct distribute *)) +{ + distribute_delete_hook = func; +} + +void * +distribute_hash_alloc (struct distribute *arg) +{ + struct distribute *dist; + + dist = distribute_new (); + if (arg->ifname) + dist->ifname = strdup (arg->ifname); + else + dist->ifname = NULL; + return dist; +} + +/* Make new distribute list and push into hash. */ +struct distribute * +distribute_get (char *ifname) +{ + struct distribute key; + + key.ifname = ifname; + + return hash_get (disthash, &key, distribute_hash_alloc); +} + +unsigned int +distribute_hash_make (struct distribute *dist) +{ + unsigned int key; + int i; + + key = 0; + if (dist->ifname) + for (i = 0; i < strlen (dist->ifname); i++) + key += dist->ifname[i]; + + return key; +} + +/* If two distribute-list have same value then return 1 else return + 0. This function is used by hash package. */ +int +distribute_cmp (struct distribute *dist1, struct distribute *dist2) +{ + if (dist1->ifname && dist2->ifname) + if (strcmp (dist1->ifname, dist2->ifname) == 0) + return 1; + if (! dist1->ifname && ! dist2->ifname) + return 1; + return 0; +} + +/* Set access-list name to the distribute list. */ +struct distribute * +distribute_list_set (char *ifname, enum distribute_type type, char *alist_name) +{ + struct distribute *dist; + + dist = distribute_get (ifname); + + if (type == DISTRIBUTE_IN) + { + if (dist->list[DISTRIBUTE_IN]) + free (dist->list[DISTRIBUTE_IN]); + dist->list[DISTRIBUTE_IN] = strdup (alist_name); + } + if (type == DISTRIBUTE_OUT) + { + if (dist->list[DISTRIBUTE_OUT]) + free (dist->list[DISTRIBUTE_OUT]); + dist->list[DISTRIBUTE_OUT] = strdup (alist_name); + } + + /* Apply this distribute-list to the interface. */ + (*distribute_add_hook) (dist); + + return dist; +} + +/* Unset distribute-list. If matched distribute-list exist then + return 1. */ +int +distribute_list_unset (char *ifname, enum distribute_type type, + char *alist_name) +{ + struct distribute *dist; + + dist = distribute_lookup (ifname); + if (!dist) + return 0; + + if (type == DISTRIBUTE_IN) + { + if (!dist->list[DISTRIBUTE_IN]) + return 0; + if (strcmp (dist->list[DISTRIBUTE_IN], alist_name) != 0) + return 0; + + free (dist->list[DISTRIBUTE_IN]); + dist->list[DISTRIBUTE_IN] = NULL; + } + + if (type == DISTRIBUTE_OUT) + { + if (!dist->list[DISTRIBUTE_OUT]) + return 0; + if (strcmp (dist->list[DISTRIBUTE_OUT], alist_name) != 0) + return 0; + + free (dist->list[DISTRIBUTE_OUT]); + dist->list[DISTRIBUTE_OUT] = NULL; + } + + /* Apply this distribute-list to the interface. */ + (*distribute_delete_hook) (dist); + + /* If both out and in is NULL then free distribute list. */ + if (dist->list[DISTRIBUTE_IN] == NULL && + dist->list[DISTRIBUTE_OUT] == NULL && + dist->prefix[DISTRIBUTE_IN] == NULL && + dist->prefix[DISTRIBUTE_OUT] == NULL) + { + hash_release (disthash, dist); + distribute_free (dist); + } + + return 1; +} + +/* Set access-list name to the distribute list. */ +struct distribute * +distribute_list_prefix_set (char *ifname, enum distribute_type type, + char *plist_name) +{ + struct distribute *dist; + + dist = distribute_get (ifname); + + if (type == DISTRIBUTE_IN) + { + if (dist->prefix[DISTRIBUTE_IN]) + free (dist->prefix[DISTRIBUTE_IN]); + dist->prefix[DISTRIBUTE_IN] = strdup (plist_name); + } + if (type == DISTRIBUTE_OUT) + { + if (dist->prefix[DISTRIBUTE_OUT]) + free (dist->prefix[DISTRIBUTE_OUT]); + dist->prefix[DISTRIBUTE_OUT] = strdup (plist_name); + } + + /* Apply this distribute-list to the interface. */ + (*distribute_add_hook) (dist); + + return dist; +} + +/* Unset distribute-list. If matched distribute-list exist then + return 1. */ +int +distribute_list_prefix_unset (char *ifname, enum distribute_type type, + char *plist_name) +{ + struct distribute *dist; + + dist = distribute_lookup (ifname); + if (!dist) + return 0; + + if (type == DISTRIBUTE_IN) + { + if (!dist->prefix[DISTRIBUTE_IN]) + return 0; + if (strcmp (dist->prefix[DISTRIBUTE_IN], plist_name) != 0) + return 0; + + free (dist->prefix[DISTRIBUTE_IN]); + dist->prefix[DISTRIBUTE_IN] = NULL; + } + + if (type == DISTRIBUTE_OUT) + { + if (!dist->prefix[DISTRIBUTE_OUT]) + return 0; + if (strcmp (dist->prefix[DISTRIBUTE_OUT], plist_name) != 0) + return 0; + + free (dist->prefix[DISTRIBUTE_OUT]); + dist->prefix[DISTRIBUTE_OUT] = NULL; + } + + /* Apply this distribute-list to the interface. */ + (*distribute_delete_hook) (dist); + + /* If both out and in is NULL then free distribute list. */ + if (dist->list[DISTRIBUTE_IN] == NULL && + dist->list[DISTRIBUTE_OUT] == NULL && + dist->prefix[DISTRIBUTE_IN] == NULL && + dist->prefix[DISTRIBUTE_OUT] == NULL) + { + hash_release (disthash, dist); + distribute_free (dist); + } + + return 1; +} + +DEFUN (distribute_list_all, + distribute_list_all_cmd, + "distribute-list WORD (in|out)", + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") +{ + enum distribute_type type; + struct distribute *dist; + + /* Check of distribute list type. */ + if (strncmp (argv[1], "i", 1) == 0) + type = DISTRIBUTE_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = DISTRIBUTE_OUT; + else + { + vty_out (vty, "distribute list direction must be [in|out]%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get interface name corresponding distribute list. */ + dist = distribute_list_set (NULL, type, argv[0]); + + return CMD_SUCCESS; +} + +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 index 00000000..330126b9 --- /dev/null +++ b/lib/distribute.h @@ -0,0 +1,57 @@ +/* Distribute list functions header + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_DISTRIBUTE_H +#define _ZEBRA_DISTRIBUTE_H + +/* Disctirubte list types. */ +enum distribute_type +{ + DISTRIBUTE_IN, + DISTRIBUTE_OUT, + DISTRIBUTE_MAX +}; + +struct distribute +{ + /* Name of the interface. */ + char *ifname; + + /* Filter name of `in' and `out' */ + char *list[DISTRIBUTE_MAX]; + + /* prefix-list name of `in' and `out' */ + char *prefix[DISTRIBUTE_MAX]; +}; + +/* Prototypes for distribute-list. */ +void distribute_list_init (int); +void distribute_list_reset (void); +void distribute_list_add_hook (void (*) (struct distribute *)); +void distribute_list_delete_hook (void (*) (struct distribute *)); +struct distribute *distribute_lookup (char *); +int config_write_distribute (struct vty *); +int config_show_distribute (struct vty *); + +enum filter_type distribute_apply_in (struct interface *, struct prefix *); +enum filter_type distribute_apply_out (struct interface *, struct prefix *); + +#endif /* _ZEBRA_DISTRIBUTE_H */ diff --git a/lib/filter.c b/lib/filter.c new file mode 100644 index 00000000..a483ce23 --- /dev/null +++ b/lib/filter.c @@ -0,0 +1,2058 @@ +/* Route filtering function. + * Copyright (C) 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "filter.h" +#include "memory.h" +#include "command.h" +#include "sockunion.h" +#include "buffer.h" + +struct filter_cisco +{ + /* Cisco access-list */ + int extended; + struct in_addr addr; + struct in_addr addr_mask; + struct in_addr mask; + struct in_addr mask_mask; +}; + +struct filter_zebra +{ + /* If this filter is "exact" match then this flag is set. */ + int exact; + + /* Prefix information. */ + struct prefix prefix; +}; + +/* Filter element of access list */ +struct filter +{ + /* For doubly linked list. */ + struct filter *next; + struct filter *prev; + + /* Filter type information. */ + enum filter_type type; + + /* Cisco access-list */ + int cisco; + + union + { + struct filter_cisco cfilter; + struct filter_zebra zfilter; + } u; +}; + +/* List of access_list. */ +struct access_list_list +{ + struct access_list *head; + struct access_list *tail; +}; + +/* Master structure of access_list. */ +struct access_master +{ + /* List of access_list which name is number. */ + struct access_list_list num; + + /* List of access_list which name is string. */ + struct access_list_list str; + + /* Hook function which is executed when new access_list is added. */ + void (*add_hook) (); + + /* Hook function which is executed when access_list is deleted. */ + void (*delete_hook) (); +}; + +/* Static structure for IPv4 access_list's master. */ +static struct access_master access_master_ipv4 = +{ + {NULL, NULL}, + {NULL, NULL}, + NULL, + NULL, +}; + +#ifdef HAVE_IPV6 +/* Static structure for IPv6 access_list's master. */ +static struct access_master access_master_ipv6 = +{ + {NULL, NULL}, + {NULL, NULL}, + NULL, + NULL, +}; +#endif /* HAVE_IPV6 */ + +struct access_master * +access_master_get (afi_t afi) +{ + if (afi == AFI_IP) + return &access_master_ipv4; +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6) + return &access_master_ipv6; +#endif /* HAVE_IPV6 */ + return NULL; +} + +/* Allocate new filter structure. */ +struct filter * +filter_new () +{ + return (struct filter *) XCALLOC (MTYPE_ACCESS_FILTER, + sizeof (struct filter)); +} + +void +filter_free (struct filter *filter) +{ + XFREE (MTYPE_ACCESS_FILTER, filter); +} + +/* Return string of filter_type. */ +static char * +filter_type_str (struct filter *filter) +{ + switch (filter->type) + { + case FILTER_PERMIT: + return "permit"; + break; + case FILTER_DENY: + return "deny"; + break; + case FILTER_DYNAMIC: + return "dynamic"; + break; + default: + return ""; + break; + } +} + +/* If filter match to the prefix then return 1. */ +static int +filter_match_cisco (struct filter *mfilter, struct prefix *p) +{ + struct filter_cisco *filter; + struct in_addr mask; + u_int32_t check_addr; + u_int32_t check_mask; + + filter = &mfilter->u.cfilter; + check_addr = p->u.prefix4.s_addr & ~filter->addr_mask.s_addr; + + if (filter->extended) + { + masklen2ip (p->prefixlen, &mask); + check_mask = mask.s_addr & ~filter->mask_mask.s_addr; + + if (memcmp (&check_addr, &filter->addr.s_addr, 4) == 0 + && memcmp (&check_mask, &filter->mask.s_addr, 4) == 0) + return 1; + } + else if (memcmp (&check_addr, &filter->addr.s_addr, 4) == 0) + return 1; + + return 0; +} + +/* If filter match to the prefix then return 1. */ +static int +filter_match_zebra (struct filter *mfilter, struct prefix *p) +{ + struct filter_zebra *filter; + + filter = &mfilter->u.zfilter; + + if (filter->prefix.family == p->family) + { + if (filter->exact) + { + if (filter->prefix.prefixlen == p->prefixlen) + return prefix_match (&filter->prefix, p); + else + return 0; + } + else + return prefix_match (&filter->prefix, p); + } + else + return 0; +} + +/* Allocate new access list structure. */ +struct access_list * +access_list_new () +{ + return (struct access_list *) XCALLOC (MTYPE_ACCESS_LIST, + sizeof (struct access_list)); +} + +/* Free allocated access_list. */ +void +access_list_free (struct access_list *access) +{ + XFREE (MTYPE_ACCESS_LIST, access); +} + +/* Delete access_list from access_master and free it. */ +void +access_list_delete (struct access_list *access) +{ + struct filter *filter; + struct filter *next; + struct access_list_list *list; + struct access_master *master; + + for (filter = access->head; filter; filter = next) + { + next = filter->next; + filter_free (filter); + } + + master = access->master; + + if (access->type == ACCESS_TYPE_NUMBER) + list = &master->num; + else + list = &master->str; + + if (access->next) + access->next->prev = access->prev; + else + list->tail = access->prev; + + if (access->prev) + access->prev->next = access->next; + else + list->head = access->next; + + if (access->name) + XFREE (MTYPE_ACCESS_LIST_STR, access->name); + + if (access->remark) + XFREE (MTYPE_TMP, access->remark); + + access_list_free (access); +} + +/* Insert new access list to list of access_list. Each acceess_list + is sorted by the name. */ +struct access_list * +access_list_insert (afi_t afi, char *name) +{ + int i; + long number; + struct access_list *access; + struct access_list *point; + struct access_list_list *alist; + struct access_master *master; + + master = access_master_get (afi); + if (master == NULL) + return NULL; + + /* Allocate new access_list and copy given name. */ + access = access_list_new (); + access->name = XSTRDUP (MTYPE_ACCESS_LIST_STR, name); + access->master = master; + + /* If name is made by all digit character. We treat it as + number. */ + for (number = 0, i = 0; i < strlen (name); i++) + { + if (isdigit ((int) name[i])) + number = (number * 10) + (name[i] - '0'); + else + break; + } + + /* In case of name is all digit character */ + if (i == strlen (name)) + { + access->type = ACCESS_TYPE_NUMBER; + + /* Set access_list to number list. */ + alist = &master->num; + + for (point = alist->head; point; point = point->next) + if (atol (point->name) >= number) + break; + } + else + { + access->type = ACCESS_TYPE_STRING; + + /* Set access_list to string list. */ + alist = &master->str; + + /* Set point to insertion point. */ + for (point = alist->head; point; point = point->next) + if (strcmp (point->name, name) >= 0) + break; + } + + /* In case of this is the first element of master. */ + if (alist->head == NULL) + { + alist->head = alist->tail = access; + return access; + } + + /* In case of insertion is made at the tail of access_list. */ + if (point == NULL) + { + access->prev = alist->tail; + alist->tail->next = access; + alist->tail = access; + return access; + } + + /* In case of insertion is made at the head of access_list. */ + if (point == alist->head) + { + access->next = alist->head; + alist->head->prev = access; + alist->head = access; + return access; + } + + /* Insertion is made at middle of the access_list. */ + access->next = point; + access->prev = point->prev; + + if (point->prev) + point->prev->next = access; + point->prev = access; + + return access; +} + +/* Lookup access_list from list of access_list by name. */ +struct access_list * +access_list_lookup (afi_t afi, char *name) +{ + struct access_list *access; + struct access_master *master; + + if (name == NULL) + return NULL; + + master = access_master_get (afi); + if (master == NULL) + return NULL; + + for (access = master->num.head; access; access = access->next) + if (strcmp (access->name, name) == 0) + return access; + + for (access = master->str.head; access; access = access->next) + if (strcmp (access->name, name) == 0) + return access; + + return NULL; +} + +/* Get access list from list of access_list. If there isn't matched + access_list create new one and return it. */ +struct access_list * +access_list_get (afi_t afi, char *name) +{ + struct access_list *access; + + access = access_list_lookup (afi, name); + if (access == NULL) + access = access_list_insert (afi, name); + return access; +} + +/* Apply access list to object (which should be struct prefix *). */ +enum filter_type +access_list_apply (struct access_list *access, void *object) +{ + struct filter *filter; + struct prefix *p; + + p = (struct prefix *) object; + + if (access == NULL) + return FILTER_DENY; + + for (filter = access->head; filter; filter = filter->next) + { + if (filter->cisco) + { + if (filter_match_cisco (filter, p)) + return filter->type; + } + else + { + if (filter_match_zebra (filter, p)) + return filter->type; + } + } + + return FILTER_DENY; +} + +/* Add hook function. */ +void +access_list_add_hook (void (*func) (struct access_list *access)) +{ + access_master_ipv4.add_hook = func; +#ifdef HAVE_IPV6 + access_master_ipv6.add_hook = func; +#endif /* HAVE_IPV6 */ +} + +/* Delete hook function. */ +void +access_list_delete_hook (void (*func) (struct access_list *access)) +{ + access_master_ipv4.delete_hook = func; +#ifdef HAVE_IPV6 + access_master_ipv6.delete_hook = func; +#endif /* HAVE_IPV6 */ +} + +/* Add new filter to the end of specified access_list. */ +void +access_list_filter_add (struct access_list *access, struct filter *filter) +{ + filter->next = NULL; + filter->prev = access->tail; + + if (access->tail) + access->tail->next = filter; + else + access->head = filter; + access->tail = filter; + + /* Run hook function. */ + if (access->master->add_hook) + (*access->master->add_hook) (access); +} + +/* If access_list has no filter then return 1. */ +static int +access_list_empty (struct access_list *access) +{ + if (access->head == NULL && access->tail == NULL) + return 1; + else + return 0; +} + +/* Delete filter from specified access_list. If there is hook + function execute it. */ +void +access_list_filter_delete (struct access_list *access, struct filter *filter) +{ + struct access_master *master; + + master = access->master; + + if (filter->next) + filter->next->prev = filter->prev; + else + access->tail = filter->prev; + + if (filter->prev) + filter->prev->next = filter->next; + else + access->head = filter->next; + + filter_free (filter); + + /* If access_list becomes empty delete it from access_master. */ + if (access_list_empty (access)) + access_list_delete (access); + + /* Run hook function. */ + if (master->delete_hook) + (*master->delete_hook) (access); +} + +/* + deny Specify packets to reject + permit Specify packets to forward + dynamic ? +*/ + +/* + Hostname or A.B.C.D Address to match + any Any source host + host A single host address +*/ + +struct filter * +filter_lookup_cisco (struct access_list *access, struct filter *mnew) +{ + struct filter *mfilter; + struct filter_cisco *filter; + struct filter_cisco *new; + + new = &mnew->u.cfilter; + + for (mfilter = access->head; mfilter; mfilter = mfilter->next) + { + filter = &mfilter->u.cfilter; + + if (filter->extended) + { + if (mfilter->type == mnew->type + && filter->addr.s_addr == new->addr.s_addr + && filter->addr_mask.s_addr == new->addr_mask.s_addr + && filter->mask.s_addr == new->mask.s_addr + && filter->mask_mask.s_addr == new->mask_mask.s_addr) + return mfilter; + } + else + { + if (mfilter->type == mnew->type + && filter->addr.s_addr == new->addr.s_addr + && filter->addr_mask.s_addr == new->addr_mask.s_addr) + return mfilter; + } + } + + return NULL; +} + +struct filter * +filter_lookup_zebra (struct access_list *access, struct filter *mnew) +{ + struct filter *mfilter; + struct filter_zebra *filter; + struct filter_zebra *new; + + new = &mnew->u.zfilter; + + for (mfilter = access->head; mfilter; mfilter = mfilter->next) + { + filter = &mfilter->u.zfilter; + + if (filter->exact == new->exact + && mfilter->type == mnew->type + && prefix_same (&filter->prefix, &new->prefix)) + return mfilter; + } + return NULL; +} + +int +vty_access_list_remark_unset (struct vty *vty, afi_t afi, char *name) +{ + struct access_list *access; + + access = access_list_lookup (afi, name); + if (! access) + { + vty_out (vty, "%% access-list %s doesn't exist%s", name, + VTY_NEWLINE); + return CMD_WARNING; + } + + if (access->remark) + { + XFREE (MTYPE_TMP, access->remark); + access->remark = NULL; + } + + if (access->head == NULL && access->tail == NULL && access->remark == NULL) + access_list_delete (access); + + return CMD_SUCCESS; +} + +int +filter_set_cisco (struct vty *vty, char *name_str, char *type_str, + char *addr_str, char *addr_mask_str, + char *mask_str, char *mask_mask_str, + int extended, int set) +{ + int ret; + enum filter_type type; + struct filter *mfilter; + struct filter_cisco *filter; + struct access_list *access; + struct in_addr addr; + struct in_addr addr_mask; + struct in_addr mask; + struct in_addr mask_mask; + + /* Check of filter type. */ + if (strncmp (type_str, "p", 1) == 0) + type = FILTER_PERMIT; + else if (strncmp (type_str, "d", 1) == 0) + type = FILTER_DENY; + else + { + vty_out (vty, "%% filter type must be permit or deny%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = inet_aton (addr_str, &addr); + if (ret <= 0) + { + vty_out (vty, "%%Inconsistent address and mask%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ret = inet_aton (addr_mask_str, &addr_mask); + if (ret <= 0) + { + vty_out (vty, "%%Inconsistent address and mask%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (extended) + { + ret = inet_aton (mask_str, &mask); + if (ret <= 0) + { + vty_out (vty, "%%Inconsistent address and mask%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ret = inet_aton (mask_mask_str, &mask_mask); + if (ret <= 0) + { + vty_out (vty, "%%Inconsistent address and mask%s", + VTY_NEWLINE); + return CMD_WARNING; + } + } + + mfilter = filter_new(); + mfilter->type = type; + mfilter->cisco = 1; + filter = &mfilter->u.cfilter; + filter->extended = extended; + filter->addr.s_addr = addr.s_addr & ~addr_mask.s_addr; + filter->addr_mask.s_addr = addr_mask.s_addr; + + if (extended) + { + filter->mask.s_addr = mask.s_addr & ~mask_mask.s_addr; + filter->mask_mask.s_addr = mask_mask.s_addr; + } + + /* Install new filter to the access_list. */ + access = access_list_get (AFI_IP, name_str); + + if (set) + { + if (filter_lookup_cisco (access, mfilter)) + filter_free (mfilter); + else + access_list_filter_add (access, mfilter); + } + else + { + struct filter *delete_filter; + + delete_filter = filter_lookup_cisco (access, mfilter); + if (delete_filter) + access_list_filter_delete (access, delete_filter); + + filter_free (mfilter); + } + + return CMD_SUCCESS; +} + +/* Standard access-list */ +DEFUN (access_list_standard, + access_list_standard_cmd, + "access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D A.B.C.D", + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Address to match\n" + "Wildcard bits\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], argv[3], + NULL, NULL, 0, 1); +} + +DEFUN (access_list_standard_nomask, + access_list_standard_nomask_cmd, + "access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D", + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Address to match\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0", + NULL, NULL, 0, 1); +} + +DEFUN (access_list_standard_host, + access_list_standard_host_cmd, + "access-list (<1-99>|<1300-1999>) (deny|permit) host A.B.C.D", + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "A single host address\n" + "Address to match\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0", + NULL, NULL, 0, 1); +} + +DEFUN (access_list_standard_any, + access_list_standard_any_cmd, + "access-list (<1-99>|<1300-1999>) (deny|permit) any", + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any source host\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0", + "255.255.255.255", NULL, NULL, 0, 1); +} + +DEFUN (no_access_list_standard, + no_access_list_standard_cmd, + "no access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D A.B.C.D", + NO_STR + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Address to match\n" + "Wildcard bits\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], argv[3], + NULL, NULL, 0, 0); +} + +DEFUN (no_access_list_standard_nomask, + no_access_list_standard_nomask_cmd, + "no access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D", + NO_STR + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Address to match\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0", + NULL, NULL, 0, 0); +} + +DEFUN (no_access_list_standard_host, + no_access_list_standard_host_cmd, + "no access-list (<1-99>|<1300-1999>) (deny|permit) host A.B.C.D", + NO_STR + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "A single host address\n" + "Address to match\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0", + NULL, NULL, 0, 0); +} + +DEFUN (no_access_list_standard_any, + no_access_list_standard_any_cmd, + "no access-list (<1-99>|<1300-1999>) (deny|permit) any", + NO_STR + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any source host\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0", + "255.255.255.255", NULL, NULL, 0, 0); +} + +/* Extended access-list */ +DEFUN (access_list_extended, + access_list_extended_cmd, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Source address\n" + "Source wildcard bits\n" + "Destination address\n" + "Destination Wildcard bits\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], 1 ,1); +} + +DEFUN (access_list_extended_mask_any, + access_list_extended_mask_any_cmd, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D any", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Source address\n" + "Source wildcard bits\n" + "Any destination host\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + argv[3], "0.0.0.0", + "255.255.255.255", 1, 1); +} + +DEFUN (access_list_extended_any_mask, + access_list_extended_any_mask_cmd, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip any A.B.C.D A.B.C.D", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Any source host\n" + "Destination address\n" + "Destination Wildcard bits\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0", + "255.255.255.255", argv[2], + argv[3], 1, 1); +} + +DEFUN (access_list_extended_any_any, + access_list_extended_any_any_cmd, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip any any", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Any source host\n" + "Any destination host\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0", + "255.255.255.255", "0.0.0.0", + "255.255.255.255", 1, 1); +} + +DEFUN (access_list_extended_mask_host, + access_list_extended_mask_host_cmd, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D host A.B.C.D", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Source address\n" + "Source wildcard bits\n" + "A single destination host\n" + "Destination address\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + argv[3], argv[4], + "0.0.0.0", 1, 1); +} + +DEFUN (access_list_extended_host_mask, + access_list_extended_host_mask_cmd, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D A.B.C.D A.B.C.D", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "A single source host\n" + "Source address\n" + "Destination address\n" + "Destination Wildcard bits\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + "0.0.0.0", argv[3], + argv[4], 1, 1); +} + +DEFUN (access_list_extended_host_host, + access_list_extended_host_host_cmd, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D host A.B.C.D", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "A single source host\n" + "Source address\n" + "A single destination host\n" + "Destination address\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + "0.0.0.0", argv[3], + "0.0.0.0", 1, 1); +} + +DEFUN (access_list_extended_any_host, + access_list_extended_any_host_cmd, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip any host A.B.C.D", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Any source host\n" + "A single destination host\n" + "Destination address\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0", + "255.255.255.255", argv[2], + "0.0.0.0", 1, 1); +} + +DEFUN (access_list_extended_host_any, + access_list_extended_host_any_cmd, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D any", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "A single source host\n" + "Source address\n" + "Any destination host\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + "0.0.0.0", "0.0.0.0", + "255.255.255.255", 1, 1); +} + +DEFUN (no_access_list_extended, + no_access_list_extended_cmd, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D", + NO_STR + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Source address\n" + "Source wildcard bits\n" + "Destination address\n" + "Destination Wildcard bits\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], 1, 0); +} + +DEFUN (no_access_list_extended_mask_any, + no_access_list_extended_mask_any_cmd, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D any", + NO_STR + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Source address\n" + "Source wildcard bits\n" + "Any destination host\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + argv[3], "0.0.0.0", + "255.255.255.255", 1, 0); +} + +DEFUN (no_access_list_extended_any_mask, + no_access_list_extended_any_mask_cmd, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any A.B.C.D A.B.C.D", + NO_STR + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Any source host\n" + "Destination address\n" + "Destination Wildcard bits\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0", + "255.255.255.255", argv[2], + argv[3], 1, 0); +} + +DEFUN (no_access_list_extended_any_any, + no_access_list_extended_any_any_cmd, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any any", + NO_STR + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Any source host\n" + "Any destination host\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0", + "255.255.255.255", "0.0.0.0", + "255.255.255.255", 1, 0); +} + +DEFUN (no_access_list_extended_mask_host, + no_access_list_extended_mask_host_cmd, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D host A.B.C.D", + NO_STR + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Source address\n" + "Source wildcard bits\n" + "A single destination host\n" + "Destination address\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + argv[3], argv[4], + "0.0.0.0", 1, 0); +} + +DEFUN (no_access_list_extended_host_mask, + no_access_list_extended_host_mask_cmd, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D A.B.C.D A.B.C.D", + NO_STR + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "A single source host\n" + "Source address\n" + "Destination address\n" + "Destination Wildcard bits\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + "0.0.0.0", argv[3], + argv[4], 1, 0); +} + +DEFUN (no_access_list_extended_host_host, + no_access_list_extended_host_host_cmd, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D host A.B.C.D", + NO_STR + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "A single source host\n" + "Source address\n" + "A single destination host\n" + "Destination address\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + "0.0.0.0", argv[3], + "0.0.0.0", 1, 0); +} + +DEFUN (no_access_list_extended_any_host, + no_access_list_extended_any_host_cmd, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any host A.B.C.D", + NO_STR + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Any source host\n" + "A single destination host\n" + "Destination address\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0", + "255.255.255.255", argv[2], + "0.0.0.0", 1, 0); +} + +DEFUN (no_access_list_extended_host_any, + no_access_list_extended_host_any_cmd, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D any", + NO_STR + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "A single source host\n" + "Source address\n" + "Any destination host\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + "0.0.0.0", "0.0.0.0", + "255.255.255.255", 1, 0); +} + +int +filter_set_zebra (struct vty *vty, char *name_str, char *type_str, + afi_t afi, char *prefix_str, int exact, int set) +{ + int ret; + enum filter_type type; + struct filter *mfilter; + struct filter_zebra *filter; + struct access_list *access; + struct prefix p; + + /* Check of filter type. */ + if (strncmp (type_str, "p", 1) == 0) + type = FILTER_PERMIT; + else if (strncmp (type_str, "d", 1) == 0) + type = FILTER_DENY; + else + { + vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check string format of prefix and prefixlen. */ + if (afi == AFI_IP) + { + ret = str2prefix_ipv4 (prefix_str, (struct prefix_ipv4 *)&p); + if (ret <= 0) + { + vty_out (vty, "IP address prefix/prefixlen is malformed%s", + VTY_NEWLINE); + return CMD_WARNING; + } + } +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6) + { + ret = str2prefix_ipv6 (prefix_str, (struct prefix_ipv6 *) &p); + if (ret <= 0) + { + vty_out (vty, "IPv6 address prefix/prefixlen is malformed%s", + VTY_NEWLINE); + return CMD_WARNING; + } + } +#endif /* HAVE_IPV6 */ + else + return CMD_WARNING; + + mfilter = filter_new (); + mfilter->type = type; + filter = &mfilter->u.zfilter; + prefix_copy (&filter->prefix, &p); + + /* "exact-match" */ + if (exact) + filter->exact = 1; + + /* Install new filter to the access_list. */ + access = access_list_get (afi, name_str); + + if (set) + { + if (filter_lookup_zebra (access, mfilter)) + filter_free (mfilter); + else + access_list_filter_add (access, mfilter); + } + else + { + struct filter *delete_filter; + + delete_filter = filter_lookup_zebra (access, mfilter); + if (delete_filter) + access_list_filter_delete (access, delete_filter); + + filter_free (mfilter); + } + + return CMD_SUCCESS; +} + +/* Zebra access-list */ +DEFUN (access_list, + access_list_cmd, + "access-list WORD (deny|permit) A.B.C.D/M", + "Add an access list entry\n" + "IP zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 10.0.0.0/8\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 0, 1); +} + +DEFUN (access_list_exact, + access_list_exact_cmd, + "access-list WORD (deny|permit) A.B.C.D/M exact-match", + "Add an access list entry\n" + "IP zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 10.0.0.0/8\n" + "Exact match of the prefixes\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 1, 1); +} + +DEFUN (access_list_any, + access_list_any_cmd, + "access-list WORD (deny|permit) any", + "Add an access list entry\n" + "IP zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 10.0.0.0/8\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, "0.0.0.0/0", 0, 1); +} + +DEFUN (no_access_list, + no_access_list_cmd, + "no access-list WORD (deny|permit) A.B.C.D/M", + NO_STR + "Add an access list entry\n" + "IP zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 10.0.0.0/8\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 0, 0); +} + +DEFUN (no_access_list_exact, + no_access_list_exact_cmd, + "no access-list WORD (deny|permit) A.B.C.D/M exact-match", + NO_STR + "Add an access list entry\n" + "IP zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 10.0.0.0/8\n" + "Exact match of the prefixes\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 1, 0); +} + +DEFUN (no_access_list_any, + no_access_list_any_cmd, + "no access-list WORD (deny|permit) any", + NO_STR + "Add an access list entry\n" + "IP zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 10.0.0.0/8\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, "0.0.0.0/0", 0, 0); +} + +DEFUN (no_access_list_all, + no_access_list_all_cmd, + "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)", + NO_STR + "Add an access list entry\n" + "IP standard access list\n" + "IP extended access list\n" + "IP standard access list (expanded range)\n" + "IP extended access list (expanded range)\n" + "IP zebra access-list name\n") +{ + struct access_list *access; + struct access_master *master; + + /* Looking up access_list. */ + access = access_list_lookup (AFI_IP, argv[0]); + if (access == NULL) + { + vty_out (vty, "%% access-list %s doesn't exist%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + master = access->master; + + /* Delete all filter from access-list. */ + access_list_delete (access); + + /* Run hook function. */ + if (master->delete_hook) + (*master->delete_hook) (access); + + return CMD_SUCCESS; +} + +DEFUN (access_list_remark, + access_list_remark_cmd, + "access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE", + "Add an access list entry\n" + "IP standard access list\n" + "IP extended access list\n" + "IP standard access list (expanded range)\n" + "IP extended access list (expanded range)\n" + "IP zebra access-list\n" + "Access list entry comment\n" + "Comment up to 100 characters\n") +{ + struct access_list *access; + struct buffer *b; + int i; + + access = access_list_get (AFI_IP, argv[0]); + + if (access->remark) + { + XFREE (MTYPE_TMP, access->remark); + access->remark = NULL; + } + + /* Below is remark get codes. */ + b = buffer_new (1024); + for (i = 1; i < argc; i++) + { + buffer_putstr (b, (u_char *)argv[i]); + buffer_putc (b, ' '); + } + buffer_putc (b, '\0'); + + access->remark = buffer_getstr (b); + + buffer_free (b); + + return CMD_SUCCESS; +} + +DEFUN (no_access_list_remark, + no_access_list_remark_cmd, + "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark", + NO_STR + "Add an access list entry\n" + "IP standard access list\n" + "IP extended access list\n" + "IP standard access list (expanded range)\n" + "IP extended access list (expanded range)\n" + "IP zebra access-list\n" + "Access list entry comment\n") +{ + return vty_access_list_remark_unset (vty, AFI_IP, argv[0]); +} + +ALIAS (no_access_list_remark, + no_access_list_remark_arg_cmd, + "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE", + NO_STR + "Add an access list entry\n" + "IP standard access list\n" + "IP extended access list\n" + "IP standard access list (expanded range)\n" + "IP extended access list (expanded range)\n" + "IP zebra access-list\n" + "Access list entry comment\n" + "Comment up to 100 characters\n") + +#ifdef HAVE_IPV6 +DEFUN (ipv6_access_list, + ipv6_access_list_cmd, + "ipv6 access-list WORD (deny|permit) X:X::X:X/M", + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 3ffe:506::/32\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 0, 1); +} + +DEFUN (ipv6_access_list_exact, + ipv6_access_list_exact_cmd, + "ipv6 access-list WORD (deny|permit) X:X::X:X/M exact-match", + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 3ffe:506::/32\n" + "Exact match of the prefixes\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 1, 1); +} + +DEFUN (ipv6_access_list_any, + ipv6_access_list_any_cmd, + "ipv6 access-list WORD (deny|permit) any", + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any prefixi to match\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, "::/0", 0, 1); +} + +DEFUN (no_ipv6_access_list, + no_ipv6_access_list_cmd, + "no ipv6 access-list WORD (deny|permit) X:X::X:X/M", + NO_STR + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 3ffe:506::/32\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 0, 0); +} + +DEFUN (no_ipv6_access_list_exact, + no_ipv6_access_list_exact_cmd, + "no ipv6 access-list WORD (deny|permit) X:X::X:X/M exact-match", + NO_STR + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 3ffe:506::/32\n" + "Exact match of the prefixes\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 1, 0); +} + +DEFUN (no_ipv6_access_list_any, + no_ipv6_access_list_any_cmd, + "no ipv6 access-list WORD (deny|permit) any", + NO_STR + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any prefixi to match\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, "::/0", 0, 0); +} + + +DEFUN (no_ipv6_access_list_all, + no_ipv6_access_list_all_cmd, + "no ipv6 access-list WORD", + NO_STR + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n") +{ + struct access_list *access; + struct access_master *master; + + /* Looking up access_list. */ + access = access_list_lookup (AFI_IP6, argv[0]); + if (access == NULL) + { + vty_out (vty, "%% access-list %s doesn't exist%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + master = access->master; + + /* Delete all filter from access-list. */ + access_list_delete (access); + + /* Run hook function. */ + if (master->delete_hook) + (*master->delete_hook) (access); + + return CMD_SUCCESS; +} + +DEFUN (ipv6_access_list_remark, + ipv6_access_list_remark_cmd, + "ipv6 access-list WORD remark .LINE", + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Access list entry comment\n" + "Comment up to 100 characters\n") +{ + struct access_list *access; + struct buffer *b; + int i; + + access = access_list_get (AFI_IP6, argv[0]); + + if (access->remark) + { + XFREE (MTYPE_TMP, access->remark); + access->remark = NULL; + } + + /* Below is remark get codes. */ + b = buffer_new (1024); + for (i = 1; i < argc; i++) + { + buffer_putstr (b, (u_char *)argv[i]); + buffer_putc (b, ' '); + } + buffer_putc (b, '\0'); + + access->remark = buffer_getstr (b); + + buffer_free (b); + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_access_list_remark, + no_ipv6_access_list_remark_cmd, + "no ipv6 access-list WORD remark", + NO_STR + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Access list entry comment\n") +{ + return vty_access_list_remark_unset (vty, AFI_IP6, argv[0]); +} + +ALIAS (no_ipv6_access_list_remark, + no_ipv6_access_list_remark_arg_cmd, + "no ipv6 access-list WORD remark .LINE", + NO_STR + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Access list entry comment\n" + "Comment up to 100 characters\n") +#endif /* HAVE_IPV6 */ + +void config_write_access_zebra (struct vty *, struct filter *); +void config_write_access_cisco (struct vty *, struct filter *); + +/* show access-list command. */ +int +filter_show (struct vty *vty, char *name, afi_t afi) +{ + struct access_list *access; + struct access_master *master; + struct filter *mfilter; + struct filter_cisco *filter; + int write = 0; + + master = access_master_get (afi); + if (master == NULL) + return 0; + + for (access = master->num.head; access; access = access->next) + { + if (name && strcmp (access->name, name) != 0) + continue; + + write = 1; + + for (mfilter = access->head; mfilter; mfilter = mfilter->next) + { + filter = &mfilter->u.cfilter; + + if (write) + { + vty_out (vty, "%s IP%s access list %s%s", + mfilter->cisco ? + (filter->extended ? "Extended" : "Standard") : "Zebra", + afi == AFI_IP6 ? "v6" : "", + access->name, VTY_NEWLINE); + write = 0; + } + + vty_out (vty, " %s%s", filter_type_str (mfilter), + mfilter->type == FILTER_DENY ? " " : ""); + + if (! mfilter->cisco) + config_write_access_zebra (vty, mfilter); + else if (filter->extended) + config_write_access_cisco (vty, mfilter); + else + { + if (filter->addr_mask.s_addr == 0xffffffff) + vty_out (vty, " any%s", VTY_NEWLINE); + else + { + vty_out (vty, " %s", inet_ntoa (filter->addr)); + if (filter->addr_mask.s_addr != 0) + vty_out (vty, ", wildcard bits %s", inet_ntoa (filter->addr_mask)); + vty_out (vty, "%s", VTY_NEWLINE); + } + } + } + } + + for (access = master->str.head; access; access = access->next) + { + if (name && strcmp (access->name, name) != 0) + continue; + + write = 1; + + for (mfilter = access->head; mfilter; mfilter = mfilter->next) + { + filter = &mfilter->u.cfilter; + + if (write) + { + vty_out (vty, "%s IP%s access list %s%s", + mfilter->cisco ? + (filter->extended ? "Extended" : "Standard") : "Zebra", + afi == AFI_IP6 ? "v6" : "", + access->name, VTY_NEWLINE); + write = 0; + } + + vty_out (vty, " %s%s", filter_type_str (mfilter), + mfilter->type == FILTER_DENY ? " " : ""); + + if (! mfilter->cisco) + config_write_access_zebra (vty, mfilter); + else if (filter->extended) + config_write_access_cisco (vty, mfilter); + else + { + if (filter->addr_mask.s_addr == 0xffffffff) + vty_out (vty, " any%s", VTY_NEWLINE); + else + { + vty_out (vty, " %s", inet_ntoa (filter->addr)); + if (filter->addr_mask.s_addr != 0) + vty_out (vty, ", wildcard bits %s", inet_ntoa (filter->addr_mask)); + vty_out (vty, "%s", VTY_NEWLINE); + } + } + } + } + return CMD_SUCCESS; +} + +DEFUN (show_ip_access_list, + show_ip_access_list_cmd, + "show ip access-list", + SHOW_STR + IP_STR + "List IP access lists\n") +{ + return filter_show (vty, NULL, AFI_IP); +} + +DEFUN (show_ip_access_list_name, + show_ip_access_list_name_cmd, + "show ip access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)", + SHOW_STR + IP_STR + "List IP access lists\n" + "IP standard access list\n" + "IP extended access list\n" + "IP standard access list (expanded range)\n" + "IP extended access list (expanded range)\n" + "IP zebra access-list\n") +{ + return filter_show (vty, argv[0], AFI_IP); +} + +#ifdef HAVE_IPV6 +DEFUN (show_ipv6_access_list, + show_ipv6_access_list_cmd, + "show ipv6 access-list", + SHOW_STR + IPV6_STR + "List IPv6 access lists\n") +{ + return filter_show (vty, NULL, AFI_IP6); +} + +DEFUN (show_ipv6_access_list_name, + show_ipv6_access_list_name_cmd, + "show ipv6 access-list WORD", + SHOW_STR + IPV6_STR + "List IPv6 access lists\n" + "IPv6 zebra access-list\n") +{ + return filter_show (vty, argv[0], AFI_IP6); +} +#endif /* HAVE_IPV6 */ + +void +config_write_access_cisco (struct vty *vty, struct filter *mfilter) +{ + struct filter_cisco *filter; + + filter = &mfilter->u.cfilter; + + if (filter->extended) + { + vty_out (vty, " ip"); + if (filter->addr_mask.s_addr == 0xffffffff) + vty_out (vty, " any"); + else if (filter->addr_mask.s_addr == 0) + vty_out (vty, " host %s", inet_ntoa (filter->addr)); + else + { + vty_out (vty, " %s", inet_ntoa (filter->addr)); + vty_out (vty, " %s", inet_ntoa (filter->addr_mask)); + } + + if (filter->mask_mask.s_addr == 0xffffffff) + vty_out (vty, " any"); + else if (filter->mask_mask.s_addr == 0) + vty_out (vty, " host %s", inet_ntoa (filter->mask)); + else + { + vty_out (vty, " %s", inet_ntoa (filter->mask)); + vty_out (vty, " %s", inet_ntoa (filter->mask_mask)); + } + vty_out (vty, "%s", VTY_NEWLINE); + } + else + { + if (filter->addr_mask.s_addr == 0xffffffff) + vty_out (vty, " any%s", VTY_NEWLINE); + else + { + vty_out (vty, " %s", inet_ntoa (filter->addr)); + if (filter->addr_mask.s_addr != 0) + vty_out (vty, " %s", inet_ntoa (filter->addr_mask)); + vty_out (vty, "%s", VTY_NEWLINE); + } + } +} + +void +config_write_access_zebra (struct vty *vty, struct filter *mfilter) +{ + struct filter_zebra *filter; + struct prefix *p; + char buf[BUFSIZ]; + + filter = &mfilter->u.zfilter; + p = &filter->prefix; + + if (p->prefixlen == 0 && ! filter->exact) + vty_out (vty, " any"); + else + vty_out (vty, " %s/%d%s", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen, + filter->exact ? " exact-match" : ""); + + vty_out (vty, "%s", VTY_NEWLINE); +} + +int +config_write_access (struct vty *vty, afi_t afi) +{ + struct access_list *access; + struct access_master *master; + struct filter *mfilter; + int write = 0; + + master = access_master_get (afi); + if (master == NULL) + return 0; + + for (access = master->num.head; access; access = access->next) + { + if (access->remark) + { + vty_out (vty, "%saccess-list %s remark %s%s", + afi == AFI_IP ? "" : "ipv6 ", + access->name, access->remark, + VTY_NEWLINE); + write++; + } + + for (mfilter = access->head; mfilter; mfilter = mfilter->next) + { + vty_out (vty, "%saccess-list %s %s", + afi == AFI_IP ? "" : "ipv6 ", + access->name, + filter_type_str (mfilter)); + + if (mfilter->cisco) + config_write_access_cisco (vty, mfilter); + else + config_write_access_zebra (vty, mfilter); + + write++; + } + } + + for (access = master->str.head; access; access = access->next) + { + if (access->remark) + { + vty_out (vty, "%saccess-list %s remark %s%s", + afi == AFI_IP ? "" : "ipv6 ", + access->name, access->remark, + VTY_NEWLINE); + write++; + } + + for (mfilter = access->head; mfilter; mfilter = mfilter->next) + { + vty_out (vty, "%saccess-list %s %s", + afi == AFI_IP ? "" : "ipv6 ", + access->name, + filter_type_str (mfilter)); + + if (mfilter->cisco) + config_write_access_cisco (vty, mfilter); + else + config_write_access_zebra (vty, mfilter); + + write++; + } + } + return write; +} + +/* Access-list node. */ +struct cmd_node access_node = +{ + ACCESS_NODE, + "", /* Access list has no interface. */ + 1 +}; + +int +config_write_access_ipv4 (struct vty *vty) +{ + return config_write_access (vty, AFI_IP); +} + +void +access_list_reset_ipv4 () +{ + struct access_list *access; + struct access_list *next; + struct access_master *master; + + master = access_master_get (AFI_IP); + if (master == NULL) + return; + + for (access = master->num.head; access; access = next) + { + next = access->next; + access_list_delete (access); + } + for (access = master->str.head; access; access = next) + { + next = access->next; + access_list_delete (access); + } + + assert (master->num.head == NULL); + assert (master->num.tail == NULL); + + assert (master->str.head == NULL); + assert (master->str.tail == NULL); +} + +/* Install vty related command. */ +void +access_list_init_ipv4 () +{ + install_node (&access_node, config_write_access_ipv4); + + install_element (ENABLE_NODE, &show_ip_access_list_cmd); + install_element (ENABLE_NODE, &show_ip_access_list_name_cmd); + + /* Zebra access-list */ + install_element (CONFIG_NODE, &access_list_cmd); + install_element (CONFIG_NODE, &access_list_exact_cmd); + install_element (CONFIG_NODE, &access_list_any_cmd); + install_element (CONFIG_NODE, &no_access_list_cmd); + install_element (CONFIG_NODE, &no_access_list_exact_cmd); + install_element (CONFIG_NODE, &no_access_list_any_cmd); + + /* Standard access-list */ + install_element (CONFIG_NODE, &access_list_standard_cmd); + install_element (CONFIG_NODE, &access_list_standard_nomask_cmd); + install_element (CONFIG_NODE, &access_list_standard_host_cmd); + install_element (CONFIG_NODE, &access_list_standard_any_cmd); + install_element (CONFIG_NODE, &no_access_list_standard_cmd); + install_element (CONFIG_NODE, &no_access_list_standard_nomask_cmd); + install_element (CONFIG_NODE, &no_access_list_standard_host_cmd); + install_element (CONFIG_NODE, &no_access_list_standard_any_cmd); + + /* Extended access-list */ + install_element (CONFIG_NODE, &access_list_extended_cmd); + install_element (CONFIG_NODE, &access_list_extended_any_mask_cmd); + install_element (CONFIG_NODE, &access_list_extended_mask_any_cmd); + install_element (CONFIG_NODE, &access_list_extended_any_any_cmd); + install_element (CONFIG_NODE, &access_list_extended_host_mask_cmd); + install_element (CONFIG_NODE, &access_list_extended_mask_host_cmd); + install_element (CONFIG_NODE, &access_list_extended_host_host_cmd); + install_element (CONFIG_NODE, &access_list_extended_any_host_cmd); + install_element (CONFIG_NODE, &access_list_extended_host_any_cmd); + install_element (CONFIG_NODE, &no_access_list_extended_cmd); + install_element (CONFIG_NODE, &no_access_list_extended_any_mask_cmd); + install_element (CONFIG_NODE, &no_access_list_extended_mask_any_cmd); + install_element (CONFIG_NODE, &no_access_list_extended_any_any_cmd); + install_element (CONFIG_NODE, &no_access_list_extended_host_mask_cmd); + install_element (CONFIG_NODE, &no_access_list_extended_mask_host_cmd); + install_element (CONFIG_NODE, &no_access_list_extended_host_host_cmd); + install_element (CONFIG_NODE, &no_access_list_extended_any_host_cmd); + install_element (CONFIG_NODE, &no_access_list_extended_host_any_cmd); + + install_element (CONFIG_NODE, &access_list_remark_cmd); + install_element (CONFIG_NODE, &no_access_list_all_cmd); + install_element (CONFIG_NODE, &no_access_list_remark_cmd); + install_element (CONFIG_NODE, &no_access_list_remark_arg_cmd); +} + +#ifdef HAVE_IPV6 +struct cmd_node access_ipv6_node = +{ + ACCESS_IPV6_NODE, + "", + 1 +}; + +int +config_write_access_ipv6 (struct vty *vty) +{ + return config_write_access (vty, AFI_IP6); +} + +void +access_list_reset_ipv6 () +{ + struct access_list *access; + struct access_list *next; + struct access_master *master; + + master = access_master_get (AFI_IP6); + if (master == NULL) + return; + + for (access = master->num.head; access; access = next) + { + next = access->next; + access_list_delete (access); + } + for (access = master->str.head; access; access = next) + { + next = access->next; + access_list_delete (access); + } + + assert (master->num.head == NULL); + assert (master->num.tail == NULL); + + assert (master->str.head == NULL); + assert (master->str.tail == NULL); +} + +void +access_list_init_ipv6 () +{ + install_node (&access_ipv6_node, config_write_access_ipv6); + + install_element (ENABLE_NODE, &show_ipv6_access_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_access_list_name_cmd); + + install_element (CONFIG_NODE, &ipv6_access_list_cmd); + install_element (CONFIG_NODE, &ipv6_access_list_exact_cmd); + install_element (CONFIG_NODE, &ipv6_access_list_any_cmd); + install_element (CONFIG_NODE, &no_ipv6_access_list_exact_cmd); + install_element (CONFIG_NODE, &no_ipv6_access_list_cmd); + install_element (CONFIG_NODE, &no_ipv6_access_list_any_cmd); + + install_element (CONFIG_NODE, &no_ipv6_access_list_all_cmd); + install_element (CONFIG_NODE, &ipv6_access_list_remark_cmd); + install_element (CONFIG_NODE, &no_ipv6_access_list_remark_cmd); + install_element (CONFIG_NODE, &no_ipv6_access_list_remark_arg_cmd); +} +#endif /* HAVE_IPV6 */ + +void +access_list_init () +{ + access_list_init_ipv4 (); +#ifdef HAVE_IPV6 + access_list_init_ipv6(); +#endif /* HAVE_IPV6 */ +} + +void +access_list_reset () +{ + access_list_reset_ipv4 (); +#ifdef HAVE_IPV6 + access_list_reset_ipv6(); +#endif /* HAVE_IPV6 */ +} diff --git a/lib/filter.h b/lib/filter.h new file mode 100644 index 00000000..077ac2fb --- /dev/null +++ b/lib/filter.h @@ -0,0 +1,67 @@ +/* + * Route filtering function. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_FILTER_H +#define _ZEBRA_FILTER_H + +#include "if.h" + +/* Filter type is made by `permit', `deny' and `dynamic'. */ +enum filter_type +{ + FILTER_DENY, + FILTER_PERMIT, + FILTER_DYNAMIC +}; + +enum access_type +{ + ACCESS_TYPE_STRING, + ACCESS_TYPE_NUMBER +}; + +/* Access list */ +struct access_list +{ + char *name; + char *remark; + + struct access_master *master; + + enum access_type type; + + struct access_list *next; + struct access_list *prev; + + struct filter *head; + struct filter *tail; +}; + +/* Prototypes for access-list. */ +void access_list_init (void); +void access_list_reset (void); +void access_list_add_hook (void (*func)(struct access_list *)); +void access_list_delete_hook (void (*func)(struct access_list *)); +struct access_list *access_list_lookup (afi_t, char *); +enum filter_type access_list_apply (struct access_list *, void *); + +#endif /* _ZEBRA_FILTER_H */ diff --git a/lib/getopt.c b/lib/getopt.c new file mode 100644 index 00000000..426b29bf --- /dev/null +++ b/lib/getopt.c @@ -0,0 +1,1054 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to drepper@gnu.org + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98 + Free Software Foundation, Inc. + + NOTE: The canonical source of this file is maintained with the GNU C Library. + Bugs can be reported to bug-glibc@gnu.org. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include +# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +# include +# include +#endif /* GNU C library. */ + +#ifdef VMS +# include +# if HAVE_STRING_H - 0 +# include +# endif +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +# ifdef HAVE_LIBINTL_H +# include +# define _(msgid) gettext (msgid) +# else +# define _(msgid) (msgid) +# endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = NULL; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Formerly, initialization of getopt depended on optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +int __getopt_initialized = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +# include +# define my_index strchr +#else + +# if HAVE_STRING_H +# include +# else +# include +# endif + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#ifndef getenv +extern char *getenv (); +#endif + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +# if (!defined __STDC__ || !__STDC__) && !defined strlen +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +# endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; + +static int original_argc; +static char *const *original_argv; + +/* Make sure the environment variable bash 2.0 puts in the environment + is valid for the getopt call we must make sure that the ARGV passed + to getopt is that one passed to the process. */ +static void +__attribute__ ((unused)) +store_args_and_env (int argc, char *const *argv) +{ + /* XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; +} +# ifdef text_set_element +text_set_element (__libc_subinit, store_args_and_env); +# endif /* text_set_element */ + +# define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined __STDC__ && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#ifdef _LIBC + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc (top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memset (__mempcpy (new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined __STDC__ && __STDC__ +static const char *_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#ifdef _LIBC + if (posixly_correct == NULL + && argc == original_argc && argv == original_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen (orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#ifdef _LIBC +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + } + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/lib/getopt.h b/lib/getopt.h new file mode 100644 index 00000000..fb30719a --- /dev/null +++ b/lib/getopt.h @@ -0,0 +1,133 @@ +/* Declarations for getopt. + Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc. + + NOTE: The canonical source of this file is maintained with the GNU C Library. + Bugs can be reported to bug-glibc@gnu.org. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if defined (__STDC__) && __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if defined (__STDC__) && __STDC__ +#ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* getopt.h */ diff --git a/lib/getopt1.c b/lib/getopt1.c new file mode 100644 index 00000000..ff257374 --- /dev/null +++ b/lib/getopt1.c @@ -0,0 +1,190 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 + Free Software Foundation, Inc. + + NOTE: The canonical source of this file is maintained with the GNU C Library. + Bugs can be reported to bug-glibc@gnu.org. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "getopt.h" + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +#include + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/lib/hash.c b/lib/hash.c new file mode 100644 index 00000000..40975079 --- /dev/null +++ b/lib/hash.c @@ -0,0 +1,182 @@ +/* Hash routine. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "hash.h" +#include "memory.h" + +/* Allocate a new hash. */ +struct hash * +hash_create_size (unsigned int size, + unsigned int (*hash_key) (), int (*hash_cmp) ()) +{ + struct hash *hash; + + hash = XMALLOC (MTYPE_HASH, sizeof (struct hash)); + hash->index = XMALLOC (MTYPE_HASH_INDEX, + sizeof (struct hash_backet *) * size); + memset (hash->index, 0, sizeof (struct hash_backet *) * size); + hash->size = size; + hash->hash_key = hash_key; + hash->hash_cmp = hash_cmp; + hash->count = 0; + + return hash; +} + +/* Allocate a new hash with default hash size. */ +struct hash * +hash_create (unsigned int (*hash_key) (), int (*hash_cmp) ()) +{ + return hash_create_size (HASHTABSIZE, hash_key, hash_cmp); +} + +/* Utility function for hash_get(). When this function is specified + as alloc_func, return arugment as it is. This function is used for + intern already allocated value. */ +void * +hash_alloc_intern (void *arg) +{ + return arg; +} + +/* Lookup and return hash backet in hash. If there is no + corresponding hash backet and alloc_func is specified, create new + hash backet. */ +void * +hash_get (struct hash *hash, void *data, void * (*alloc_func) ()) +{ + unsigned int key; + unsigned int index; + void *newdata; + struct hash_backet *backet; + + key = (*hash->hash_key) (data); + index = key % hash->size; + + for (backet = hash->index[index]; backet != NULL; backet = backet->next) + if (backet->key == key && (*hash->hash_cmp) (backet->data, data)) + return backet->data; + + if (alloc_func) + { + newdata = (*alloc_func) (data); + if (newdata == NULL) + return NULL; + + backet = XMALLOC (MTYPE_HASH_BACKET, sizeof (struct hash_backet)); + backet->data = newdata; + backet->key = key; + backet->next = hash->index[index]; + hash->index[index] = backet; + hash->count++; + return backet->data; + } + return NULL; +} + +/* Hash lookup. */ +void * +hash_lookup (struct hash *hash, void *data) +{ + return hash_get (hash, data, NULL); +} + +/* This function release registered value from specified hash. When + release is successfully finished, return the data pointer in the + hash backet. */ +void * +hash_release (struct hash *hash, void *data) +{ + void *ret; + unsigned int key; + unsigned int index; + struct hash_backet *backet; + struct hash_backet *pp; + + key = (*hash->hash_key) (data); + index = key % hash->size; + + for (backet = pp = hash->index[index]; backet; backet = backet->next) + { + if (backet->key == key && (*hash->hash_cmp) (backet->data, data)) + { + if (backet == pp) + hash->index[index] = backet->next; + else + pp->next = backet->next; + + ret = backet->data; + XFREE (MTYPE_HASH_BACKET, backet); + hash->count--; + return ret; + } + pp = backet; + } + return NULL; +} + +/* Iterator function for hash. */ +void +hash_iterate (struct hash *hash, + void (*func) (struct hash_backet *, void *), void *arg) +{ + int i; + struct hash_backet *hb; + + for (i = 0; i < hash->size; i++) + for (hb = hash->index[i]; hb; hb = hb->next) + (*func) (hb, arg); +} + +/* Clean up hash. */ +void +hash_clean (struct hash *hash, void (*free_func) (void *)) +{ + int i; + struct hash_backet *hb; + struct hash_backet *next; + + for (i = 0; i < hash->size; i++) + { + for (hb = hash->index[i]; hb; hb = next) + { + next = hb->next; + + if (free_func) + (*free_func) (hb->data); + + XFREE (MTYPE_HASH_BACKET, hb); + hash->count--; + } + hash->index[i] = NULL; + } +} + +/* Free hash memory. You may call hash_clean before call this + function. */ +void +hash_free (struct hash *hash) +{ + XFREE (MTYPE_HASH_INDEX, hash->index); + XFREE (MTYPE_HASH, hash); +} diff --git a/lib/hash.h b/lib/hash.h new file mode 100644 index 00000000..715e53b5 --- /dev/null +++ b/lib/hash.h @@ -0,0 +1,71 @@ +/* Hash routine. + Copyright (C) 1998 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published +by the Free Software Foundation; either version 2, or (at your +option) any later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef _ZEBRA_HASH_H +#define _ZEBRA_HASH_H + +/* Default hash table size. */ +#define HASHTABSIZE 1024 + +struct hash_backet +{ + /* Linked list. */ + struct hash_backet *next; + + /* Hash key. */ + unsigned int key; + + /* Data. */ + void *data; +}; + +struct hash +{ + /* Hash backet. */ + struct hash_backet **index; + + /* Hash table size. */ + unsigned int size; + + /* Key make function. */ + unsigned int (*hash_key) (); + + /* Data compare function. */ + int (*hash_cmp) (); + + /* Backet alloc. */ + unsigned long count; +}; + +struct hash *hash_create (unsigned int (*) (), int (*) ()); +struct hash *hash_create_size (unsigned int, unsigned int (*) (), int (*) ()); + +void *hash_get (struct hash *, void *, void * (*) ()); +void *hash_alloc_intern (void *); +void *hash_lookup (struct hash *, void *); +void *hash_release (struct hash *, void *); + +void hash_iterate (struct hash *, + void (*) (struct hash_backet *, void *), void *); + +void hash_clean (struct hash *, void (*) (void *)); +void hash_free (struct hash *); + +#endif /* _ZEBRA_HASH_H */ diff --git a/lib/if.c b/lib/if.c new file mode 100644 index 00000000..bbf22ab1 --- /dev/null +++ b/lib/if.c @@ -0,0 +1,713 @@ +/* + * Interface functions. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "linklist.h" +#include "vector.h" +#include "vty.h" +#include "command.h" +#include "if.h" +#include "sockunion.h" +#include "prefix.h" +#include "zebra/connected.h" +#include "memory.h" +#include "table.h" +#include "buffer.h" +#include "str.h" +#include "log.h" + +/* Master list of interfaces. */ +struct list *iflist; + +/* One for each program. This structure is needed to store hooks. */ +struct if_master +{ + int (*if_new_hook) (struct interface *); + int (*if_delete_hook) (struct interface *); +} if_master; + +/* Create new interface structure. */ +struct interface * +if_new () +{ + struct interface *ifp; + + ifp = XMALLOC (MTYPE_IF, sizeof (struct interface)); + memset (ifp, 0, sizeof (struct interface)); + return ifp; +} + +struct interface * +if_create () +{ + struct interface *ifp; + + ifp = if_new (); + + listnode_add (iflist, ifp); + ifp->connected = list_new (); + ifp->connected->del = (void (*) (void *)) connected_free; + + if (if_master.if_new_hook) + (*if_master.if_new_hook) (ifp); + + return ifp; +} + +/* Delete and free interface structure. */ +void +if_delete (struct interface *ifp) +{ + listnode_delete (iflist, ifp); + + if (if_master.if_delete_hook) + (*if_master.if_delete_hook) (ifp); + + /* Free connected address list */ + list_delete (ifp->connected); + + XFREE (MTYPE_IF, ifp); +} + +/* Add hook to interface master. */ +void +if_add_hook (int type, int (*func)(struct interface *ifp)) +{ + switch (type) { + case IF_NEW_HOOK: + if_master.if_new_hook = func; + break; + case IF_DELETE_HOOK: + if_master.if_delete_hook = func; + break; + default: + break; + } +} + +/* Interface existance check by index. */ +struct interface * +if_lookup_by_index (unsigned int index) +{ + listnode node; + struct interface *ifp; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + if (ifp->ifindex == index) + return ifp; + } + return NULL; +} + +char * +ifindex2ifname (unsigned int index) +{ + listnode node; + struct interface *ifp; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + if (ifp->ifindex == index) + return ifp->name; + } + return "unknown"; +} + +/* Interface existance check by interface name. */ +struct interface * +if_lookup_by_name (char *name) +{ + listnode node; + struct interface *ifp; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + if (strncmp (name, ifp->name, sizeof ifp->name) == 0) + return ifp; + } + return NULL; +} + +/* Lookup interface by IPv4 address. */ +struct interface * +if_lookup_exact_address (struct in_addr src) +{ + listnode node; + listnode cnode; + struct interface *ifp; + struct prefix *p; + struct connected *c; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + c = getdata (cnode); + + p = c->address; + + if (p && p->family == AF_INET) + { + if (IPV4_ADDR_SAME (&p->u.prefix4, &src)) + return ifp; + } + } + } + return NULL; +} + +/* Lookup interface by IPv4 address. */ +struct interface * +if_lookup_address (struct in_addr src) +{ + listnode node; + struct prefix addr; + struct prefix best; + listnode cnode; + struct interface *ifp; + struct prefix *p; + struct connected *c; + struct interface *match; + + /* Zero structures - get rid of rubbish from stack */ + memset(&addr, 0, sizeof(addr)); + memset(&best, 0, sizeof(best)); + + addr.family = AF_INET; + addr.u.prefix4 = src; + addr.prefixlen = IPV4_MAX_BITLEN; + + match = NULL; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + c = getdata (cnode); + + if (if_is_pointopoint (ifp)) + { + p = c->address; + + if (p && p->family == AF_INET) + { +#ifdef OLD_RIB /* PTP links are conventionally identified + by the address of the far end - MAG */ + if (IPV4_ADDR_SAME (&p->u.prefix4, &src)) + return ifp; +#endif + p = c->destination; + if (p && IPV4_ADDR_SAME (&p->u.prefix4, &src)) + return ifp; + } + } + else + { + p = c->address; + + if (p->family == AF_INET) + { + if (prefix_match (p, &addr) && p->prefixlen > best.prefixlen) + { + best = *p; + match = ifp; + } + } + } + } + } + return match; +} + +/* Get interface by name if given name interface doesn't exist create + one. */ +struct interface * +if_get_by_name (char *name) +{ + struct interface *ifp; + + ifp = if_lookup_by_name (name); + if (ifp == NULL) + { + ifp = if_create (); + strncpy (ifp->name, name, IFNAMSIZ); + } + return ifp; +} + +/* Does interface up ? */ +int +if_is_up (struct interface *ifp) +{ + return ifp->flags & IFF_UP; +} + +/* Is this loopback interface ? */ +int +if_is_loopback (struct interface *ifp) +{ + return ifp->flags & IFF_LOOPBACK; +} + +/* Does this interface support broadcast ? */ +int +if_is_broadcast (struct interface *ifp) +{ + return ifp->flags & IFF_BROADCAST; +} + +/* Does this interface support broadcast ? */ +int +if_is_pointopoint (struct interface *ifp) +{ + return ifp->flags & IFF_POINTOPOINT; +} + +/* Does this interface support multicast ? */ +int +if_is_multicast (struct interface *ifp) +{ + return ifp->flags & IFF_MULTICAST; +} + +/* Printout flag information into log */ +const char * +if_flag_dump (unsigned long flag) +{ + int separator = 0; + static char logbuf[BUFSIZ]; + +#define IFF_OUT_LOG(X,STR) \ + if ((X) && (flag & (X))) \ + { \ + if (separator) \ + strlcat (logbuf, ",", BUFSIZ); \ + else \ + separator = 1; \ + strlcat (logbuf, STR, BUFSIZ); \ + } + + strlcpy (logbuf, " <", BUFSIZ); + IFF_OUT_LOG (IFF_UP, "UP"); + IFF_OUT_LOG (IFF_BROADCAST, "BROADCAST"); + IFF_OUT_LOG (IFF_DEBUG, "DEBUG"); + IFF_OUT_LOG (IFF_LOOPBACK, "LOOPBACK"); + IFF_OUT_LOG (IFF_POINTOPOINT, "POINTOPOINT"); + IFF_OUT_LOG (IFF_NOTRAILERS, "NOTRAILERS"); + IFF_OUT_LOG (IFF_RUNNING, "RUNNING"); + IFF_OUT_LOG (IFF_NOARP, "NOARP"); + IFF_OUT_LOG (IFF_PROMISC, "PROMISC"); + IFF_OUT_LOG (IFF_ALLMULTI, "ALLMULTI"); + IFF_OUT_LOG (IFF_OACTIVE, "OACTIVE"); + IFF_OUT_LOG (IFF_SIMPLEX, "SIMPLEX"); + IFF_OUT_LOG (IFF_LINK0, "LINK0"); + IFF_OUT_LOG (IFF_LINK1, "LINK1"); + IFF_OUT_LOG (IFF_LINK2, "LINK2"); + IFF_OUT_LOG (IFF_MULTICAST, "MULTICAST"); + + strlcat (logbuf, ">", BUFSIZ); + + return logbuf; +} + +/* For debugging */ +void +if_dump (struct interface *ifp) +{ + listnode node; + + zlog_info ("Interface %s index %d metric %d mtu %d %s", + ifp->name, ifp->ifindex, ifp->metric, ifp->mtu, + if_flag_dump (ifp->flags)); + + for (node = listhead (ifp->connected); node; nextnode (node)) + ; +} + +/* Interface printing for all interface. */ +void +if_dump_all () +{ + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + if_dump (getdata (node)); +} + +DEFUN (interface_desc, + interface_desc_cmd, + "description .LINE", + "Interface specific description\n" + "Characters describing this interface\n") +{ + int i; + struct interface *ifp; + struct buffer *b; + + if (argc == 0) + return CMD_SUCCESS; + + ifp = vty->index; + if (ifp->desc) + XFREE (0, ifp->desc); + + b = buffer_new (1024); + for (i = 0; i < argc; i++) + { + buffer_putstr (b, (u_char *)argv[i]); + buffer_putc (b, ' '); + } + buffer_putc (b, '\0'); + + ifp->desc = buffer_getstr (b); + buffer_free (b); + + return CMD_SUCCESS; +} + +DEFUN (no_interface_desc, + no_interface_desc_cmd, + "no description", + NO_STR + "Interface specific description\n") +{ + struct interface *ifp; + + ifp = vty->index; + if (ifp->desc) + XFREE (0, ifp->desc); + ifp->desc = NULL; + + return CMD_SUCCESS; +} + + +/* See also wrapper function zebra_interface() in zebra/interface.c */ +DEFUN (interface, + interface_cmd, + "interface IFNAME", + "Select an interface to configure\n" + "Interface's name\n") +{ + struct interface *ifp; + + ifp = if_lookup_by_name (argv[0]); + + if (ifp == NULL) + { + ifp = if_create (); + strncpy (ifp->name, argv[0], INTERFACE_NAMSIZ); + } + vty->index = ifp; + vty->node = INTERFACE_NODE; + + return CMD_SUCCESS; +} + +/* For debug purpose. */ +DEFUN (show_address, + show_address_cmd, + "show address", + SHOW_STR + "address\n") +{ + listnode node; + listnode node2; + struct interface *ifp; + struct connected *ifc; + struct prefix *p; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + + for (node2 = listhead (ifp->connected); node2; nextnode (node2)) + { + ifc = getdata (node2); + p = ifc->address; + + if (p->family == AF_INET) + vty_out (vty, "%s/%d%s", inet_ntoa (p->u.prefix4), p->prefixlen, + VTY_NEWLINE); + } + } + return CMD_SUCCESS; +} + +/* Allocate connected structure. */ +struct connected * +connected_new () +{ + struct connected *new = XMALLOC (MTYPE_CONNECTED, sizeof (struct connected)); + memset (new, 0, sizeof (struct connected)); + return new; +} + +/* Free connected structure. */ +void +connected_free (struct connected *connected) +{ + if (connected->address) + prefix_free (connected->address); + + if (connected->destination) + prefix_free (connected->destination); + + if (connected->label) + free (connected->label); + + XFREE (MTYPE_CONNECTED, connected); +} + +/* Print if_addr structure. */ +void +connected_log (struct connected *connected, char *str) +{ + struct prefix *p; + struct interface *ifp; + char logbuf[BUFSIZ]; + char buf[BUFSIZ]; + + ifp = connected->ifp; + p = connected->address; + + snprintf (logbuf, BUFSIZ, "%s interface %s %s %s/%d ", + str, ifp->name, prefix_family_str (p), + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen); + + p = connected->destination; + if (p) + { + strncat (logbuf, inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + BUFSIZ - strlen(logbuf)); + } + zlog (NULL, LOG_INFO, logbuf); +} + +/* If two connected address has same prefix return 1. */ +int +connected_same_prefix (struct prefix *p1, struct prefix *p2) +{ + if (p1->family == p2->family) + { + if (p1->family == AF_INET && + IPV4_ADDR_SAME (&p1->u.prefix4, &p2->u.prefix4)) + return 1; +#ifdef HAVE_IPV6 + if (p1->family == AF_INET6 && + IPV6_ADDR_SAME (&p1->u.prefix6, &p2->u.prefix6)) + return 1; +#endif /* HAVE_IPV6 */ + } + return 0; +} + +struct connected * +connected_delete_by_prefix (struct interface *ifp, struct prefix *p) +{ + struct listnode *node; + struct listnode *next; + struct connected *ifc; + + /* In case of same prefix come, replace it with new one. */ + for (node = listhead (ifp->connected); node; node = next) + { + ifc = getdata (node); + next = node->next; + + if (connected_same_prefix (ifc->address, p)) + { + listnode_delete (ifp->connected, ifc); + return ifc; + } + } + return NULL; +} + +/* Check the connected information is PtP style or not. */ +int +ifc_pointopoint (struct connected *ifc) +{ + struct prefix *p; + int ptp = 0; + + /* When interface has PtP flag. */ + if (if_is_pointopoint (ifc->ifp)) + return 1; + + /* RFC3021 PtP check. */ + p = ifc->address; + + if (p->family == AF_INET) + ptp = (p->prefixlen >= IPV4_MAX_PREFIXLEN - 1); +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + ptp = (p->prefixlen >= IPV6_MAX_PREFIXLEN - 1); +#endif /* HAVE_IPV6 */ + + return ptp; +} + +#ifndef HAVE_IF_NAMETOINDEX +unsigned int +if_nametoindex (const char *name) +{ + listnode node; + struct interface *ifp; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + if (strcmp (ifp->name, name) == 0) + return ifp->ifindex; + } + return 0; +} +#endif + +#ifndef HAVE_IF_INDEXTONAME +char * +if_indextoname (unsigned int ifindex, char *name) +{ + listnode node; + struct interface *ifp; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + if (ifp->ifindex == ifindex) + { + memcpy (name, ifp->name, IFNAMSIZ); + return ifp->name; + } + } + return NULL; +} +#endif + +/* Interface looking up by interface's address. */ + +/* Interface's IPv4 address reverse lookup table. */ +struct route_table *ifaddr_ipv4_table; +/* struct route_table *ifaddr_ipv6_table; */ + +void +ifaddr_ipv4_add (struct in_addr *ifaddr, struct interface *ifp) +{ + struct route_node *rn; + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = *ifaddr; + + rn = route_node_get (ifaddr_ipv4_table, (struct prefix *) &p); + if (rn) + { + route_unlock_node (rn); + zlog_info ("ifaddr_ipv4_add(): address %s is already added", + inet_ntoa (*ifaddr)); + return; + } + rn->info = ifp; +} + +void +ifaddr_ipv4_delete (struct in_addr *ifaddr, struct interface *ifp) +{ + struct route_node *rn; + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = *ifaddr; + + rn = route_node_lookup (ifaddr_ipv4_table, (struct prefix *) &p); + if (! rn) + { + zlog_info ("ifaddr_ipv4_delete(): can't find address %s", + inet_ntoa (*ifaddr)); + return; + } + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); +} + +/* Lookup interface by interface's IP address or interface index. */ +struct interface * +ifaddr_ipv4_lookup (struct in_addr *addr, unsigned int ifindex) +{ + struct prefix_ipv4 p; + struct route_node *rn; + struct interface *ifp; + listnode node; + + if (addr) + { + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = *addr; + + rn = route_node_lookup (ifaddr_ipv4_table, (struct prefix *) &p); + if (! rn) + return NULL; + + ifp = rn->info; + route_unlock_node (rn); + return ifp; + } + else + { + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + + if (ifp->ifindex == ifindex) + return ifp; + } + } + return NULL; +} + +/* Initialize interface list. */ +void +if_init () +{ + iflist = list_new (); + ifaddr_ipv4_table = route_table_init (); + + if (iflist) + return; + + memset (&if_master, 0, sizeof if_master); +} diff --git a/lib/if.h b/lib/if.h new file mode 100644 index 00000000..3896d187 --- /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 index 00000000..d3031fad --- /dev/null +++ b/lib/if_rmap.c @@ -0,0 +1,305 @@ +/* route-map for interface. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "hash.h" +#include "command.h" +#include "memory.h" +#include "if.h" +#include "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; + +struct if_rmap * +if_rmap_new () +{ + struct if_rmap *new; + + new = XCALLOC (MTYPE_IF_RMAP, sizeof (struct if_rmap)); + + return new; +} + +void +if_rmap_free (struct if_rmap *if_rmap) +{ + if (if_rmap->ifname) + free (if_rmap->ifname); + + if (if_rmap->routemap[IF_RMAP_IN]) + free (if_rmap->routemap[IF_RMAP_IN]); + if (if_rmap->routemap[IF_RMAP_OUT]) + free (if_rmap->routemap[IF_RMAP_OUT]); + + XFREE (MTYPE_IF_RMAP, if_rmap); +} + +struct if_rmap * +if_rmap_lookup (char *ifname) +{ + struct if_rmap key; + struct if_rmap *if_rmap; + + key.ifname = ifname; + + if_rmap = hash_lookup (ifrmaphash, &key); + + return if_rmap; +} + +void +if_rmap_hook_add (void (*func) (struct if_rmap *)) +{ + if_rmap_add_hook = func; +} + +void +if_rmap_hook_delete (void (*func) (struct if_rmap *)) +{ + if_rmap_delete_hook = func; +} + +void * +if_rmap_hash_alloc (struct if_rmap *arg) +{ + struct if_rmap *if_rmap; + + if_rmap = if_rmap_new (); + if_rmap->ifname = strdup (arg->ifname); + + return if_rmap; +} + +struct if_rmap * +if_rmap_get (char *ifname) +{ + struct if_rmap key; + + key.ifname = ifname; + + return (struct if_rmap *) hash_get (ifrmaphash, &key, if_rmap_hash_alloc); +} + +unsigned int +if_rmap_hash_make (struct if_rmap *if_rmap) +{ + unsigned int key; + int i; + + key = 0; + for (i = 0; i < strlen (if_rmap->ifname); i++) + key += if_rmap->ifname[i]; + + return key; +} + +int +if_rmap_hash_cmp (struct if_rmap *if_rmap1, struct if_rmap *if_rmap2) +{ + if (strcmp (if_rmap1->ifname, if_rmap2->ifname) == 0) + return 1; + return 0; +} + +struct if_rmap * +if_rmap_set (char *ifname, enum if_rmap_type type, char *routemap_name) +{ + struct if_rmap *if_rmap; + + if_rmap = if_rmap_get (ifname); + + if (type == IF_RMAP_IN) + { + if (if_rmap->routemap[IF_RMAP_IN]) + free (if_rmap->routemap[IF_RMAP_IN]); + if_rmap->routemap[IF_RMAP_IN] = strdup (routemap_name); + } + if (type == IF_RMAP_OUT) + { + if (if_rmap->routemap[IF_RMAP_OUT]) + free (if_rmap->routemap[IF_RMAP_OUT]); + if_rmap->routemap[IF_RMAP_OUT] = strdup (routemap_name); + } + + if (if_rmap_add_hook) + (*if_rmap_add_hook) (if_rmap); + + return if_rmap; +} + +int +if_rmap_unset (char *ifname, enum if_rmap_type type, char *routemap_name) +{ + struct if_rmap *if_rmap; + + if_rmap = if_rmap_lookup (ifname); + if (!if_rmap) + return 0; + + if (type == IF_RMAP_IN) + { + if (!if_rmap->routemap[IF_RMAP_IN]) + return 0; + if (strcmp (if_rmap->routemap[IF_RMAP_IN], routemap_name) != 0) + return 0; + + free (if_rmap->routemap[IF_RMAP_IN]); + if_rmap->routemap[IF_RMAP_IN] = NULL; + } + + if (type == IF_RMAP_OUT) + { + if (!if_rmap->routemap[IF_RMAP_OUT]) + return 0; + if (strcmp (if_rmap->routemap[IF_RMAP_OUT], routemap_name) != 0) + return 0; + + free (if_rmap->routemap[IF_RMAP_OUT]); + if_rmap->routemap[IF_RMAP_OUT] = NULL; + } + + if (if_rmap_delete_hook) + (*if_rmap_delete_hook) (if_rmap); + + if (if_rmap->routemap[IF_RMAP_IN] == NULL && + if_rmap->routemap[IF_RMAP_OUT] == NULL) + { + hash_release (ifrmaphash, if_rmap); + if_rmap_free (if_rmap); + } + + return 1; +} + +DEFUN (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; +} + +/* 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 index 00000000..a9355ab9 --- /dev/null +++ b/lib/if_rmap.h @@ -0,0 +1,47 @@ +/* route-map for interface. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_IF_RMAP_H +#define _ZEBRA_IF_RMAP_H + +enum if_rmap_type +{ + IF_RMAP_IN, + IF_RMAP_OUT, + IF_RMAP_MAX +}; + +struct if_rmap +{ + /* Name of the interface. */ + char *ifname; + + char *routemap[IF_RMAP_MAX]; +}; + +void if_rmap_init (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 index 00000000..dbf431a4 --- /dev/null +++ b/lib/keychain.c @@ -0,0 +1,1001 @@ +/* key-chain for authentication. + Copyright (C) 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published +by the Free Software Foundation; either version 2, or (at your +option) any later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include + +#include "command.h" +#include "memory.h" +#include "linklist.h" +#include "keychain.h" + +/* Master list of key chain. */ +struct list *keychain_list; + +struct keychain * +keychain_new () +{ + struct keychain *new; + new = XMALLOC (MTYPE_KEYCHAIN, sizeof (struct keychain)); + memset (new, 0, sizeof (struct keychain)); + return new; +} + +void +keychain_free (struct keychain *keychain) +{ + XFREE (MTYPE_KEYCHAIN, keychain); +} + +struct key * +key_new () +{ + struct key *new; + new = XMALLOC (MTYPE_KEY, sizeof (struct key)); + memset (new, 0, sizeof (struct key)); + return new; +} + +void +key_free (struct key *key) +{ + XFREE (MTYPE_KEY, key); +} + +struct keychain * +keychain_lookup (char *name) +{ + struct listnode *nn; + struct keychain *keychain; + + if (name == NULL) + return NULL; + + LIST_LOOP (keychain_list, keychain, nn) + { + if (strcmp (keychain->name, name) == 0) + return keychain; + } + return NULL; +} + +int +key_cmp_func (struct key *k1, struct key *k2) +{ + if (k1->index > k2->index) + return 1; + if (k1->index < k2->index) + return -1; + return 0; +} + +void +key_delete_func (struct key *key) +{ + if (key->string) + free (key->string); + key_free (key); +} + +struct keychain * +keychain_get (char *name) +{ + struct keychain *keychain; + + keychain = keychain_lookup (name); + + if (keychain) + return keychain; + + keychain = keychain_new (); + keychain->name = strdup (name); + keychain->key = list_new (); + keychain->key->cmp = (int (*)(void *, void *)) key_cmp_func; + keychain->key->del = (void (*)(void *)) key_delete_func; + listnode_add (keychain_list, keychain); + + return keychain; +} + +void +keychain_delete (struct keychain *keychain) +{ + if (keychain->name) + free (keychain->name); + + list_delete (keychain->key); + listnode_delete (keychain_list, keychain); + keychain_free (keychain); +} + +struct key * +key_lookup (struct keychain *keychain, u_int32_t index) +{ + struct listnode *nn; + struct key *key; + + LIST_LOOP (keychain->key, key, nn) + { + if (key->index == index) + return key; + } + return NULL; +} + +struct key * +key_lookup_for_accept (struct keychain *keychain, u_int32_t index) +{ + struct listnode *nn; + struct key *key; + time_t now; + + now = time (NULL); + + LIST_LOOP (keychain->key, key, nn) + { + if (key->index >= index) + { + if (key->accept.start == 0) + return key; + + if (key->accept.start <= now) + if (key->accept.end >= now || key->accept.end == -1) + return key; + } + } + return NULL; +} + +struct key * +key_match_for_accept (struct keychain *keychain, char *auth_str) +{ + struct listnode *nn; + struct key *key; + time_t now; + + now = time (NULL); + + LIST_LOOP (keychain->key, key, nn) + { + if (key->accept.start == 0 || + (key->accept.start <= now && + (key->accept.end >= now || key->accept.end == -1))) + if (strncmp (key->string, auth_str, 16) == 0) + return key; + } + return NULL; +} + +struct key * +key_lookup_for_send (struct keychain *keychain) +{ + struct listnode *nn; + struct key *key; + time_t now; + + now = time (NULL); + + LIST_LOOP (keychain->key, key, nn) + { + if (key->send.start == 0) + return key; + + if (key->send.start <= now) + if (key->send.end >= now || key->send.end == -1) + return key; + } + return NULL; +} + +struct key * +key_get (struct keychain *keychain, u_int32_t index) +{ + struct key *key; + + key = key_lookup (keychain, index); + + if (key) + return key; + + key = key_new (); + key->index = index; + listnode_add_sort (keychain->key, key); + + return key; +} + +void +key_delete (struct keychain *keychain, struct key *key) +{ + listnode_delete (keychain->key, key); + + if (key->string) + free (key->string); + key_free (key); +} + +DEFUN (key_chain, + key_chain_cmd, + "key chain WORD", + "Authentication key management\n" + "Key-chain management\n" + "Key-chain name\n") +{ + struct keychain *keychain; + + keychain = keychain_get (argv[0]); + vty->index = keychain; + vty->node = KEYCHAIN_NODE; + + return CMD_SUCCESS; +} + +DEFUN (no_key_chain, + no_key_chain_cmd, + "no key chain WORD", + NO_STR + "Authentication key management\n" + "Key-chain management\n" + "Key-chain name\n") +{ + struct keychain *keychain; + + keychain = keychain_lookup (argv[0]); + + if (! keychain) + { + vty_out (vty, "Can't find keychain %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + keychain_delete (keychain); + + return CMD_SUCCESS; +} + +DEFUN (key, + key_cmd, + "key <0-2147483647>", + "Configure a key\n" + "Key identifier number\n") +{ + struct keychain *keychain; + struct key *key; + u_int32_t index; + char *endptr = NULL; + + keychain = vty->index; + + index = strtoul (argv[0], &endptr, 10); + if (index == ULONG_MAX || *endptr != '\0') + { + vty_out (vty, "Key identifier number error%s", VTY_NEWLINE); + return CMD_WARNING; + } + key = key_get (keychain, index); + vty->index_sub = key; + vty->node = KEYCHAIN_KEY_NODE; + + return CMD_SUCCESS; +} + +DEFUN (no_key, + no_key_cmd, + "no key <0-2147483647>", + NO_STR + "Delete a key\n" + "Key identifier number\n") +{ + struct keychain *keychain; + struct key *key; + u_int32_t index; + char *endptr = NULL; + + keychain = vty->index; + + index = strtoul (argv[0], &endptr, 10); + if (index == ULONG_MAX || *endptr != '\0') + { + vty_out (vty, "Key identifier number error%s", VTY_NEWLINE); + return CMD_WARNING; + } + + key = key_lookup (keychain, index); + if (! key) + { + vty_out (vty, "Can't find key %d%s", index, VTY_NEWLINE); + return CMD_WARNING; + } + + key_delete (keychain, key); + + vty->node = KEYCHAIN_NODE; + + return CMD_SUCCESS; +} + +DEFUN (key_string, + key_string_cmd, + "key-string LINE", + "Set key string\n" + "The key\n") +{ + struct key *key; + + key = vty->index_sub; + + if (key->string) + free (key->string); + key->string = strdup (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (no_key_string, + no_key_string_cmd, + "no key-string [LINE]", + NO_STR + "Unset key string\n" + "The key\n") +{ + struct key *key; + + key = vty->index_sub; + + if (key->string) + { + free (key->string); + key->string = NULL; + } + + return CMD_SUCCESS; +} + +/* Convert HH:MM:SS MON DAY YEAR to time_t value. -1 is returned when + given string is malformed. */ +time_t +key_str2time(char *time_str, char *day_str, char *month_str, char *year_str) +{ + int i = 0; + char *colon; + struct tm tm; + time_t time; + int sec, min, hour; + int day, month, year; + char *endptr = NULL; + + char *month_name[] = + { + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + NULL + }; + + /* Check hour field of time_str. */ + colon = strchr (time_str, ':'); + if (colon == NULL) + return -1; + *colon = '\0'; + + /* Hour must be between 0 and 23. */ + hour = strtoul (time_str, &endptr, 10); + if (hour == ULONG_MAX || *endptr != '\0' || hour < 0 || hour > 23) + return -1; + + /* Check min field of time_str. */ + time_str = colon + 1; + colon = strchr (time_str, ':'); + if (*time_str == '\0' || colon == NULL) + return -1; + *colon = '\0'; + + /* Min must be between 0 and 59. */ + min = strtoul (time_str, &endptr, 10); + if (min == ULONG_MAX || *endptr != '\0' || min < 0 || min > 59) + return -1; + + /* Check sec field of time_str. */ + time_str = colon + 1; + if (*time_str == '\0') + return -1; + + /* Sec must be between 0 and 59. */ + sec = strtoul (time_str, &endptr, 10); + if (sec == ULONG_MAX || *endptr != '\0' || sec < 0 || sec > 59) + return -1; + + /* Check day_str. Day must be <1-31>. */ + day = strtoul (day_str, &endptr, 10); + if (day == ULONG_MAX || *endptr != '\0' || day < 0 || day > 31) + return -1; + + /* Check month_str. Month must match month_name. */ + month = 0; + if (strlen (month_str) >= 3) + for (i = 0; month_name[i]; i++) + if (strncmp (month_str, month_name[i], strlen (month_str)) == 0) + { + month = i; + break; + } + if (! month_name[i]) + return -1; + + /* Check year_str. Year must be <1993-2035>. */ + year = strtoul (year_str, &endptr, 10); + if (year == ULONG_MAX || *endptr != '\0' || year < 1993 || year > 2035) + return -1; + + memset (&tm, 0, sizeof (struct tm)); + tm.tm_sec = sec; + tm.tm_min = min; + tm.tm_hour = hour; + tm.tm_mon = month; + tm.tm_mday = day; + tm.tm_year = year - 1900; + + time = mktime (&tm); + + return time; +} + +int +key_lifetime_set (struct vty *vty, struct key_range *krange, char *stime_str, + char *sday_str, char *smonth_str, char *syear_str, + char *etime_str, char *eday_str, char *emonth_str, + char *eyear_str) +{ + time_t time_start; + time_t time_end; + + time_start = key_str2time (stime_str, sday_str, smonth_str, syear_str); + if (time_start < 0) + { + vty_out (vty, "Malformed time value%s", VTY_NEWLINE); + return CMD_WARNING; + } + time_end = key_str2time (etime_str, eday_str, emonth_str, eyear_str); + + if (time_end < 0) + { + vty_out (vty, "Malformed time value%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (time_end <= time_start) + { + vty_out (vty, "Expire time is not later than start time%s", VTY_NEWLINE); + return CMD_WARNING; + } + + krange->start = time_start; + krange->end = time_end; + + return CMD_SUCCESS; +} + +int +key_lifetime_duration_set (struct vty *vty, struct key_range *krange, + char *stime_str, char *sday_str, char *smonth_str, + char *syear_str, char *duration_str) +{ + time_t time_start; + u_int32_t duration; + char *endptr = NULL; + + time_start = key_str2time (stime_str, sday_str, smonth_str, syear_str); + if (time_start < 0) + { + vty_out (vty, "Malformed time value%s", VTY_NEWLINE); + return CMD_WARNING; + } + krange->start = time_start; + + duration = strtoul (duration_str, &endptr, 10); + if (duration == ULONG_MAX || *endptr != '\0') + { + vty_out (vty, "Malformed duration%s", VTY_NEWLINE); + return CMD_WARNING; + } + krange->duration = 1; + krange->end = time_start + duration; + + return CMD_SUCCESS; +} + +int +key_lifetime_infinite_set (struct vty *vty, struct key_range *krange, + char *stime_str, char *sday_str, char *smonth_str, + char *syear_str) +{ + time_t time_start; + + time_start = key_str2time (stime_str, sday_str, smonth_str, syear_str); + if (time_start < 0) + { + vty_out (vty, "Malformed time value%s", VTY_NEWLINE); + return CMD_WARNING; + } + krange->start = time_start; + + krange->end = -1; + + return CMD_SUCCESS; +} + +DEFUN (accept_lifetime_day_month_day_month, + accept_lifetime_day_month_day_month_cmd, + "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", + "Set accept lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Time to expire\n" + "Day of th month to expire\n" + "Month of the year to expire\n" + "Year to expire\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_set (vty, &key->accept, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], argv[6], argv[7]); +} + +DEFUN (accept_lifetime_day_month_month_day, + accept_lifetime_day_month_month_day_cmd, + "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", + "Set accept lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Time to expire\n" + "Month of the year to expire\n" + "Day of th month to expire\n" + "Year to expire\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_set (vty, &key->accept, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[6], argv[5], argv[7]); +} + +DEFUN (accept_lifetime_month_day_day_month, + accept_lifetime_month_day_day_month_cmd, + "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", + "Set accept lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Time to expire\n" + "Day of th month to expire\n" + "Month of the year to expire\n" + "Year to expire\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_set (vty, &key->accept, argv[0], argv[2], argv[1], + argv[3], argv[4], argv[5], argv[6], argv[7]); +} + +DEFUN (accept_lifetime_month_day_month_day, + accept_lifetime_month_day_month_day_cmd, + "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", + "Set accept lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Time to expire\n" + "Month of the year to expire\n" + "Day of th month to expire\n" + "Year to expire\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_set (vty, &key->accept, argv[0], argv[2], argv[1], + argv[3], argv[4], argv[6], argv[5], argv[7]); +} + +DEFUN (accept_lifetime_infinite_day_month, + accept_lifetime_infinite_day_month_cmd, + "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> infinite", + "Set accept lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Never expires") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_infinite_set (vty, &key->accept, argv[0], argv[1], + argv[2], argv[3]); +} + +DEFUN (accept_lifetime_infinite_month_day, + accept_lifetime_infinite_month_day_cmd, + "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> infinite", + "Set accept lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Never expires") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_infinite_set (vty, &key->accept, argv[0], argv[2], + argv[1], argv[3]); +} + +DEFUN (accept_lifetime_duration_day_month, + accept_lifetime_duration_day_month_cmd, + "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> duration <1-2147483646>", + "Set accept lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Duration of the key\n" + "Duration seconds\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_duration_set (vty, &key->accept, argv[0], argv[1], + argv[2], argv[3], argv[4]); +} + +DEFUN (accept_lifetime_duration_month_day, + accept_lifetime_duration_month_day_cmd, + "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> duration <1-2147483646>", + "Set accept lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Duration of the key\n" + "Duration seconds\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_duration_set (vty, &key->accept, argv[0], argv[2], + argv[1], argv[3], argv[4]); +} + +DEFUN (send_lifetime_day_month_day_month, + send_lifetime_day_month_day_month_cmd, + "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", + "Set send lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Time to expire\n" + "Day of th month to expire\n" + "Month of the year to expire\n" + "Year to expire\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_set (vty, &key->send, argv[0], argv[1], argv[2], argv[3], + argv[4], argv[5], argv[6], argv[7]); +} + +DEFUN (send_lifetime_day_month_month_day, + send_lifetime_day_month_month_day_cmd, + "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", + "Set send lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Time to expire\n" + "Month of the year to expire\n" + "Day of th month to expire\n" + "Year to expire\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_set (vty, &key->send, argv[0], argv[1], argv[2], argv[3], + argv[4], argv[6], argv[5], argv[7]); +} + +DEFUN (send_lifetime_month_day_day_month, + send_lifetime_month_day_day_month_cmd, + "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", + "Set send lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Time to expire\n" + "Day of th month to expire\n" + "Month of the year to expire\n" + "Year to expire\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_set (vty, &key->send, argv[0], argv[2], argv[1], argv[3], + argv[4], argv[5], argv[6], argv[7]); +} + +DEFUN (send_lifetime_month_day_month_day, + send_lifetime_month_day_month_day_cmd, + "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", + "Set send lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Time to expire\n" + "Month of the year to expire\n" + "Day of th month to expire\n" + "Year to expire\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_set (vty, &key->send, argv[0], argv[2], argv[1], argv[3], + argv[4], argv[6], argv[5], argv[7]); +} + +DEFUN (send_lifetime_infinite_day_month, + send_lifetime_infinite_day_month_cmd, + "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> infinite", + "Set send lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Never expires") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_infinite_set (vty, &key->send, argv[0], argv[1], argv[2], + argv[3]); +} + +DEFUN (send_lifetime_infinite_month_day, + send_lifetime_infinite_month_day_cmd, + "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> infinite", + "Set send lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Never expires") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_infinite_set (vty, &key->send, argv[0], argv[2], argv[1], + argv[3]); +} + +DEFUN (send_lifetime_duration_day_month, + send_lifetime_duration_day_month_cmd, + "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> duration <1-2147483646>", + "Set send lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Duration of the key\n" + "Duration seconds\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_duration_set (vty, &key->send, argv[0], argv[1], argv[2], + argv[3], argv[4]); +} + +DEFUN (send_lifetime_duration_month_day, + send_lifetime_duration_month_day_cmd, + "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> duration <1-2147483646>", + "Set send lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Duration of the key\n" + "Duration seconds\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_duration_set (vty, &key->send, argv[0], argv[2], argv[1], + argv[3], argv[4]); +} + +struct cmd_node keychain_node = +{ + KEYCHAIN_NODE, + "%s(config-keychain)# ", + 1 +}; + +struct cmd_node keychain_key_node = +{ + KEYCHAIN_KEY_NODE, + "%s(config-keychain-key)# ", + 1 +}; + +int +keychain_strftime (char *buf, int bufsiz, time_t *time) +{ + struct tm *tm; + size_t len; + + tm = localtime (time); + + len = strftime (buf, bufsiz, "%T %b %d %Y", tm); + + return len; +} + +int +keychain_config_write (struct vty *vty) +{ + struct keychain *keychain; + struct key *key; + struct listnode *nn; + struct listnode *nm; + char buf[BUFSIZ]; + + LIST_LOOP (keychain_list, keychain, nn) + { + vty_out (vty, "key chain %s%s", keychain->name, VTY_NEWLINE); + + LIST_LOOP (keychain->key, key, nm) + { + vty_out (vty, " key %d%s", key->index, VTY_NEWLINE); + + if (key->string) + vty_out (vty, " key-string %s%s", key->string, VTY_NEWLINE); + + if (key->accept.start) + { + keychain_strftime (buf, BUFSIZ, &key->accept.start); + vty_out (vty, " accept-lifetime %s", buf); + + if (key->accept.end == -1) + vty_out (vty, " infinite"); + else if (key->accept.duration) + vty_out (vty, " duration %ld", + key->accept.end - key->accept.start); + else + { + keychain_strftime (buf, BUFSIZ, &key->accept.end); + vty_out (vty, " %s", buf); + } + vty_out (vty, "%s", VTY_NEWLINE); + } + + if (key->send.start) + { + keychain_strftime (buf, BUFSIZ, &key->send.start); + vty_out (vty, " send-lifetime %s", buf); + + if (key->send.end == -1) + vty_out (vty, " infinite"); + else if (key->send.duration) + vty_out (vty, " duration %ld", key->send.end - key->send.start); + else + { + keychain_strftime (buf, BUFSIZ, &key->send.end); + vty_out (vty, " %s", buf); + } + vty_out (vty, "%s", VTY_NEWLINE); + } + } + vty_out (vty, "!%s", VTY_NEWLINE); + } + + return 0; +} + +void +keychain_init () +{ + keychain_list = list_new (); + + install_node (&keychain_node, keychain_config_write); + install_node (&keychain_key_node, NULL); + + install_default (KEYCHAIN_NODE); + install_default (KEYCHAIN_KEY_NODE); + + install_element (CONFIG_NODE, &key_chain_cmd); + install_element (CONFIG_NODE, &no_key_chain_cmd); + install_element (KEYCHAIN_NODE, &key_cmd); + install_element (KEYCHAIN_NODE, &no_key_cmd); + + install_element (KEYCHAIN_NODE, &key_chain_cmd); + install_element (KEYCHAIN_NODE, &no_key_chain_cmd); + + install_element (KEYCHAIN_KEY_NODE, &key_string_cmd); + install_element (KEYCHAIN_KEY_NODE, &no_key_string_cmd); + + install_element (KEYCHAIN_KEY_NODE, &key_chain_cmd); + install_element (KEYCHAIN_KEY_NODE, &no_key_chain_cmd); + + install_element (KEYCHAIN_KEY_NODE, &key_cmd); + install_element (KEYCHAIN_KEY_NODE, &no_key_cmd); + + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_day_month_day_month_cmd); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_day_month_month_day_cmd); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_month_day_day_month_cmd); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_month_day_month_day_cmd); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_infinite_day_month_cmd); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_infinite_month_day_cmd); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_duration_day_month_cmd); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_duration_month_day_cmd); + + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_day_month_day_month_cmd); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_day_month_month_day_cmd); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_month_day_day_month_cmd); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_month_day_month_day_cmd); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_infinite_day_month_cmd); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_infinite_month_day_cmd); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_duration_day_month_cmd); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_duration_month_day_cmd); +} diff --git a/lib/keychain.h b/lib/keychain.h new file mode 100644 index 00000000..0cfa3d52 --- /dev/null +++ b/lib/keychain.h @@ -0,0 +1,56 @@ +/* key-chain for authentication. + * Copyright (C) 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_KEYCHAIN_H +#define _ZEBRA_KEYCHAIN_H + +struct keychain +{ + char *name; + + struct list *key; +}; + +struct key_range +{ + time_t start; + time_t end; + + u_char duration; +}; + +struct key +{ + u_int32_t index; + + char *string; + + struct key_range send; + struct key_range accept; +}; + +void keychain_init (); +struct keychain *keychain_lookup (char *); +struct key *key_lookup_for_accept (struct keychain *, u_int32_t); +struct key *key_match_for_accept (struct keychain *, char *); +struct key *key_lookup_for_send (struct keychain *); + +#endif /* _ZEBRA_KEYCHAIN_H */ diff --git a/lib/linklist.c b/lib/linklist.c new file mode 100644 index 00000000..5a2b6969 --- /dev/null +++ b/lib/linklist.c @@ -0,0 +1,312 @@ +/* Generic linked list routine. + * Copyright (C) 1997, 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "linklist.h" +#include "memory.h" + +/* Allocate new list. */ +struct list * +list_new () +{ + struct list *new; + + new = XMALLOC (MTYPE_LINK_LIST, sizeof (struct list)); + memset (new, 0, sizeof (struct list)); + return new; +} + +/* Free list. */ +void +list_free (struct list *l) +{ + XFREE (MTYPE_LINK_LIST, l); +} + +/* Allocate new listnode. Internal use only. */ +static struct listnode * +listnode_new () +{ + struct listnode *node; + + node = XMALLOC (MTYPE_LINK_NODE, sizeof (struct listnode)); + memset (node, 0, sizeof (struct listnode)); + return node; +} + +/* Free listnode. */ +static void +listnode_free (struct listnode *node) +{ + XFREE (MTYPE_LINK_NODE, node); +} + +/* Add new data to the list. */ +void +listnode_add (struct list *list, void *val) +{ + struct listnode *node; + + node = listnode_new (); + + node->prev = list->tail; + node->data = val; + + if (list->head == NULL) + list->head = node; + else + list->tail->next = node; + list->tail = node; + + list->count++; +} + +/* Add new node with sort function. */ +void +listnode_add_sort (struct list *list, void *val) +{ + struct listnode *n; + struct listnode *new; + + new = listnode_new (); + new->data = val; + + if (list->cmp) + { + for (n = list->head; n; n = n->next) + { + if ((*list->cmp) (val, n->data) < 0) + { + new->next = n; + new->prev = n->prev; + + if (n->prev) + n->prev->next = new; + else + list->head = new; + n->prev = new; + list->count++; + return; + } + } + } + + new->prev = list->tail; + + if (list->tail) + list->tail->next = new; + else + list->head = new; + + list->tail = new; + list->count++; +} + +void +listnode_add_after (struct list *list, struct listnode *pp, void *val) +{ + struct listnode *nn; + + nn = listnode_new (); + nn->data = val; + + if (pp == NULL) + { + if (list->head) + list->head->prev = nn; + else + list->tail = nn; + + nn->next = list->head; + nn->prev = pp; + + list->head = nn; + } + else + { + if (pp->next) + pp->next->prev = nn; + else + list->tail = nn; + + nn->next = pp->next; + nn->prev = pp; + + pp->next = nn; + } +} + + +/* Delete specific date pointer from the list. */ +void +listnode_delete (struct list *list, void *val) +{ + struct listnode *node; + + for (node = list->head; node; node = node->next) + { + if (node->data == val) + { + if (node->prev) + node->prev->next = node->next; + else + list->head = node->next; + + if (node->next) + node->next->prev = node->prev; + else + list->tail = node->prev; + + list->count--; + listnode_free (node); + return; + } + } +} + +/* Return first node's data if it is there. */ +void * +listnode_head (struct list *list) +{ + struct listnode *node; + + node = list->head; + + if (node) + return node->data; + return NULL; +} + +/* Delete all listnode from the list. */ +void +list_delete_all_node (struct list *list) +{ + struct listnode *node; + struct listnode *next; + + for (node = list->head; node; node = next) + { + next = node->next; + if (list->del) + (*list->del) (node->data); + listnode_free (node); + } + list->head = list->tail = NULL; + list->count = 0; +} + +/* Delete all listnode then free list itself. */ +void +list_delete (struct list *list) +{ + struct listnode *node; + struct listnode *next; + + for (node = list->head; node; node = next) + { + next = node->next; + if (list->del) + (*list->del) (node->data); + listnode_free (node); + } + list_free (list); +} + +/* Lookup the node which has given data. */ +struct listnode * +listnode_lookup (struct list *list, void *data) +{ + listnode node; + + for (node = list->head; node; nextnode (node)) + if (data == getdata (node)) + return node; + return NULL; +} + +/* Delete the node from list. For ospfd and ospf6d. */ +void +list_delete_node (list list, listnode node) +{ + if (node->prev) + node->prev->next = node->next; + else + list->head = node->next; + if (node->next) + node->next->prev = node->prev; + else + list->tail = node->prev; + list->count--; + listnode_free (node); +} + +/* ospf_spf.c */ +void +list_add_node_prev (list list, listnode current, void *val) +{ + struct listnode *node; + + node = listnode_new (); + node->next = current; + node->data = val; + + if (current->prev == NULL) + list->head = node; + else + current->prev->next = node; + + node->prev = current->prev; + current->prev = node; + + list->count++; +} + +/* ospf_spf.c */ +void +list_add_node_next (list list, listnode current, void *val) +{ + struct listnode *node; + + node = listnode_new (); + node->prev = current; + node->data = val; + + if (current->next == NULL) + list->tail = node; + else + current->next->prev = node; + + node->next = current->next; + current->next = node; + + list->count++; +} + +/* ospf_spf.c */ +void +list_add_list (struct list *l, struct list *m) +{ + struct listnode *n; + + for (n = listhead (m); n; nextnode (n)) + listnode_add (l, n->data); +} diff --git a/lib/linklist.h b/lib/linklist.h new file mode 100644 index 00000000..a91947c3 --- /dev/null +++ b/lib/linklist.h @@ -0,0 +1,101 @@ +/* Generic linked list + * Copyright (C) 1997, 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_LINKLIST_H +#define _ZEBRA_LINKLIST_H + +typedef struct list *list; +typedef struct listnode *listnode; + +struct listnode +{ + struct listnode *next; + struct listnode *prev; + void *data; +}; + +struct list +{ + struct listnode *head; + struct listnode *tail; + unsigned int count; + int (*cmp) (void *val1, void *val2); + void (*del) (void *val); +}; + +#define nextnode(X) ((X) = (X)->next) +#define listhead(X) ((X)->head) +#define listcount(X) ((X)->count) +#define list_isempty(X) ((X)->head == NULL && (X)->tail == NULL) +#define getdata(X) ((X)->data) + +/* Prototypes. */ +struct list *list_new(); +void list_free (struct list *); + +void listnode_add (struct list *, void *); +void listnode_add_sort (struct list *, void *); +void listnode_add_after (struct list *, struct listnode *, void *); +void listnode_delete (struct list *, void *); +struct listnode *listnode_lookup (struct list *, void *); +void *listnode_head (struct list *); + +void list_delete (struct list *); +void list_delete_all_node (struct list *); + +/* For ospfd and ospf6d. */ +void list_delete_node (list, listnode); + +/* For ospf_spf.c */ +void list_add_node_prev (list, listnode, void *); +void list_add_node_next (list, listnode, void *); +void list_add_list (list, list); + +/* List iteration macro. */ +#define LIST_LOOP(L,V,N) \ + for ((N) = (L)->head; (N); (N) = (N)->next) \ + if (((V) = (N)->data) != NULL) + +/* List node add macro. */ +#define LISTNODE_ADD(L,N) \ + do { \ + (N)->prev = (L)->tail; \ + if ((L)->head == NULL) \ + (L)->head = (N); \ + else \ + (L)->tail->next = (N); \ + (L)->tail = (N); \ + } while (0) + +/* List node delete macro. */ +#define LISTNODE_DELETE(L,N) \ + do { \ + if ((N)->prev) \ + (N)->prev->next = (N)->next; \ + else \ + (L)->head = (N)->next; \ + if ((N)->next) \ + (N)->next->prev = (N)->prev; \ + else \ + (L)->tail = (N)->prev; \ + } while (0) + +#endif /* _ZEBRA_LINKLIST_H */ diff --git a/lib/log.c b/lib/log.c new file mode 100644 index 00000000..9c676428 --- /dev/null +++ b/lib/log.c @@ -0,0 +1,483 @@ +/* Logging of zebra + * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "log.h" +#include "memory.h" +#include "command.h" + +struct zlog *zlog_default = NULL; + +const char *zlog_proto_names[] = +{ + "NONE", + "DEFAULT", + "ZEBRA", + "RIP", + "BGP", + "OSPF", + "RIPNG", + "OSPF6", + "MASC", + NULL, +}; + +const char *zlog_priority[] = +{ + "emergencies", + "alerts", + "critical", + "errors", + "warnings", + "notifications", + "informational", + "debugging", + NULL, +}; + + + +/* For time string format. */ +#define TIME_BUF 27 + +/* Utility routine for current time printing. */ +static void +time_print (FILE *fp) +{ + int ret; + char buf [TIME_BUF]; + time_t clock; + struct tm *tm; + + time (&clock); + tm = localtime (&clock); + + ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm); + if (ret == 0) { + zlog_warn ("strftime error"); + } + + fprintf (fp, "%s ", buf); +} + +/* va_list version of zlog. */ +void +vzlog (struct zlog *zl, int priority, const char *format, va_list *args) +{ + /* If zlog is not specified, use default one. */ + if (zl == NULL) + zl = zlog_default; + + /* When zlog_default is also NULL, use stderr for logging. */ + if (zl == NULL) + { + time_print (stderr); + fprintf (stderr, "%s: ", "unknown"); + vfprintf (stderr, format, args[ZLOG_NOLOG_INDEX]); + fprintf (stderr, "\n"); + fflush (stderr); + + /* In this case we return at here. */ + return; + } + + /* only log this information if it has not been masked out */ + if ( priority > zl->maskpri ) + return ; + + /* Syslog output */ + if (zl->flags & ZLOG_SYSLOG) + vsyslog (priority, format, args[ZLOG_SYSLOG_INDEX]); + + /* File output. */ + if (zl->flags & ZLOG_FILE) + { + time_print (zl->fp); + if (zl->record_priority) fprintf (zl->fp, "%s: ", zlog_priority[priority]); + fprintf (zl->fp, "%s: ", zlog_proto_names[zl->protocol]); + vfprintf (zl->fp, format, args[ZLOG_FILE_INDEX]); + fprintf (zl->fp, "\n"); + fflush (zl->fp); + } + + /* stdout output. */ + if (zl->flags & ZLOG_STDOUT) + { + time_print (stdout); + if (zl->record_priority) fprintf (stdout, "%s: ", zlog_priority[priority]); + fprintf (stdout, "%s: ", zlog_proto_names[zl->protocol]); + vfprintf (stdout, format, args[ZLOG_STDOUT_INDEX]); + fprintf (stdout, "\n"); + fflush (stdout); + } + + /* stderr output. */ + if (zl->flags & ZLOG_STDERR) + { + time_print (stderr); + if (zl->record_priority) fprintf (stderr, "%s: ", zlog_priority[priority]); + fprintf (stderr, "%s: ", zlog_proto_names[zl->protocol]); + vfprintf (stderr, format, args[ZLOG_STDERR_INDEX]); + fprintf (stderr, "\n"); + fflush (stderr); + } + + /* Terminal monitor. */ + vty_log (zlog_proto_names[zl->protocol], format, args[ZLOG_NOLOG_INDEX]); +} + +void +zlog (struct zlog *zl, int priority, const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (zl, priority, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +zlog_err (const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (NULL, LOG_ERR, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +zlog_warn (const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (NULL, LOG_WARNING, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +zlog_info (const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (NULL, LOG_INFO, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +zlog_notice (const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (NULL, LOG_NOTICE, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +zlog_debug (const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (NULL, LOG_DEBUG, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +plog_err (struct zlog *zl, const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (zl, LOG_ERR, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +plog_warn (struct zlog *zl, const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (zl, LOG_WARNING, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +plog_info (struct zlog *zl, const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (zl, LOG_INFO, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +plog_notice (struct zlog *zl, const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (zl, LOG_NOTICE, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +plog_debug (struct zlog *zl, const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (zl, LOG_DEBUG, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + + +/* Open log stream */ +struct zlog * +openzlog (const char *progname, int flags, zlog_proto_t protocol, + int syslog_flags, int syslog_facility) +{ + struct zlog *zl; + + zl = XMALLOC(MTYPE_ZLOG, sizeof (struct zlog)); + memset (zl, 0, sizeof (struct zlog)); + + zl->ident = progname; + zl->flags = flags; + zl->protocol = protocol; + zl->facility = syslog_facility; + zl->maskpri = LOG_DEBUG; + zl->record_priority = 0; + + openlog (progname, syslog_flags, zl->facility); + + return zl; +} + +void +closezlog (struct zlog *zl) +{ + closelog(); + fclose (zl->fp); + + XFREE (MTYPE_ZLOG, zl); +} + +/* Called from command.c. */ +void +zlog_set_flag (struct zlog *zl, int flags) +{ + if (zl == NULL) + zl = zlog_default; + + zl->flags |= flags; +} + +void +zlog_reset_flag (struct zlog *zl, int flags) +{ + if (zl == NULL) + zl = zlog_default; + + zl->flags &= ~flags; +} + +int +zlog_set_file (struct zlog *zl, int flags, char *filename) +{ + FILE *fp; + + /* There is opend file. */ + zlog_reset_file (zl); + + /* Set default zl. */ + if (zl == NULL) + zl = zlog_default; + + /* Open file. */ + fp = fopen (filename, "a"); + if (fp == NULL) + return 0; + + /* Set flags. */ + zl->filename = strdup (filename); + zl->flags |= ZLOG_FILE; + zl->fp = fp; + + return 1; +} + +/* Reset opend file. */ +int +zlog_reset_file (struct zlog *zl) +{ + if (zl == NULL) + zl = zlog_default; + + zl->flags &= ~ZLOG_FILE; + + if (zl->fp) + fclose (zl->fp); + zl->fp = NULL; + + if (zl->filename) + free (zl->filename); + zl->filename = NULL; + + return 1; +} + +/* Reopen log file. */ +int +zlog_rotate (struct zlog *zl) +{ + FILE *fp; + + if (zl == NULL) + zl = zlog_default; + + if (zl->fp) + fclose (zl->fp); + zl->fp = NULL; + + if (zl->filename) + { + fp = fopen (zl->filename, "a"); + if (fp == NULL) + return -1; + zl->fp = fp; + } + + return 1; +} + +static char *zlog_cwd = NULL; + +void +zlog_save_cwd () +{ + char *cwd; + + cwd = getcwd (NULL, MAXPATHLEN); + + zlog_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1); + strcpy (zlog_cwd, cwd); +} + +char * +zlog_get_cwd () +{ + return zlog_cwd; +} + +void +zlog_free_cwd () +{ + if (zlog_cwd) + XFREE (MTYPE_TMP, zlog_cwd); +} + +/* Message lookup function. */ +char * +lookup (struct message *mes, int key) +{ + struct message *pnt; + + for (pnt = mes; pnt->key != 0; pnt++) + if (pnt->key == key) + return pnt->str; + + return ""; +} + +/* Very old hacky version of message lookup function. Still partly + used in bgpd and ospfd. */ +char * +mes_lookup (struct message *meslist, int max, int index) +{ + if (index < 0 || index >= max) + { + zlog_err ("message index out of bound: %d", max); + return NULL; + } + return meslist[index].str; +} diff --git a/lib/log.h b/lib/log.h new file mode 100644 index 00000000..69919b49 --- /dev/null +++ b/lib/log.h @@ -0,0 +1,128 @@ +/* Zebra logging funcions. + * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_LOG_H +#define _ZEBRA_LOG_H + +#include + +#define ZLOG_NOLOG 0x00 +#define ZLOG_FILE 0x01 +#define ZLOG_SYSLOG 0x02 +#define ZLOG_STDOUT 0x04 +#define ZLOG_STDERR 0x08 + +#define ZLOG_NOLOG_INDEX 0 +#define ZLOG_FILE_INDEX 1 +#define ZLOG_SYSLOG_INDEX 2 +#define ZLOG_STDOUT_INDEX 3 +#define ZLOG_STDERR_INDEX 4 +#define ZLOG_MAX_INDEX 5 + +typedef enum +{ + ZLOG_NONE, + ZLOG_DEFAULT, + ZLOG_ZEBRA, + ZLOG_RIP, + ZLOG_BGP, + ZLOG_OSPF, + ZLOG_RIPNG, + ZLOG_OSPF6, + ZLOG_MASC +} zlog_proto_t; + +struct zlog +{ + const char *ident; + zlog_proto_t protocol; + int flags; + FILE *fp; + char *filename; + int syslog; + int stat; + int connected; + int maskpri; /* as per syslog setlogmask */ + int priority; /* as per syslog priority */ + int facility; /* as per syslog facility */ + int record_priority; +}; + +/* Message structure. */ +struct message +{ + int key; + char *str; +}; + +/* Default logging strucutre. */ +extern struct zlog *zlog_default; + +/* Open zlog function */ +struct zlog *openzlog (const char *, int, zlog_proto_t, int, int); + +/* Close zlog function. */ +void closezlog (struct zlog *zl); + +/* GCC have printf type attribute check. */ +#ifdef __GNUC__ +#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b))) +#else +#define PRINTF_ATTRIBUTE(a,b) +#endif /* __GNUC__ */ + +/* Generic function for zlog. */ +void zlog (struct zlog *zl, int priority, const char *format, ...) PRINTF_ATTRIBUTE(3, 4); + +/* Handy zlog functions. */ +void zlog_err (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); +void zlog_warn (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); +void zlog_info (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); +void zlog_notice (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); +void zlog_debug (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); + +/* For bgpd's peer oriented log. */ +void plog_err (struct zlog *, const char *format, ...); +void plog_warn (struct zlog *, const char *format, ...); +void plog_info (struct zlog *, const char *format, ...); +void plog_notice (struct zlog *, const char *format, ...); +void plog_debug (struct zlog *, const char *format, ...); + +/* Set zlog flags. */ +void zlog_set_flag (struct zlog *zl, int flags); +void zlog_reset_flag (struct zlog *zl, int flags); + +/* Set zlog filename. */ +int zlog_set_file (struct zlog *zl, int flags, char *filename); +int zlog_reset_file (struct zlog *zl); + +/* Rotate log. */ +int zlog_rotate (); + +/* For hackey massage lookup and check */ +#define LOOKUP(x, y) mes_lookup(x, x ## _max, y) + +char *lookup (struct message *, int); +char *mes_lookup (struct message *meslist, int max, int index); + +extern const char *zlog_priority[]; + +#endif /* _ZEBRA_LOG_H */ diff --git a/lib/md5-gnu.h b/lib/md5-gnu.h new file mode 100644 index 00000000..dacc1ae7 --- /dev/null +++ b/lib/md5-gnu.h @@ -0,0 +1,156 @@ +/* Declaration of functions and data types used for MD5 sum computing + library functions. + Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _MD5_H +#define _MD5_H 1 + +#include + +#if defined HAVE_LIMITS_H || _LIBC +# include +#endif + +/* The following contortions are an attempt to use the C preprocessor + to determine an unsigned integral type that is 32 bits wide. An + alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but + doing that would require that the configure script compile and *run* + the resulting executable. Locally running cross-compiled executables + is usually not possible. */ + +#ifdef _LIBC +# include +typedef u_int32_t md5_uint32; +#else +# if defined __STDC__ && __STDC__ +# define UINT_MAX_32_BITS 4294967295U +# else +# define UINT_MAX_32_BITS 0xFFFFFFFF +# endif + +/* If UINT_MAX isn't defined, assume it's a 32-bit type. + This should be valid for all systems GNU cares about because + that doesn't include 16-bit systems, and only modern systems + (that certainly have ) have 64+-bit integral types. */ + +# ifndef UINT_MAX +# define UINT_MAX UINT_MAX_32_BITS +# endif + +# if UINT_MAX == UINT_MAX_32_BITS + typedef unsigned int md5_uint32; +# else +# if USHRT_MAX == UINT_MAX_32_BITS + typedef unsigned short md5_uint32; +# else +# if ULONG_MAX == UINT_MAX_32_BITS + typedef unsigned long md5_uint32; +# else + /* The following line is intended to evoke an error. + Using #error is not portable enough. */ + "Cannot determine unsigned 32-bit data type." +# endif +# endif +# endif +#endif + +#undef __P +#if defined (__STDC__) && __STDC__ +# define __P(x) x +#else +# define __P(x) () +#endif + +/* Structure to save state of computation between the single steps. */ +struct md5_ctx +{ + md5_uint32 A; + md5_uint32 B; + md5_uint32 C; + md5_uint32 D; + + md5_uint32 total[2]; + md5_uint32 buflen; + char buffer[128]; +}; + +/* + * The following three functions are build up the low level used in + * the functions `md5_stream' and `md5_buffer'. + */ + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +extern void __md5_init_ctx __P ((struct md5_ctx *ctx)); +extern void md5_init_ctx __P ((struct md5_ctx *ctx)); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +extern void __md5_process_block __P ((const void *buffer, size_t len, + struct md5_ctx *ctx)); +extern void md5_process_block __P ((const void *buffer, size_t len, + struct md5_ctx *ctx)); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ +extern void __md5_process_bytes __P ((const void *buffer, size_t len, + struct md5_ctx *ctx)); +extern void md5_process_bytes __P ((const void *buffer, size_t len, + struct md5_ctx *ctx)); + +/* Process the remaining bytes in the buffer and put result from CTX + in first 16 bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +extern void *__md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf)); +extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf)); + + +/* Put result from CTX in first 16 bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +extern void *__md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf)); +extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf)); + + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +extern int __md5_stream __P ((FILE *stream, void *resblock)); + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *__md5_buffer __P ((const char *buffer, size_t len, + void *resblock)); +extern void *md5_buffer __P ((const char *buffer, size_t len, + void *resblock)); + +#endif /* md5.h */ diff --git a/lib/md5.c b/lib/md5.c new file mode 100644 index 00000000..2068c46d --- /dev/null +++ b/lib/md5.c @@ -0,0 +1,447 @@ +/* md5.c - Functions to compute MD5 message digest of files or memory blocks + according to the definition of MD5 in RFC 1321 from April 1992. + Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* Written by Ulrich Drepper , 1995. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#if STDC_HEADERS || defined _LIBC +# include +# include +#else +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# endif +#endif + +#include "md5-gnu.h" + +#ifdef _LIBC +# include +# if __BYTE_ORDER == __BIG_ENDIAN +# define WORDS_BIGENDIAN 1 +# endif +/* We need to keep the namespace clean so define the MD5 function + protected using leading __ and use weak aliases. */ +# define md5_init_ctx __md5_init_ctx +# define md5_process_block __md5_process_block +# define md5_process_bytes __md5_process_bytes +# define md5_finish_ctx __md5_finish_ctx +# define md5_read_ctx __md5_read_ctx +# define md5_stream __md5_stream +# define md5_buffer __md5_buffer +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#else +# define SWAP(n) (n) +#endif + + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. (RFC 1321, 3.1: Step 1) */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +void +md5_init_ctx (ctx) + struct md5_ctx *ctx; +{ + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* Put result from CTX in first 16 bytes following RESBUF. The result + must be in little endian byte order. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +md5_read_ctx (ctx, resbuf) + const struct md5_ctx *ctx; + void *resbuf; +{ + ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A); + ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B); + ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C); + ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +md5_finish_ctx (ctx, resbuf) + struct md5_ctx *ctx; + void *resbuf; +{ + /* Take yet unprocessed bytes into account. */ + md5_uint32 bytes = ctx->buflen; + size_t pad; + + /* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; + memcpy (&ctx->buffer[bytes], fillbuf, pad); + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3); + *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) | + (ctx->total[0] >> 29)); + + /* Process last bytes. */ + md5_process_block (ctx->buffer, bytes + pad + 8, ctx); + + return md5_read_ctx (ctx, resbuf); +} + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +int +md5_stream (stream, resblock) + FILE *stream; + void *resblock; +{ + /* Important: BLOCKSIZE must be a multiple of 64. */ +#define BLOCKSIZE 4096 + struct md5_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + do + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + } + while (sum < BLOCKSIZE && n != 0); + if (n == 0 && ferror (stream)) + return 1; + + /* If end of file is reached, end the loop. */ + if (n == 0) + break; + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + md5_process_block (buffer, BLOCKSIZE, &ctx); + } + + /* Add the last bytes if necessary. */ + if (sum > 0) + md5_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + md5_finish_ctx (&ctx, resblock); + return 0; +} + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +md5_buffer (buffer, len, resblock) + const char *buffer; + size_t len; + void *resblock; +{ + struct md5_ctx ctx; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + md5_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return md5_finish_ctx (&ctx, resblock); +} + + +void +md5_process_bytes (buffer, len, ctx) + const void *buffer; + size_t len; + struct md5_ctx *ctx; +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy (&ctx->buffer[left_over], buffer, add); + ctx->buflen += add; + + if (left_over + add > 64) + { + md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx); + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], + (left_over + add) & 63); + ctx->buflen = (left_over + add) & 63; + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len > 64) + { + md5_process_block (buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + memcpy (ctx->buffer, buffer, len); + ctx->buflen = len; + } +} + + +/* These are the four functions used in the four steps of the MD5 algorithm + and defined in the RFC 1321. The first function is a little bit optimized + (as found in Colin Plumbs public domain implementation). */ +/* #define FF(b, c, d) ((b & c) | (~b & d)) */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF (d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. */ + +void +md5_process_block (buffer, len, ctx) + const void *buffer; + size_t len; + struct md5_ctx *ctx; +{ + md5_uint32 correct_words[16]; + const md5_uint32 *words = buffer; + size_t nwords = len / sizeof (md5_uint32); + const md5_uint32 *endp = words + nwords; + md5_uint32 A = ctx->A; + md5_uint32 B = ctx->B; + md5_uint32 C = ctx->C; + md5_uint32 D = ctx->D; + + /* First increment the byte count. RFC 1321 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += len; + if (ctx->total[0] < len) + ++ctx->total[1]; + + /* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + while (words < endp) + { + md5_uint32 *cwp = correct_words; + md5_uint32 A_save = A; + md5_uint32 B_save = B; + md5_uint32 C_save = C; + md5_uint32 D_save = D; + + /* First round: using the given function, the context and a constant + the next context is computed. Because the algorithms processing + unit is a 32-bit word and it is determined to work on words in + little endian byte order we perhaps have to change the byte order + before the computation. To reduce the work for the next steps + we store the swapped words in the array CORRECT_WORDS. */ + +#define OP(a, b, c, d, s, T) \ + do \ + { \ + a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ + ++words; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* It is unfortunate that C does not provide an operator for + cyclic rotation. Hope the C compiler is smart enough. */ +#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) + + /* Before we start, one word to the strange constants. + They are defined in RFC 1321 as + + T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 + */ + + /* Round 1. */ + OP (A, B, C, D, 7, 0xd76aa478); + OP (D, A, B, C, 12, 0xe8c7b756); + OP (C, D, A, B, 17, 0x242070db); + OP (B, C, D, A, 22, 0xc1bdceee); + OP (A, B, C, D, 7, 0xf57c0faf); + OP (D, A, B, C, 12, 0x4787c62a); + OP (C, D, A, B, 17, 0xa8304613); + OP (B, C, D, A, 22, 0xfd469501); + OP (A, B, C, D, 7, 0x698098d8); + OP (D, A, B, C, 12, 0x8b44f7af); + OP (C, D, A, B, 17, 0xffff5bb1); + OP (B, C, D, A, 22, 0x895cd7be); + OP (A, B, C, D, 7, 0x6b901122); + OP (D, A, B, C, 12, 0xfd987193); + OP (C, D, A, B, 17, 0xa679438e); + OP (B, C, D, A, 22, 0x49b40821); + + /* For the second to fourth round we have the possibly swapped words + in CORRECT_WORDS. Redefine the macro to take an additional first + argument specifying the function to use. */ +#undef OP +#define OP(f, a, b, c, d, k, s, T) \ + do \ + { \ + a += f (b, c, d) + correct_words[k] + T; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* Round 2. */ + OP (FG, A, B, C, D, 1, 5, 0xf61e2562); + OP (FG, D, A, B, C, 6, 9, 0xc040b340); + OP (FG, C, D, A, B, 11, 14, 0x265e5a51); + OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); + OP (FG, A, B, C, D, 5, 5, 0xd62f105d); + OP (FG, D, A, B, C, 10, 9, 0x02441453); + OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); + OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); + OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); + OP (FG, D, A, B, C, 14, 9, 0xc33707d6); + OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); + OP (FG, B, C, D, A, 8, 20, 0x455a14ed); + OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); + OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); + OP (FG, C, D, A, B, 7, 14, 0x676f02d9); + OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); + + /* Round 3. */ + OP (FH, A, B, C, D, 5, 4, 0xfffa3942); + OP (FH, D, A, B, C, 8, 11, 0x8771f681); + OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); + OP (FH, B, C, D, A, 14, 23, 0xfde5380c); + OP (FH, A, B, C, D, 1, 4, 0xa4beea44); + OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); + OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); + OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); + OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); + OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); + OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); + OP (FH, B, C, D, A, 6, 23, 0x04881d05); + OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); + OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); + OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); + OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); + + /* Round 4. */ + OP (FI, A, B, C, D, 0, 6, 0xf4292244); + OP (FI, D, A, B, C, 7, 10, 0x432aff97); + OP (FI, C, D, A, B, 14, 15, 0xab9423a7); + OP (FI, B, C, D, A, 5, 21, 0xfc93a039); + OP (FI, A, B, C, D, 12, 6, 0x655b59c3); + OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); + OP (FI, C, D, A, B, 10, 15, 0xffeff47d); + OP (FI, B, C, D, A, 1, 21, 0x85845dd1); + OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); + OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); + OP (FI, C, D, A, B, 6, 15, 0xa3014314); + OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); + OP (FI, A, B, C, D, 4, 6, 0xf7537e82); + OP (FI, D, A, B, C, 11, 10, 0xbd3af235); + OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); + OP (FI, B, C, D, A, 9, 21, 0xeb86d391); + + /* Add the starting values of the context. */ + A += A_save; + B += B_save; + C += C_save; + D += D_save; + } + + /* Put checksum in context given as argument. */ + ctx->A = A; + ctx->B = B; + ctx->C = C; + ctx->D = D; +} + + +#ifdef _LIBC +/* Define weak aliases. */ +# undef md5_init_ctx +weak_alias (__md5_init_ctx, md5_init_ctx) +# undef md5_process_block +weak_alias (__md5_process_block, md5_process_block) +# undef md5_process_bytes +weak_alias (__md5_process_bytes, md5_process_bytes) +# undef md5_finish_ctx +weak_alias (__md5_finish_ctx, md5_finish_ctx) +# undef md5_read_ctx +weak_alias (__md5_read_ctx, md5_read_ctx) +# undef md5_stream +weak_alias (__md5_stream, md5_stream) +# undef md5_buffer +weak_alias (__md5_buffer, md5_buffer) +#endif diff --git a/lib/memory.c b/lib/memory.c new file mode 100644 index 00000000..bf142dcf --- /dev/null +++ b/lib/memory.c @@ -0,0 +1,493 @@ +/* + * Memory management routine + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "log.h" +#include "memory.h" + +void alloc_inc (int); +void alloc_dec (int); + +struct message mstr [] = +{ + { MTYPE_THREAD, "thread" }, + { MTYPE_THREAD_MASTER, "thread_master" }, + { MTYPE_VECTOR, "vector" }, + { MTYPE_VECTOR_INDEX, "vector_index" }, + { MTYPE_IF, "interface" }, + { 0, NULL }, +}; + +/* Fatal memory allocation error occured. */ +static void +zerror (const char *fname, int type, size_t size) +{ + fprintf (stderr, "%s : can't allocate memory for `%s' size %d\n", + fname, lookup (mstr, type), (int) size); + exit (1); +} + +/* Memory allocation. */ +void * +zmalloc (int type, size_t size) +{ + void *memory; + + memory = malloc (size); + + if (memory == NULL) + zerror ("malloc", type, size); + + alloc_inc (type); + + return memory; +} + +/* Memory allocation with num * size with cleared. */ +void * +zcalloc (int type, size_t size) +{ + void *memory; + + memory = calloc (1, size); + + if (memory == NULL) + zerror ("calloc", type, size); + + alloc_inc (type); + + return memory; +} + +/* Memory reallocation. */ +void * +zrealloc (int type, void *ptr, size_t size) +{ + void *memory; + + memory = realloc (ptr, size); + if (memory == NULL) + zerror ("realloc", type, size); + return memory; +} + +/* Memory free. */ +void +zfree (int type, void *ptr) +{ + alloc_dec (type); + free (ptr); +} + +/* String duplication. */ +char * +zstrdup (int type, char *str) +{ + void *dup; + + dup = strdup (str); + if (dup == NULL) + zerror ("strdup", type, strlen (str)); + alloc_inc (type); + return dup; +} + +#ifdef MEMORY_LOG +struct +{ + char *name; + unsigned long alloc; + unsigned long t_malloc; + unsigned long c_malloc; + unsigned long t_calloc; + unsigned long c_calloc; + unsigned long t_realloc; + unsigned long t_free; + unsigned long c_strdup; +} mstat [MTYPE_MAX]; + +void +mtype_log (char *func, void *memory, const char *file, int line, int type) +{ + zlog_info ("%s: %s %p %s %d", func, lookup (mstr, type), memory, file, line); +} + +void * +mtype_zmalloc (const char *file, int line, int type, size_t size) +{ + void *memory; + + mstat[type].c_malloc++; + mstat[type].t_malloc++; + + memory = zmalloc (type, size); + mtype_log ("zmalloc", memory, file, line, type); + + return memory; +} + +void * +mtype_zcalloc (const char *file, int line, int type, size_t size) +{ + void *memory; + + mstat[type].c_calloc++; + mstat[type].t_calloc++; + + memory = zcalloc (type, size); + mtype_log ("xcalloc", memory, file, line, type); + + return memory; +} + +void * +mtype_zrealloc (const char *file, int line, int type, void *ptr, size_t size) +{ + void *memory; + + /* Realloc need before allocated pointer. */ + mstat[type].t_realloc++; + + memory = zrealloc (type, ptr, size); + + mtype_log ("xrealloc", memory, file, line, type); + + return memory; +} + +/* Important function. */ +void +mtype_zfree (const char *file, int line, int type, void *ptr) +{ + mstat[type].t_free++; + + mtype_log ("xfree", ptr, file, line, type); + + zfree (type, ptr); +} + +char * +mtype_zstrdup (const char *file, int line, int type, char *str) +{ + char *memory; + + mstat[type].c_strdup++; + + memory = zstrdup (type, str); + + mtype_log ("xstrdup", memory, file, line, type); + + return memory; +} +#else +struct +{ + char *name; + unsigned long alloc; +} mstat [MTYPE_MAX]; +#endif /* MTPYE_LOG */ + +/* Increment allocation counter. */ +void +alloc_inc (int type) +{ + mstat[type].alloc++; +} + +/* Decrement allocation counter. */ +void +alloc_dec (int type) +{ + mstat[type].alloc--; +} + +/* Looking up memory status from vty interface. */ +#include "vector.h" +#include "vty.h" +#include "command.h" + +/* For pretty printng of memory allocate information. */ +struct memory_list +{ + int index; + char *format; +}; + +struct memory_list memory_list_lib[] = +{ + { MTYPE_TMP, "Temporary memory" }, + { MTYPE_ROUTE_TABLE, "Route table " }, + { MTYPE_ROUTE_NODE, "Route node " }, + { MTYPE_RIB, "RIB " }, + { MTYPE_NEXTHOP, "Nexthop " }, + { MTYPE_LINK_LIST, "Link List " }, + { MTYPE_LINK_NODE, "Link Node " }, + { MTYPE_HASH, "Hash " }, + { MTYPE_HASH_BACKET, "Hash Bucket " }, + { MTYPE_ACCESS_LIST, "Access List " }, + { MTYPE_ACCESS_LIST_STR, "Access List Str " }, + { MTYPE_ACCESS_FILTER, "Access Filter " }, + { MTYPE_PREFIX_LIST, "Prefix List " }, + { MTYPE_PREFIX_LIST_STR, "Prefix List Str " }, + { MTYPE_PREFIX_LIST_ENTRY, "Prefix List Entry "}, + { MTYPE_ROUTE_MAP, "Route map " }, + { MTYPE_ROUTE_MAP_NAME, "Route map name " }, + { MTYPE_ROUTE_MAP_INDEX, "Route map index " }, + { MTYPE_ROUTE_MAP_RULE, "Route map rule " }, + { MTYPE_ROUTE_MAP_RULE_STR, "Route map rule str" }, + { MTYPE_DESC, "Command desc " }, + { MTYPE_BUFFER, "Buffer " }, + { MTYPE_BUFFER_DATA, "Buffer data " }, + { MTYPE_STREAM, "Stream " }, + { MTYPE_KEYCHAIN, "Key chain " }, + { MTYPE_KEY, "Key " }, + { MTYPE_VTY, "VTY " }, + { -1, NULL } +}; + +struct memory_list memory_list_bgp[] = +{ + { MTYPE_BGP_PEER, "BGP peer" }, + { MTYPE_ATTR, "BGP attribute" }, + { MTYPE_AS_PATH, "BGP aspath" }, + { MTYPE_AS_SEG, "BGP aspath seg" }, + { MTYPE_AS_STR, "BGP aspath str" }, + { 0, NULL }, + { MTYPE_BGP_TABLE, "BGP table" }, + { MTYPE_BGP_NODE, "BGP node" }, + { MTYPE_BGP_ADVERTISE_ATTR, "BGP adv attr" }, + { MTYPE_BGP_ADVERTISE, "BGP adv" }, + { MTYPE_BGP_ADJ_IN, "BGP adj in" }, + { MTYPE_BGP_ADJ_OUT, "BGP adj out" }, + { 0, NULL }, + { MTYPE_AS_LIST, "BGP AS list" }, + { MTYPE_AS_FILTER, "BGP AS filter" }, + { MTYPE_AS_FILTER_STR, "BGP AS filter str" }, + { 0, NULL }, + { MTYPE_COMMUNITY, "community" }, + { MTYPE_COMMUNITY_VAL, "community val" }, + { MTYPE_COMMUNITY_STR, "community str" }, + { 0, NULL }, + { MTYPE_ECOMMUNITY, "extcommunity" }, + { MTYPE_ECOMMUNITY_VAL, "extcommunity val" }, + { MTYPE_ECOMMUNITY_STR, "extcommunity str" }, + { 0, NULL }, + { MTYPE_COMMUNITY_LIST, "community-list" }, + { MTYPE_COMMUNITY_LIST_NAME, "community-list name" }, + { MTYPE_COMMUNITY_LIST_ENTRY, "community-list entry" }, + { MTYPE_COMMUNITY_LIST_CONFIG, "community-list config" }, + { 0, NULL }, + { MTYPE_CLUSTER, "Cluster list" }, + { MTYPE_CLUSTER_VAL, "Cluster list val" }, + { 0, NULL }, + { MTYPE_TRANSIT, "BGP transit attr" }, + { MTYPE_TRANSIT_VAL, "BGP transit val" }, + { 0, NULL }, + { MTYPE_BGP_DISTANCE, "BGP distance" }, + { MTYPE_BGP_NEXTHOP_CACHE, "BGP nexthop" }, + { MTYPE_BGP_CONFED_LIST, "BGP confed list" }, + { MTYPE_PEER_UPDATE_SOURCE, "peer update if" }, + { MTYPE_BGP_DAMP_INFO, "Dampening info" }, + { MTYPE_BGP_REGEXP, "BGP regexp" }, + { -1, NULL } +}; + +struct memory_list memory_list_rip[] = +{ + { MTYPE_RIP, "RIP structure " }, + { MTYPE_RIP_INFO, "RIP route info " }, + { MTYPE_RIP_INTERFACE, "RIP interface " }, + { MTYPE_RIP_PEER, "RIP peer " }, + { MTYPE_RIP_OFFSET_LIST, "RIP offset list " }, + { MTYPE_RIP_DISTANCE, "RIP distance " }, + { -1, NULL } +}; + +struct memory_list memory_list_ospf[] = +{ + { MTYPE_OSPF_TOP, "OSPF top " }, + { MTYPE_OSPF_AREA, "OSPF area " }, + { MTYPE_OSPF_AREA_RANGE, "OSPF area range " }, + { MTYPE_OSPF_NETWORK, "OSPF network " }, +#ifdef NBMA_ENABLE + { MTYPE_OSPF_NEIGHBOR_STATIC,"OSPF static nbr " }, +#endif /* NBMA_ENABLE */ + { MTYPE_OSPF_IF, "OSPF interface " }, + { MTYPE_OSPF_NEIGHBOR, "OSPF neighbor " }, + { MTYPE_OSPF_ROUTE, "OSPF route " }, + { MTYPE_OSPF_TMP, "OSPF tmp mem " }, + { MTYPE_OSPF_LSA, "OSPF LSA " }, + { MTYPE_OSPF_LSA_DATA, "OSPF LSA data " }, + { MTYPE_OSPF_LSDB, "OSPF LSDB " }, + { MTYPE_OSPF_PACKET, "OSPF packet " }, + { MTYPE_OSPF_FIFO, "OSPF FIFO queue " }, + { MTYPE_OSPF_VERTEX, "OSPF vertex " }, + { MTYPE_OSPF_NEXTHOP, "OSPF nexthop " }, + { MTYPE_OSPF_PATH, "OSPF path " }, + { MTYPE_OSPF_VL_DATA, "OSPF VL data " }, + { MTYPE_OSPF_CRYPT_KEY, "OSPF crypt key " }, + { MTYPE_OSPF_EXTERNAL_INFO, "OSPF ext. info " }, + { MTYPE_OSPF_DISTANCE, "OSPF distance " }, + { MTYPE_OSPF_IF_INFO, "OSPF if info " }, + { MTYPE_OSPF_IF_PARAMS, "OSPF if params " }, + { -1, NULL }, +}; + +struct memory_list memory_list_ospf6[] = +{ + { MTYPE_OSPF6_TOP, "OSPF6 top " }, + { MTYPE_OSPF6_AREA, "OSPF6 area " }, + { MTYPE_OSPF6_IF, "OSPF6 interface " }, + { MTYPE_OSPF6_NEIGHBOR, "OSPF6 neighbor " }, + { MTYPE_OSPF6_ROUTE, "OSPF6 route " }, + { MTYPE_OSPF6_PREFIX, "OSPF6 prefix " }, + { MTYPE_OSPF6_MESSAGE, "OSPF6 message " }, + { MTYPE_OSPF6_LSA, "OSPF6 LSA " }, + { MTYPE_OSPF6_LSA_SUMMARY, "OSPF6 LSA summary " }, + { MTYPE_OSPF6_LSDB, "OSPF6 LSA database" }, + { MTYPE_OSPF6_VERTEX, "OSPF6 vertex " }, + { MTYPE_OSPF6_SPFTREE, "OSPF6 SPF tree " }, + { MTYPE_OSPF6_NEXTHOP, "OSPF6 nexthop " }, + { MTYPE_OSPF6_EXTERNAL_INFO,"OSPF6 ext. info " }, + { MTYPE_OSPF6_OTHER, "OSPF6 other " }, + { -1, NULL }, +}; + +struct memory_list memory_list_separator[] = +{ + { 0, NULL}, + {-1, NULL} +}; + +void +show_memory_vty (struct vty *vty, struct memory_list *list) +{ + struct memory_list *m; + + for (m = list; m->index >= 0; m++) + if (m->index == 0) + vty_out (vty, "-----------------------------\r\n"); + else + vty_out (vty, "%-22s: %5ld\r\n", m->format, mstat[m->index].alloc); +} + +DEFUN (show_memory_all, + show_memory_all_cmd, + "show memory all", + "Show running system information\n" + "Memory statistics\n" + "All memory statistics\n") +{ + show_memory_vty (vty, memory_list_lib); + show_memory_vty (vty, memory_list_separator); + show_memory_vty (vty, memory_list_rip); + show_memory_vty (vty, memory_list_separator); + show_memory_vty (vty, memory_list_ospf); + show_memory_vty (vty, memory_list_separator); + show_memory_vty (vty, memory_list_ospf6); + show_memory_vty (vty, memory_list_separator); + show_memory_vty (vty, memory_list_bgp); + + return CMD_SUCCESS; +} + +ALIAS (show_memory_all, + show_memory_cmd, + "show memory", + "Show running system information\n" + "Memory statistics\n") + +DEFUN (show_memory_lib, + show_memory_lib_cmd, + "show memory lib", + SHOW_STR + "Memory statistics\n" + "Library memory\n") +{ + show_memory_vty (vty, memory_list_lib); + return CMD_SUCCESS; +} + +DEFUN (show_memory_rip, + show_memory_rip_cmd, + "show memory rip", + SHOW_STR + "Memory statistics\n" + "RIP memory\n") +{ + show_memory_vty (vty, memory_list_rip); + return CMD_SUCCESS; +} + +DEFUN (show_memory_bgp, + show_memory_bgp_cmd, + "show memory bgp", + SHOW_STR + "Memory statistics\n" + "BGP memory\n") +{ + show_memory_vty (vty, memory_list_bgp); + return CMD_SUCCESS; +} + +DEFUN (show_memory_ospf, + show_memory_ospf_cmd, + "show memory ospf", + SHOW_STR + "Memory statistics\n" + "OSPF memory\n") +{ + show_memory_vty (vty, memory_list_ospf); + return CMD_SUCCESS; +} + +DEFUN (show_memory_ospf6, + show_memory_ospf6_cmd, + "show memory ospf6", + SHOW_STR + "Memory statistics\n" + "OSPF6 memory\n") +{ + show_memory_vty (vty, memory_list_ospf6); + return CMD_SUCCESS; +} + +void +memory_init () +{ + install_element (VIEW_NODE, &show_memory_cmd); + install_element (VIEW_NODE, &show_memory_all_cmd); + install_element (VIEW_NODE, &show_memory_lib_cmd); + install_element (VIEW_NODE, &show_memory_rip_cmd); + install_element (VIEW_NODE, &show_memory_bgp_cmd); + install_element (VIEW_NODE, &show_memory_ospf_cmd); + install_element (VIEW_NODE, &show_memory_ospf6_cmd); + + install_element (ENABLE_NODE, &show_memory_cmd); + install_element (ENABLE_NODE, &show_memory_all_cmd); + install_element (ENABLE_NODE, &show_memory_lib_cmd); + install_element (ENABLE_NODE, &show_memory_rip_cmd); + install_element (ENABLE_NODE, &show_memory_bgp_cmd); + install_element (ENABLE_NODE, &show_memory_ospf_cmd); + install_element (ENABLE_NODE, &show_memory_ospf6_cmd); +} diff --git a/lib/memory.h b/lib/memory.h new file mode 100644 index 00000000..52e3bc11 --- /dev/null +++ b/lib/memory.h @@ -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 index 00000000..b68761bc --- /dev/null +++ b/lib/network.c @@ -0,0 +1,71 @@ +/* + * Network library. + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +/* Read nbytes from fd and store into ptr. */ +int +readn (int fd, char *ptr, int nbytes) +{ + int nleft; + int nread; + + nleft = nbytes; + + while (nleft > 0) + { + nread = read (fd, ptr, nleft); + + if (nread < 0) + return (nread); + else + if (nread == 0) + break; + + nleft -= nread; + ptr += nread; + } + + return nbytes - nleft; +} + +/* Write nbytes from ptr to fd. */ +int +writen(int fd, char *ptr, int nbytes) +{ + int nleft; + int nwritten; + + nleft = nbytes; + + while (nleft > 0) + { + nwritten = write(fd, ptr, nleft); + + if (nwritten <= 0) + return (nwritten); + + nleft -= nwritten; + ptr += nwritten; + } + return nbytes - nleft; +} diff --git a/lib/network.h b/lib/network.h new file mode 100644 index 00000000..a0212950 --- /dev/null +++ b/lib/network.h @@ -0,0 +1,29 @@ +/* + * Network library header. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_NETWORK_H +#define _ZEBRA_NETWORK_H + +int readn (int, char *, int); +int writen (int, char *, int); + +#endif /* _ZEBRA_NETWORK_H */ diff --git a/lib/pid_output.c b/lib/pid_output.c new file mode 100644 index 00000000..4146244a --- /dev/null +++ b/lib/pid_output.c @@ -0,0 +1,77 @@ +/* + * Process id output. + * Copyright (C) 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +pid_t +pid_output (char *path) +{ + FILE *fp; + pid_t pid; + + pid = getpid(); + + fp = fopen (path, "w"); + if (fp != NULL) + { + fprintf (fp, "%d\n", (int) pid); + fclose (fp); + return -1; + } + return pid; +} + +pid_t +pid_output_lock (char *path) +{ + int tmp; + int fd; + pid_t pid; + char buf[16], *p; + + pid = getpid (); + + fd = open (path, O_RDWR | O_CREAT | O_EXCL, 0644); + if (fd < 0) + { + fd = open (path, O_RDONLY); + if (fd < 0) + fprintf (stderr, "Can't creat pid lock file, exit\n"); + else + { + read (fd, buf, sizeof (buf)); + if ((p = index (buf, '\n')) != NULL) + *p = 0; + fprintf (stderr, "Another process(%s) running, exit\n", buf); + } + exit (-1); + } + else + { + sprintf (buf, "%d\n", (int) pid); + tmp = write (fd, buf, strlen (buf)); + close (fd); + } + + return pid; +} + diff --git a/lib/plist.c b/lib/plist.c new file mode 100644 index 00000000..c2aeea5b --- /dev/null +++ b/lib/plist.c @@ -0,0 +1,2881 @@ +/* Prefix list functions. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "command.h" +#include "memory.h" +#include "plist.h" +#include "sockunion.h" +#include "buffer.h" + +/* Each prefix-list's entry. */ +struct prefix_list_entry +{ + int seq; + + int le; + int ge; + + enum prefix_list_type type; + + int any; + struct prefix prefix; + + unsigned long refcnt; + unsigned long hitcnt; + + struct prefix_list_entry *next; + struct prefix_list_entry *prev; +}; + +/* List of struct prefix_list. */ +struct prefix_list_list +{ + struct prefix_list *head; + struct prefix_list *tail; +}; + +/* Master structure of prefix_list. */ +struct prefix_master +{ + /* List of prefix_list which name is number. */ + struct prefix_list_list num; + + /* List of prefix_list which name is string. */ + struct prefix_list_list str; + + /* Whether sequential number is used. */ + int seqnum; + + /* The latest update. */ + struct prefix_list *recent; + + /* Hook function which is executed when new prefix_list is added. */ + void (*add_hook) (); + + /* Hook function which is executed when prefix_list is deleted. */ + void (*delete_hook) (); +}; + +/* Static structure of IPv4 prefix_list's master. */ +static struct prefix_master prefix_master_ipv4 = +{ + {NULL, NULL}, + {NULL, NULL}, + 1, + NULL, + NULL, +}; + +#ifdef HAVE_IPV6 +/* Static structure of IPv6 prefix-list's master. */ +static struct prefix_master prefix_master_ipv6 = +{ + {NULL, NULL}, + {NULL, NULL}, + 1, + NULL, + NULL, +}; +#endif /* HAVE_IPV6*/ + +/* Static structure of BGP ORF prefix_list's master. */ +static struct prefix_master prefix_master_orf = +{ + {NULL, NULL}, + {NULL, NULL}, + 1, + NULL, + NULL, +}; + +struct prefix_master * +prefix_master_get (afi_t afi) +{ + if (afi == AFI_IP) + return &prefix_master_ipv4; +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6) + return &prefix_master_ipv6; +#endif /* HAVE_IPV6 */ + else if (afi == AFI_ORF_PREFIX) + return &prefix_master_orf; + return NULL; +} + +/* Lookup prefix_list from list of prefix_list by name. */ +struct prefix_list * +prefix_list_lookup (afi_t afi, char *name) +{ + struct prefix_list *plist; + struct prefix_master *master; + + if (name == NULL) + return NULL; + + master = prefix_master_get (afi); + if (master == NULL) + return NULL; + + for (plist = master->num.head; plist; plist = plist->next) + if (strcmp (plist->name, name) == 0) + return plist; + + for (plist = master->str.head; plist; plist = plist->next) + if (strcmp (plist->name, name) == 0) + return plist; + + return NULL; +} + +struct prefix_list * +prefix_list_new () +{ + struct prefix_list *new; + + new = XCALLOC (MTYPE_PREFIX_LIST, sizeof (struct prefix_list)); + return new; +} + +void +prefix_list_free (struct prefix_list *plist) +{ + XFREE (MTYPE_PREFIX_LIST, plist); +} + +struct prefix_list_entry * +prefix_list_entry_new () +{ + struct prefix_list_entry *new; + + new = XCALLOC (MTYPE_PREFIX_LIST_ENTRY, sizeof (struct prefix_list_entry)); + return new; +} + +void +prefix_list_entry_free (struct prefix_list_entry *pentry) +{ + XFREE (MTYPE_PREFIX_LIST_ENTRY, pentry); +} + +/* Insert new prefix list to list of prefix_list. Each prefix_list + is sorted by the name. */ +struct prefix_list * +prefix_list_insert (afi_t afi, char *name) +{ + int i; + long number; + struct prefix_list *plist; + struct prefix_list *point; + struct prefix_list_list *list; + struct prefix_master *master; + + master = prefix_master_get (afi); + if (master == NULL) + return NULL; + + /* Allocate new prefix_list and copy given name. */ + plist = prefix_list_new (); + plist->name = XSTRDUP (MTYPE_PREFIX_LIST_STR, name); + plist->master = master; + + /* If name is made by all digit character. We treat it as + number. */ + for (number = 0, i = 0; i < strlen (name); i++) + { + if (isdigit ((int) name[i])) + number = (number * 10) + (name[i] - '0'); + else + break; + } + + /* In case of name is all digit character */ + if (i == strlen (name)) + { + plist->type = PREFIX_TYPE_NUMBER; + + /* Set prefix_list to number list. */ + list = &master->num; + + for (point = list->head; point; point = point->next) + if (atol (point->name) >= number) + break; + } + else + { + plist->type = PREFIX_TYPE_STRING; + + /* Set prefix_list to string list. */ + list = &master->str; + + /* Set point to insertion point. */ + for (point = list->head; point; point = point->next) + if (strcmp (point->name, name) >= 0) + break; + } + + /* In case of this is the first element of master. */ + if (list->head == NULL) + { + list->head = list->tail = plist; + return plist; + } + + /* In case of insertion is made at the tail of access_list. */ + if (point == NULL) + { + plist->prev = list->tail; + list->tail->next = plist; + list->tail = plist; + return plist; + } + + /* In case of insertion is made at the head of access_list. */ + if (point == list->head) + { + plist->next = list->head; + list->head->prev = plist; + list->head = plist; + return plist; + } + + /* Insertion is made at middle of the access_list. */ + plist->next = point; + plist->prev = point->prev; + + if (point->prev) + point->prev->next = plist; + point->prev = plist; + + return plist; +} + +struct prefix_list * +prefix_list_get (afi_t afi, char *name) +{ + struct prefix_list *plist; + + plist = prefix_list_lookup (afi, name); + + if (plist == NULL) + plist = prefix_list_insert (afi, name); + return plist; +} + +/* Delete prefix-list from prefix_list_master and free it. */ +void +prefix_list_delete (struct prefix_list *plist) +{ + struct prefix_list_list *list; + struct prefix_master *master; + struct prefix_list_entry *pentry; + struct prefix_list_entry *next; + + /* If prefix-list contain prefix_list_entry free all of it. */ + for (pentry = plist->head; pentry; pentry = next) + { + next = pentry->next; + prefix_list_entry_free (pentry); + plist->count--; + } + + master = plist->master; + + if (plist->type == PREFIX_TYPE_NUMBER) + list = &master->num; + else + list = &master->str; + + if (plist->next) + plist->next->prev = plist->prev; + else + list->tail = plist->prev; + + if (plist->prev) + plist->prev->next = plist->next; + else + list->head = plist->next; + + if (plist->desc) + XFREE (MTYPE_TMP, plist->desc); + + /* Make sure master's recent changed prefix-list information is + cleared. */ + master->recent = NULL; + + if (plist->name) + XFREE (MTYPE_PREFIX_LIST_STR, plist->name); + + prefix_list_free (plist); + + if (master->delete_hook) + (*master->delete_hook) (); +} + +struct prefix_list_entry * +prefix_list_entry_make (struct prefix *prefix, enum prefix_list_type type, + int seq, int le, int ge, int any) +{ + struct prefix_list_entry *pentry; + + pentry = prefix_list_entry_new (); + + if (any) + pentry->any = 1; + + prefix_copy (&pentry->prefix, prefix); + pentry->type = type; + pentry->seq = seq; + pentry->le = le; + pentry->ge = ge; + + return pentry; +} + +/* Add hook function. */ +void +prefix_list_add_hook (void (*func) (struct prefix_list *plist)) +{ + prefix_master_ipv4.add_hook = func; +#ifdef HAVE_IPV6 + prefix_master_ipv6.add_hook = func; +#endif /* HAVE_IPV6 */ +} + +/* Delete hook function. */ +void +prefix_list_delete_hook (void (*func) (struct prefix_list *plist)) +{ + prefix_master_ipv4.delete_hook = func; +#ifdef HAVE_IPV6 + prefix_master_ipv6.delete_hook = func; +#endif /* HAVE_IPVt6 */ +} + +/* Calculate new sequential number. */ +int +prefix_new_seq_get (struct prefix_list *plist) +{ + int maxseq; + int newseq; + struct prefix_list_entry *pentry; + + maxseq = newseq = 0; + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + if (maxseq < pentry->seq) + maxseq = pentry->seq; + } + + newseq = ((maxseq / 5) * 5) + 5; + + return newseq; +} + +/* Return prefix list entry which has same seq number. */ +struct prefix_list_entry * +prefix_seq_check (struct prefix_list *plist, int seq) +{ + struct prefix_list_entry *pentry; + + for (pentry = plist->head; pentry; pentry = pentry->next) + if (pentry->seq == seq) + return pentry; + return NULL; +} + +struct prefix_list_entry * +prefix_list_entry_lookup (struct prefix_list *plist, struct prefix *prefix, + enum prefix_list_type type, int seq, int le, int ge) +{ + struct prefix_list_entry *pentry; + + for (pentry = plist->head; pentry; pentry = pentry->next) + if (prefix_same (&pentry->prefix, prefix) && pentry->type == type) + { + if (seq >= 0 && pentry->seq != seq) + continue; + + if (pentry->le != le) + continue; + if (pentry->ge != ge) + continue; + + return pentry; + } + + return NULL; +} + +void +prefix_list_entry_delete (struct prefix_list *plist, + struct prefix_list_entry *pentry, + int update_list) +{ + if (plist == NULL || pentry == NULL) + return; + if (pentry->prev) + pentry->prev->next = pentry->next; + else + plist->head = pentry->next; + if (pentry->next) + pentry->next->prev = pentry->prev; + else + plist->tail = pentry->prev; + + prefix_list_entry_free (pentry); + + plist->count--; + + if (update_list) + { + if (plist->master->delete_hook) + (*plist->master->delete_hook) (plist); + + if (plist->head == NULL && plist->tail == NULL && plist->desc == NULL) + prefix_list_delete (plist); + else + plist->master->recent = plist; + } +} + +void +prefix_list_entry_add (struct prefix_list *plist, + struct prefix_list_entry *pentry) +{ + struct prefix_list_entry *replace; + struct prefix_list_entry *point; + + /* Automatic asignment of seq no. */ + if (pentry->seq == -1) + pentry->seq = prefix_new_seq_get (plist); + + /* Is there any same seq prefix list entry? */ + replace = prefix_seq_check (plist, pentry->seq); + if (replace) + prefix_list_entry_delete (plist, replace, 0); + + /* Check insert point. */ + for (point = plist->head; point; point = point->next) + if (point->seq >= pentry->seq) + break; + + /* In case of this is the first element of the list. */ + pentry->next = point; + + if (point) + { + if (point->prev) + point->prev->next = pentry; + else + plist->head = pentry; + + pentry->prev = point->prev; + point->prev = pentry; + } + else + { + if (plist->tail) + plist->tail->next = pentry; + else + plist->head = pentry; + + pentry->prev = plist->tail; + plist->tail = pentry; + } + + /* Increment count. */ + plist->count++; + + /* Run hook function. */ + if (plist->master->add_hook) + (*plist->master->add_hook) (plist); + + plist->master->recent = plist; +} + +/* Return string of prefix_list_type. */ +static char * +prefix_list_type_str (struct prefix_list_entry *pentry) +{ + switch (pentry->type) + { + case PREFIX_PERMIT: + return "permit"; + break; + case PREFIX_DENY: + return "deny"; + break; + default: + return ""; + break; + } +} + +int +prefix_list_entry_match (struct prefix_list_entry *pentry, struct prefix *p) +{ + int ret; + + ret = prefix_match (&pentry->prefix, p); + if (! ret) + return 0; + + /* In case of le nor ge is specified, exact match is performed. */ + if (! pentry->le && ! pentry->ge) + { + if (pentry->prefix.prefixlen != p->prefixlen) + return 0; + } + else + { + if (pentry->le) + if (p->prefixlen > pentry->le) + return 0; + + if (pentry->ge) + if (p->prefixlen < pentry->ge) + return 0; + } + return 1; +} + +enum prefix_list_type +prefix_list_apply (struct prefix_list *plist, void *object) +{ + struct prefix_list_entry *pentry; + struct prefix *p; + + p = (struct prefix *) object; + + if (plist == NULL) + return PREFIX_DENY; + + if (plist->count == 0) + return PREFIX_PERMIT; + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + pentry->refcnt++; + if (prefix_list_entry_match (pentry, p)) + { + pentry->hitcnt++; + return pentry->type; + } + } + + return PREFIX_DENY; +} + +void +prefix_list_print (struct prefix_list *plist) +{ + struct prefix_list_entry *pentry; + + if (plist == NULL) + return; + + printf ("ip prefix-list %s: %d entries\n", plist->name, plist->count); + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + if (pentry->any) + printf ("any %s\n", prefix_list_type_str (pentry)); + else + { + struct prefix *p; + char buf[BUFSIZ]; + + p = &pentry->prefix; + + printf (" seq %d %s %s/%d", + pentry->seq, + prefix_list_type_str (pentry), + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen); + if (pentry->ge) + printf (" ge %d", pentry->ge); + if (pentry->le) + printf (" le %d", pentry->le); + printf ("\n"); + } + } +} + +/* Retrun 1 when plist already include pentry policy. */ +struct prefix_list_entry * +prefix_entry_dup_check (struct prefix_list *plist, + struct prefix_list_entry *new) +{ + struct prefix_list_entry *pentry; + int seq = 0; + + if (new->seq == -1) + seq = prefix_new_seq_get (plist); + else + seq = new->seq; + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + if (prefix_same (&pentry->prefix, &new->prefix) + && pentry->type == new->type + && pentry->le == new->le + && pentry->ge == new->ge + && pentry->seq != seq) + return pentry; + } + return NULL; +} + +int +vty_invalid_prefix_range (struct vty *vty, char *prefix) +{ + vty_out (vty, "%% Invalid prefix range for %s, make sure: len < ge-value <= le-value%s", + prefix, VTY_NEWLINE); + return CMD_WARNING; +} + +int +vty_prefix_list_install (struct vty *vty, afi_t afi, + char *name, char *seq, char *typestr, + char *prefix, char *ge, char *le) +{ + int ret; + enum prefix_list_type type; + struct prefix_list *plist; + struct prefix_list_entry *pentry; + struct prefix_list_entry *dup; + struct prefix p; + int any = 0; + int seqnum = -1; + int lenum = 0; + int genum = 0; + + /* Sequential number. */ + if (seq) + seqnum = atoi (seq); + + /* ge and le number */ + if (ge) + genum = atoi (ge); + if (le) + lenum = atoi (le); + + /* Check filter type. */ + if (strncmp ("permit", typestr, 1) == 0) + type = PREFIX_PERMIT; + else if (strncmp ("deny", typestr, 1) == 0) + type = PREFIX_DENY; + else + { + vty_out (vty, "%% prefix type must be permit or deny%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* "any" is special token for matching any IPv4 addresses. */ + if (afi == AFI_IP) + { + if (strncmp ("any", prefix, strlen (prefix)) == 0) + { + ret = str2prefix_ipv4 ("0.0.0.0/0", (struct prefix_ipv4 *) &p); + genum = 0; + lenum = IPV4_MAX_BITLEN; + any = 1; + } + else + ret = str2prefix_ipv4 (prefix, (struct prefix_ipv4 *) &p); + + if (ret <= 0) + { + vty_out (vty, "%% Malformed IPv4 prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + } +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6) + { + if (strncmp ("any", prefix, strlen (prefix)) == 0) + { + ret = str2prefix_ipv6 ("::/0", (struct prefix_ipv6 *) &p); + genum = 0; + lenum = IPV6_MAX_BITLEN; + any = 1; + } + else + ret = str2prefix_ipv6 (prefix, (struct prefix_ipv6 *) &p); + + if (ret <= 0) + { + vty_out (vty, "%% Malformed IPv6 prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + } +#endif /* HAVE_IPV6 */ + + /* ge and le check. */ + if (genum && genum <= p.prefixlen) + return vty_invalid_prefix_range (vty, prefix); + + if (lenum && lenum <= p.prefixlen) + return vty_invalid_prefix_range (vty, prefix); + + if (lenum && genum > lenum) + return vty_invalid_prefix_range (vty, prefix); + + if (genum && lenum == (afi == AFI_IP ? 32 : 128)) + lenum = 0; + + /* Get prefix_list with name. */ + plist = prefix_list_get (afi, name); + + /* Make prefix entry. */ + pentry = prefix_list_entry_make (&p, type, seqnum, lenum, genum, any); + + /* Check same policy. */ + dup = prefix_entry_dup_check (plist, pentry); + + if (dup) + { + prefix_list_entry_free (pentry); + vty_out (vty, "%% Insertion failed - prefix-list entry exists:%s", + VTY_NEWLINE); + vty_out (vty, " seq %d %s %s", dup->seq, typestr, prefix); + if (! any && genum) + vty_out (vty, " ge %d", genum); + if (! any && lenum) + vty_out (vty, " le %d", lenum); + vty_out (vty, "%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Install new filter to the access_list. */ + prefix_list_entry_add (plist, pentry); + + return CMD_SUCCESS; +} + +int +vty_prefix_list_uninstall (struct vty *vty, afi_t afi, + char *name, char *seq, char *typestr, + char *prefix, char *ge, char *le) +{ + int ret; + enum prefix_list_type type; + struct prefix_list *plist; + struct prefix_list_entry *pentry; + struct prefix p; + int seqnum = -1; + int lenum = 0; + int genum = 0; + + /* Check prefix list name. */ + plist = prefix_list_lookup (afi, name); + if (! plist) + { + vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Only prefix-list name specified, delete the entire prefix-list. */ + if (seq == NULL && typestr == NULL && prefix == NULL && + ge == NULL && le == NULL) + { + prefix_list_delete (plist); + return CMD_SUCCESS; + } + + /* Check sequence number. */ + if (seq) + seqnum = atoi (seq); + + /* ge and le number */ + if (ge) + genum = atoi (ge); + if (le) + lenum = atoi (le); + + /* Check of filter type. */ + if (strncmp ("permit", typestr, 1) == 0) + type = PREFIX_PERMIT; + else if (strncmp ("deny", typestr, 1) == 0) + type = PREFIX_DENY; + else + { + vty_out (vty, "%% prefix type must be permit or deny%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* "any" is special token for matching any IPv4 addresses. */ + if (afi == AFI_IP) + { + if (strncmp ("any", prefix, strlen (prefix)) == 0) + { + ret = str2prefix_ipv4 ("0.0.0.0/0", (struct prefix_ipv4 *) &p); + genum = 0; + lenum = IPV4_MAX_BITLEN; + } + else + ret = str2prefix_ipv4 (prefix, (struct prefix_ipv4 *) &p); + + if (ret <= 0) + { + vty_out (vty, "%% Malformed IPv4 prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + } +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6) + { + if (strncmp ("any", prefix, strlen (prefix)) == 0) + { + ret = str2prefix_ipv6 ("::/0", (struct prefix_ipv6 *) &p); + genum = 0; + lenum = IPV6_MAX_BITLEN; + } + else + ret = str2prefix_ipv6 (prefix, (struct prefix_ipv6 *) &p); + + if (ret <= 0) + { + vty_out (vty, "%% Malformed IPv6 prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + } +#endif /* HAVE_IPV6 */ + + /* Lookup prefix entry. */ + pentry = prefix_list_entry_lookup(plist, &p, type, seqnum, lenum, genum); + + if (pentry == NULL) + { + vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Install new filter to the access_list. */ + prefix_list_entry_delete (plist, pentry, 1); + + return CMD_SUCCESS; +} + +int +vty_prefix_list_desc_unset (struct vty *vty, afi_t afi, char *name) +{ + struct prefix_list *plist; + + plist = prefix_list_lookup (afi, name); + if (! plist) + { + vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (plist->desc) + { + XFREE (MTYPE_TMP, plist->desc); + plist->desc = NULL; + } + + if (plist->head == NULL && plist->tail == NULL && plist->desc == NULL) + prefix_list_delete (plist); + + return CMD_SUCCESS; +} + +enum display_type +{ + normal_display, + summary_display, + detail_display, + sequential_display, + longer_display, + first_match_display +}; + +void +vty_show_prefix_entry (struct vty *vty, afi_t afi, struct prefix_list *plist, + struct prefix_master *master, enum display_type dtype, + int seqnum) +{ + struct prefix_list_entry *pentry; + + if (dtype == normal_display) + { + vty_out (vty, "ip%s prefix-list %s: %d entries%s", + afi == AFI_IP ? "" : "v6", + plist->name, plist->count, VTY_NEWLINE); + if (plist->desc) + vty_out (vty, " Description: %s%s", plist->desc, VTY_NEWLINE); + } + else if (dtype == summary_display || dtype == detail_display) + { + vty_out (vty, "ip%s prefix-list %s:%s", + afi == AFI_IP ? "" : "v6", plist->name, VTY_NEWLINE); + + if (plist->desc) + vty_out (vty, " Description: %s%s", plist->desc, VTY_NEWLINE); + + vty_out (vty, " count: %d, range entries: %d, sequences: %d - %d%s", + plist->count, plist->rangecount, + plist->head ? plist->head->seq : 0, + plist->tail ? plist->tail->seq : 0, + VTY_NEWLINE); + } + + if (dtype != summary_display) + { + for (pentry = plist->head; pentry; pentry = pentry->next) + { + if (dtype == sequential_display && pentry->seq != seqnum) + continue; + + vty_out (vty, " "); + + if (master->seqnum) + vty_out (vty, "seq %d ", pentry->seq); + + vty_out (vty, "%s ", prefix_list_type_str (pentry)); + + if (pentry->any) + vty_out (vty, "any"); + else + { + struct prefix *p = &pentry->prefix; + char buf[BUFSIZ]; + + vty_out (vty, "%s/%d", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen); + + if (pentry->ge) + vty_out (vty, " ge %d", pentry->ge); + if (pentry->le) + vty_out (vty, " le %d", pentry->le); + } + + if (dtype == detail_display || dtype == sequential_display) + vty_out (vty, " (hit count: %ld, refcount: %ld)", + pentry->hitcnt, pentry->refcnt); + + vty_out (vty, "%s", VTY_NEWLINE); + } + } +} + +int +vty_show_prefix_list (struct vty *vty, afi_t afi, char *name, + char *seq, enum display_type dtype) +{ + struct prefix_list *plist; + struct prefix_master *master; + int seqnum = 0; + + master = prefix_master_get (afi); + if (master == NULL) + return CMD_WARNING; + + if (seq) + seqnum = atoi (seq); + + if (name) + { + plist = prefix_list_lookup (afi, name); + if (! plist) + { + vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + vty_show_prefix_entry (vty, afi, plist, master, dtype, seqnum); + } + else + { + if (dtype == detail_display || dtype == summary_display) + { + if (master->recent) + vty_out (vty, "Prefix-list with the last deletion/insertion: %s%s", + master->recent->name, VTY_NEWLINE); + } + + for (plist = master->num.head; plist; plist = plist->next) + vty_show_prefix_entry (vty, afi, plist, master, dtype, seqnum); + + for (plist = master->str.head; plist; plist = plist->next) + vty_show_prefix_entry (vty, afi, plist, master, dtype, seqnum); + } + + return CMD_SUCCESS; +} + +int +vty_show_prefix_list_prefix (struct vty *vty, afi_t afi, char *name, + char *prefix, enum display_type type) +{ + struct prefix_list *plist; + struct prefix_list_entry *pentry; + struct prefix p; + int ret; + int match; + + plist = prefix_list_lookup (afi, name); + if (! plist) + { + vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2prefix (prefix, &p); + if (ret <= 0) + { + vty_out (vty, "%% prefix is malformed%s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + match = 0; + + if (type == normal_display || type == first_match_display) + if (prefix_same (&p, &pentry->prefix)) + match = 1; + + if (type == longer_display) + if (prefix_match (&p, &pentry->prefix)) + match = 1; + + if (match) + { + vty_out (vty, " seq %d %s ", + pentry->seq, + prefix_list_type_str (pentry)); + + if (pentry->any) + vty_out (vty, "any"); + else + { + struct prefix *p = &pentry->prefix; + char buf[BUFSIZ]; + + vty_out (vty, "%s/%d", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen); + + if (pentry->ge) + vty_out (vty, " ge %d", pentry->ge); + if (pentry->le) + vty_out (vty, " le %d", pentry->le); + } + + if (type == normal_display || type == first_match_display) + vty_out (vty, " (hit count: %ld, refcount: %ld)", + pentry->hitcnt, pentry->refcnt); + + vty_out (vty, "%s", VTY_NEWLINE); + + if (type == first_match_display) + return CMD_SUCCESS; + } + } + return CMD_SUCCESS; +} + +int +vty_clear_prefix_list (struct vty *vty, afi_t afi, char *name, char *prefix) +{ + struct prefix_master *master; + struct prefix_list *plist; + struct prefix_list_entry *pentry; + int ret; + struct prefix p; + + master = prefix_master_get (afi); + if (master == NULL) + return CMD_WARNING; + + if (name == NULL && prefix == NULL) + { + for (plist = master->num.head; plist; plist = plist->next) + for (pentry = plist->head; pentry; pentry = pentry->next) + pentry->hitcnt = 0; + + for (plist = master->str.head; plist; plist = plist->next) + for (pentry = plist->head; pentry; pentry = pentry->next) + pentry->hitcnt = 0; + } + else + { + plist = prefix_list_lookup (afi, name); + if (! plist) + { + vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (prefix) + { + ret = str2prefix (prefix, &p); + if (ret <= 0) + { + vty_out (vty, "%% prefix is malformed%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + if (prefix) + { + if (prefix_match (&pentry->prefix, &p)) + pentry->hitcnt = 0; + } + else + pentry->hitcnt = 0; + } + } + return CMD_SUCCESS; +} + +DEFUN (ip_prefix_list, + ip_prefix_list_cmd, + "ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, + argv[1], argv[2], NULL, NULL); +} + +DEFUN (ip_prefix_list_ge, + ip_prefix_list_ge_cmd, + "ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32>", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1], + argv[2], argv[3], NULL); +} + +DEFUN (ip_prefix_list_ge_le, + ip_prefix_list_ge_le_cmd, + "ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1], + argv[2], argv[3], argv[4]); +} + +DEFUN (ip_prefix_list_le, + ip_prefix_list_le_cmd, + "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1], + argv[2], NULL, argv[3]); +} + +DEFUN (ip_prefix_list_le_ge, + ip_prefix_list_le_ge_cmd, + "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1], + argv[2], argv[4], argv[3]); +} + +DEFUN (ip_prefix_list_seq, + ip_prefix_list_seq_cmd, + "ip prefix-list WORD seq <1-4294967295> (deny|permit) (A.B.C.D/M|any)", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], NULL, NULL); +} + +DEFUN (ip_prefix_list_seq_ge, + ip_prefix_list_seq_ge_cmd, + "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32>", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], argv[4], NULL); +} + +DEFUN (ip_prefix_list_seq_ge_le, + ip_prefix_list_seq_ge_le_cmd, + "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5]); +} + +DEFUN (ip_prefix_list_seq_le, + ip_prefix_list_seq_le_cmd, + "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32>", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], NULL, argv[4]); +} + +DEFUN (ip_prefix_list_seq_le_ge, + ip_prefix_list_seq_le_ge_cmd, + "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], argv[5], argv[4]); +} + +DEFUN (no_ip_prefix_list, + no_ip_prefix_list_cmd, + "no ip prefix-list WORD", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, NULL, + NULL, NULL, NULL); +} + +DEFUN (no_ip_prefix_list_prefix, + no_ip_prefix_list_prefix_cmd, + "no ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1], + argv[2], NULL, NULL); +} + +DEFUN (no_ip_prefix_list_ge, + no_ip_prefix_list_ge_cmd, + "no ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32>", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1], + argv[2], argv[3], NULL); +} + +DEFUN (no_ip_prefix_list_ge_le, + no_ip_prefix_list_ge_le_cmd, + "no ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1], + argv[2], argv[3], argv[4]); +} + +DEFUN (no_ip_prefix_list_le, + no_ip_prefix_list_le_cmd, + "no ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1], + argv[2], NULL, argv[3]); +} + +DEFUN (no_ip_prefix_list_le_ge, + no_ip_prefix_list_le_ge_cmd, + "no ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1], + argv[2], argv[4], argv[3]); +} + +DEFUN (no_ip_prefix_list_seq, + no_ip_prefix_list_seq_cmd, + "no ip prefix-list WORD seq <1-4294967295> (deny|permit) (A.B.C.D/M|any)", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], NULL, NULL); +} + +DEFUN (no_ip_prefix_list_seq_ge, + no_ip_prefix_list_seq_ge_cmd, + "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32>", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], argv[4], NULL); +} + +DEFUN (no_ip_prefix_list_seq_ge_le, + no_ip_prefix_list_seq_ge_le_cmd, + "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5]); +} + +DEFUN (no_ip_prefix_list_seq_le, + no_ip_prefix_list_seq_le_cmd, + "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32>", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], NULL, argv[4]); +} + +DEFUN (no_ip_prefix_list_seq_le_ge, + no_ip_prefix_list_seq_le_ge_cmd, + "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], argv[5], argv[4]); +} + +DEFUN (ip_prefix_list_sequence_number, + ip_prefix_list_sequence_number_cmd, + "ip prefix-list sequence-number", + IP_STR + PREFIX_LIST_STR + "Include/exclude sequence numbers in NVGEN\n") +{ + prefix_master_ipv4.seqnum = 1; + return CMD_SUCCESS; +} + +DEFUN (no_ip_prefix_list_sequence_number, + no_ip_prefix_list_sequence_number_cmd, + "no ip prefix-list sequence-number", + NO_STR + IP_STR + PREFIX_LIST_STR + "Include/exclude sequence numbers in NVGEN\n") +{ + prefix_master_ipv4.seqnum = 0; + return CMD_SUCCESS; +} + +DEFUN (ip_prefix_list_description, + ip_prefix_list_description_cmd, + "ip prefix-list WORD description .LINE", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Prefix-list specific description\n" + "Up to 80 characters describing this prefix-list\n") +{ + struct prefix_list *plist; + struct buffer *b; + int i; + + plist = prefix_list_get (AFI_IP, argv[0]); + + if (plist->desc) + { + XFREE (MTYPE_TMP, plist->desc); + plist->desc = NULL; + } + + /* Below is description get codes. */ + b = buffer_new (1024); + for (i = 1; i < argc; i++) + { + buffer_putstr (b, (u_char *)argv[i]); + buffer_putc (b, ' '); + } + buffer_putc (b, '\0'); + + plist->desc = buffer_getstr (b); + + buffer_free (b); + + return CMD_SUCCESS; +} + +DEFUN (no_ip_prefix_list_description, + no_ip_prefix_list_description_cmd, + "no ip prefix-list WORD description", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Prefix-list specific description\n") +{ + return vty_prefix_list_desc_unset (vty, AFI_IP, argv[0]); +} + +ALIAS (no_ip_prefix_list_description, + no_ip_prefix_list_description_arg_cmd, + "no ip prefix-list WORD description .LINE", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Prefix-list specific description\n" + "Up to 80 characters describing this prefix-list\n") + +DEFUN (show_ip_prefix_list, + show_ip_prefix_list_cmd, + "show ip prefix-list", + SHOW_STR + IP_STR + PREFIX_LIST_STR) +{ + return vty_show_prefix_list (vty, AFI_IP, NULL, NULL, normal_display); +} + +DEFUN (show_ip_prefix_list_name, + show_ip_prefix_list_name_cmd, + "show ip prefix-list WORD", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n") +{ + return vty_show_prefix_list (vty, AFI_IP, argv[0], NULL, normal_display); +} + +DEFUN (show_ip_prefix_list_name_seq, + show_ip_prefix_list_name_seq_cmd, + "show ip prefix-list WORD seq <1-4294967295>", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n") +{ + return vty_show_prefix_list (vty, AFI_IP, argv[0], argv[1], sequential_display); +} + +DEFUN (show_ip_prefix_list_prefix, + show_ip_prefix_list_prefix_cmd, + "show ip prefix-list WORD A.B.C.D/M", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return vty_show_prefix_list_prefix (vty, AFI_IP, argv[0], argv[1], normal_display); +} + +DEFUN (show_ip_prefix_list_prefix_longer, + show_ip_prefix_list_prefix_longer_cmd, + "show ip prefix-list WORD A.B.C.D/M longer", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Lookup longer prefix\n") +{ + return vty_show_prefix_list_prefix (vty, AFI_IP, argv[0], argv[1], longer_display); +} + +DEFUN (show_ip_prefix_list_prefix_first_match, + show_ip_prefix_list_prefix_first_match_cmd, + "show ip prefix-list WORD A.B.C.D/M first-match", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "First matched prefix\n") +{ + return vty_show_prefix_list_prefix (vty, AFI_IP, argv[0], argv[1], first_match_display); +} + +DEFUN (show_ip_prefix_list_summary, + show_ip_prefix_list_summary_cmd, + "show ip prefix-list summary", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Summary of prefix lists\n") +{ + return vty_show_prefix_list (vty, AFI_IP, NULL, NULL, summary_display); +} + +DEFUN (show_ip_prefix_list_summary_name, + show_ip_prefix_list_summary_name_cmd, + "show ip prefix-list summary WORD", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Summary of prefix lists\n" + "Name of a prefix list\n") +{ + return vty_show_prefix_list (vty, AFI_IP, argv[0], NULL, summary_display); +} + + +DEFUN (show_ip_prefix_list_detail, + show_ip_prefix_list_detail_cmd, + "show ip prefix-list detail", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Detail of prefix lists\n") +{ + return vty_show_prefix_list (vty, AFI_IP, NULL, NULL, detail_display); +} + +DEFUN (show_ip_prefix_list_detail_name, + show_ip_prefix_list_detail_name_cmd, + "show ip prefix-list detail WORD", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Detail of prefix lists\n" + "Name of a prefix list\n") +{ + return vty_show_prefix_list (vty, AFI_IP, argv[0], NULL, detail_display); +} + +DEFUN (clear_ip_prefix_list, + clear_ip_prefix_list_cmd, + "clear ip prefix-list", + CLEAR_STR + IP_STR + PREFIX_LIST_STR) +{ + return vty_clear_prefix_list (vty, AFI_IP, NULL, NULL); +} + +DEFUN (clear_ip_prefix_list_name, + clear_ip_prefix_list_name_cmd, + "clear ip prefix-list WORD", + CLEAR_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n") +{ + return vty_clear_prefix_list (vty, AFI_IP, argv[0], NULL); +} + +DEFUN (clear_ip_prefix_list_name_prefix, + clear_ip_prefix_list_name_prefix_cmd, + "clear ip prefix-list WORD A.B.C.D/M", + CLEAR_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return vty_clear_prefix_list (vty, AFI_IP, argv[0], argv[1]); +} + +#ifdef HAVE_IPV6 +DEFUN (ipv6_prefix_list, + ipv6_prefix_list_cmd, + "ipv6 prefix-list WORD (deny|permit) (X:X::X:X/M|any)", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Any prefix match. Same as \"::0/0 le 128\"\n") +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, + argv[1], argv[2], NULL, NULL); +} + +DEFUN (ipv6_prefix_list_ge, + ipv6_prefix_list_ge_cmd, + "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128>", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1], + argv[2], argv[3], NULL); +} + +DEFUN (ipv6_prefix_list_ge_le, + ipv6_prefix_list_ge_le_cmd, + "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1], + argv[2], argv[3], argv[4]); +} + +DEFUN (ipv6_prefix_list_le, + ipv6_prefix_list_le_cmd, + "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128>", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1], + argv[2], NULL, argv[3]); +} + +DEFUN (ipv6_prefix_list_le_ge, + ipv6_prefix_list_le_ge_cmd, + "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1], + argv[2], argv[4], argv[3]); +} + +DEFUN (ipv6_prefix_list_seq, + ipv6_prefix_list_seq_cmd, + "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) (X:X::X:X/M|any)", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Any prefix match. Same as \"::0/0 le 128\"\n") +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], NULL, NULL); +} + +DEFUN (ipv6_prefix_list_seq_ge, + ipv6_prefix_list_seq_ge_cmd, + "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128>", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], argv[4], NULL); +} + +DEFUN (ipv6_prefix_list_seq_ge_le, + ipv6_prefix_list_seq_ge_le_cmd, + "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5]); +} + +DEFUN (ipv6_prefix_list_seq_le, + ipv6_prefix_list_seq_le_cmd, + "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128>", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], NULL, argv[4]); +} + +DEFUN (ipv6_prefix_list_seq_le_ge, + ipv6_prefix_list_seq_le_ge_cmd, + "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], argv[5], argv[4]); +} + +DEFUN (no_ipv6_prefix_list, + no_ipv6_prefix_list_cmd, + "no ipv6 prefix-list WORD", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, NULL, + NULL, NULL, NULL); +} + +DEFUN (no_ipv6_prefix_list_prefix, + no_ipv6_prefix_list_prefix_cmd, + "no ipv6 prefix-list WORD (deny|permit) (X:X::X:X/M|any)", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Any prefix match. Same as \"::0/0 le 128\"\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1], + argv[2], NULL, NULL); +} + +DEFUN (no_ipv6_prefix_list_ge, + no_ipv6_prefix_list_ge_cmd, + "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128>", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1], + argv[2], argv[3], NULL); +} + +DEFUN (no_ipv6_prefix_list_ge_le, + no_ipv6_prefix_list_ge_le_cmd, + "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1], + argv[2], argv[3], argv[4]); +} + +DEFUN (no_ipv6_prefix_list_le, + no_ipv6_prefix_list_le_cmd, + "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128>", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1], + argv[2], NULL, argv[3]); +} + +DEFUN (no_ipv6_prefix_list_le_ge, + no_ipv6_prefix_list_le_ge_cmd, + "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1], + argv[2], argv[4], argv[3]); +} + +DEFUN (no_ipv6_prefix_list_seq, + no_ipv6_prefix_list_seq_cmd, + "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) (X:X::X:X/M|any)", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Any prefix match. Same as \"::0/0 le 128\"\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], NULL, NULL); +} + +DEFUN (no_ipv6_prefix_list_seq_ge, + no_ipv6_prefix_list_seq_ge_cmd, + "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128>", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], argv[4], NULL); +} + +DEFUN (no_ipv6_prefix_list_seq_ge_le, + no_ipv6_prefix_list_seq_ge_le_cmd, + "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5]); +} + +DEFUN (no_ipv6_prefix_list_seq_le, + no_ipv6_prefix_list_seq_le_cmd, + "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128>", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], NULL, argv[4]); +} + +DEFUN (no_ipv6_prefix_list_seq_le_ge, + no_ipv6_prefix_list_seq_le_ge_cmd, + "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], argv[5], argv[4]); +} + +DEFUN (ipv6_prefix_list_sequence_number, + ipv6_prefix_list_sequence_number_cmd, + "ipv6 prefix-list sequence-number", + IPV6_STR + PREFIX_LIST_STR + "Include/exclude sequence numbers in NVGEN\n") +{ + prefix_master_ipv6.seqnum = 1; + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_prefix_list_sequence_number, + no_ipv6_prefix_list_sequence_number_cmd, + "no ipv6 prefix-list sequence-number", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Include/exclude sequence numbers in NVGEN\n") +{ + prefix_master_ipv6.seqnum = 0; + return CMD_SUCCESS; +} + +DEFUN (ipv6_prefix_list_description, + ipv6_prefix_list_description_cmd, + "ipv6 prefix-list WORD description .LINE", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Prefix-list specific description\n" + "Up to 80 characters describing this prefix-list\n") +{ + struct prefix_list *plist; + struct buffer *b; + int i; + + plist = prefix_list_get (AFI_IP6, argv[0]); + + if (plist->desc) + { + XFREE (MTYPE_TMP, plist->desc); + plist->desc = NULL; + } + + /* Below is description get codes. */ + b = buffer_new (1024); + for (i = 1; i < argc; i++) + { + buffer_putstr (b, (u_char *)argv[i]); + buffer_putc (b, ' '); + } + buffer_putc (b, '\0'); + + plist->desc = buffer_getstr (b); + + buffer_free (b); + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_prefix_list_description, + no_ipv6_prefix_list_description_cmd, + "no ipv6 prefix-list WORD description", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Prefix-list specific description\n") +{ + return vty_prefix_list_desc_unset (vty, AFI_IP6, argv[0]); +} + +ALIAS (no_ipv6_prefix_list_description, + no_ipv6_prefix_list_description_arg_cmd, + "no ipv6 prefix-list WORD description .LINE", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Prefix-list specific description\n" + "Up to 80 characters describing this prefix-list\n") + +DEFUN (show_ipv6_prefix_list, + show_ipv6_prefix_list_cmd, + "show ipv6 prefix-list", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR) +{ + return vty_show_prefix_list (vty, AFI_IP6, NULL, NULL, normal_display); +} + +DEFUN (show_ipv6_prefix_list_name, + show_ipv6_prefix_list_name_cmd, + "show ipv6 prefix-list WORD", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n") +{ + return vty_show_prefix_list (vty, AFI_IP6, argv[0], NULL, normal_display); +} + +DEFUN (show_ipv6_prefix_list_name_seq, + show_ipv6_prefix_list_name_seq_cmd, + "show ipv6 prefix-list WORD seq <1-4294967295>", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n") +{ + return vty_show_prefix_list (vty, AFI_IP6, argv[0], argv[1], sequential_display); +} + +DEFUN (show_ipv6_prefix_list_prefix, + show_ipv6_prefix_list_prefix_cmd, + "show ipv6 prefix-list WORD X:X::X:X/M", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "IPv6 prefix /, e.g., 3ffe::/16\n") +{ + return vty_show_prefix_list_prefix (vty, AFI_IP6, argv[0], argv[1], normal_display); +} + +DEFUN (show_ipv6_prefix_list_prefix_longer, + show_ipv6_prefix_list_prefix_longer_cmd, + "show ipv6 prefix-list WORD X:X::X:X/M longer", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Lookup longer prefix\n") +{ + return vty_show_prefix_list_prefix (vty, AFI_IP6, argv[0], argv[1], longer_display); +} + +DEFUN (show_ipv6_prefix_list_prefix_first_match, + show_ipv6_prefix_list_prefix_first_match_cmd, + "show ipv6 prefix-list WORD X:X::X:X/M first-match", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "First matched prefix\n") +{ + return vty_show_prefix_list_prefix (vty, AFI_IP6, argv[0], argv[1], first_match_display); +} + +DEFUN (show_ipv6_prefix_list_summary, + show_ipv6_prefix_list_summary_cmd, + "show ipv6 prefix-list summary", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Summary of prefix lists\n") +{ + return vty_show_prefix_list (vty, AFI_IP6, NULL, NULL, summary_display); +} + +DEFUN (show_ipv6_prefix_list_summary_name, + show_ipv6_prefix_list_summary_name_cmd, + "show ipv6 prefix-list summary WORD", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Summary of prefix lists\n" + "Name of a prefix list\n") +{ + return vty_show_prefix_list (vty, AFI_IP6, argv[0], NULL, summary_display); +} + +DEFUN (show_ipv6_prefix_list_detail, + show_ipv6_prefix_list_detail_cmd, + "show ipv6 prefix-list detail", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Detail of prefix lists\n") +{ + return vty_show_prefix_list (vty, AFI_IP6, NULL, NULL, detail_display); +} + +DEFUN (show_ipv6_prefix_list_detail_name, + show_ipv6_prefix_list_detail_name_cmd, + "show ipv6 prefix-list detail WORD", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Detail of prefix lists\n" + "Name of a prefix list\n") +{ + return vty_show_prefix_list (vty, AFI_IP6, argv[0], NULL, detail_display); +} + +DEFUN (clear_ipv6_prefix_list, + clear_ipv6_prefix_list_cmd, + "clear ipv6 prefix-list", + CLEAR_STR + IPV6_STR + PREFIX_LIST_STR) +{ + return vty_clear_prefix_list (vty, AFI_IP6, NULL, NULL); +} + +DEFUN (clear_ipv6_prefix_list_name, + clear_ipv6_prefix_list_name_cmd, + "clear ipv6 prefix-list WORD", + CLEAR_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n") +{ + return vty_clear_prefix_list (vty, AFI_IP6, argv[0], NULL); +} + +DEFUN (clear_ipv6_prefix_list_name_prefix, + clear_ipv6_prefix_list_name_prefix_cmd, + "clear ipv6 prefix-list WORD X:X::X:X/M", + CLEAR_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "IPv6 prefix /, e.g., 3ffe::/16\n") +{ + return vty_clear_prefix_list (vty, AFI_IP6, argv[0], argv[1]); +} +#endif /* HAVE_IPV6 */ + +/* Configuration write function. */ +int +config_write_prefix_afi (afi_t afi, struct vty *vty) +{ + struct prefix_list *plist; + struct prefix_list_entry *pentry; + struct prefix_master *master; + int write = 0; + + master = prefix_master_get (afi); + if (master == NULL) + return 0; + + if (! master->seqnum) + { + vty_out (vty, "no ip%s prefix-list sequence-number%s", + afi == AFI_IP ? "" : "v6", VTY_NEWLINE); + vty_out (vty, "!%s", VTY_NEWLINE); + } + + for (plist = master->num.head; plist; plist = plist->next) + { + if (plist->desc) + { + vty_out (vty, "ip%s prefix-list %s description %s%s", + afi == AFI_IP ? "" : "v6", + plist->name, plist->desc, VTY_NEWLINE); + write++; + } + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + vty_out (vty, "ip%s prefix-list %s ", + afi == AFI_IP ? "" : "v6", + plist->name); + + if (master->seqnum) + vty_out (vty, "seq %d ", pentry->seq); + + vty_out (vty, "%s ", prefix_list_type_str (pentry)); + + if (pentry->any) + vty_out (vty, "any"); + else + { + struct prefix *p = &pentry->prefix; + char buf[BUFSIZ]; + + vty_out (vty, "%s/%d", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen); + + if (pentry->ge) + vty_out (vty, " ge %d", pentry->ge); + if (pentry->le) + vty_out (vty, " le %d", pentry->le); + } + vty_out (vty, "%s", VTY_NEWLINE); + write++; + } + /* vty_out (vty, "!%s", VTY_NEWLINE); */ + } + + for (plist = master->str.head; plist; plist = plist->next) + { + if (plist->desc) + { + vty_out (vty, "ip%s prefix-list %s description %s%s", + afi == AFI_IP ? "" : "v6", + plist->name, plist->desc, VTY_NEWLINE); + write++; + } + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + vty_out (vty, "ip%s prefix-list %s ", + afi == AFI_IP ? "" : "v6", + plist->name); + + if (master->seqnum) + vty_out (vty, "seq %d ", pentry->seq); + + vty_out (vty, "%s", prefix_list_type_str (pentry)); + + if (pentry->any) + vty_out (vty, " any"); + else + { + struct prefix *p = &pentry->prefix; + char buf[BUFSIZ]; + + vty_out (vty, " %s/%d", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen); + + if (pentry->ge) + vty_out (vty, " ge %d", pentry->ge); + if (pentry->le) + vty_out (vty, " le %d", pentry->le); + } + vty_out (vty, "%s", VTY_NEWLINE); + write++; + } + } + + return write; +} + +int stream_putc (struct stream *, u_char); +int stream_putl (struct stream *, u_int32_t); +int stream_put_prefix (struct stream *, struct prefix *); + +struct stream * +prefix_bgp_orf_entry (struct stream *s, struct prefix_list *plist, + u_char init_flag, u_char permit_flag, u_char deny_flag) +{ + struct prefix_list_entry *pentry; + + if (! plist) + return s; + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + u_char flag = init_flag; + struct prefix *p = &pentry->prefix; + + flag |= (pentry->type == PREFIX_PERMIT ? + permit_flag : deny_flag); + stream_putc (s, flag); + stream_putl (s, (u_int32_t)pentry->seq); + stream_putc (s, (u_char)pentry->ge); + stream_putc (s, (u_char)pentry->le); + stream_put_prefix (s, p); + } + + return s; +} + +int +prefix_bgp_orf_set (char *name, afi_t afi, struct orf_prefix *orfp, + int permit, int set) +{ + struct prefix_list *plist; + struct prefix_list_entry *pentry; + + /* ge and le value check */ + if (orfp->ge && orfp->ge <= orfp->p.prefixlen) + return CMD_WARNING; + if (orfp->le && orfp->le <= orfp->p.prefixlen) + return CMD_WARNING; + if (orfp->le && orfp->ge > orfp->le) + return CMD_WARNING; + + if (orfp->ge && orfp->le == (afi == AFI_IP ? 32 : 128)) + orfp->le = 0; + + plist = prefix_list_get (AFI_ORF_PREFIX, name); + if (! plist) + return CMD_WARNING; + + if (set) + { + pentry = prefix_list_entry_make (&orfp->p, + (permit ? PREFIX_PERMIT : PREFIX_DENY), + orfp->seq, orfp->le, orfp->ge, 0); + + if (prefix_entry_dup_check (plist, pentry)) + { + prefix_list_entry_free (pentry); + return CMD_WARNING; + } + + prefix_list_entry_add (plist, pentry); + } + else + { + pentry = prefix_list_entry_lookup (plist, &orfp->p, + (permit ? PREFIX_PERMIT : PREFIX_DENY), + orfp->seq, orfp->le, orfp->ge); + + if (! pentry) + return CMD_WARNING; + + prefix_list_entry_delete (plist, pentry, 1); + } + + return CMD_SUCCESS; +} + +void +prefix_bgp_orf_remove_all (char *name) +{ + struct prefix_list *plist; + + plist = prefix_list_lookup (AFI_ORF_PREFIX, name); + if (plist) + prefix_list_delete (plist); +} + +/* return prefix count */ +int +prefix_bgp_show_prefix_list (struct vty *vty, afi_t afi, char *name) +{ + struct prefix_list *plist; + struct prefix_list_entry *pentry; + + plist = prefix_list_lookup (AFI_ORF_PREFIX, name); + if (! plist) + return 0; + + if (! vty) + return plist->count; + + vty_out (vty, "ip%s prefix-list %s: %d entries%s", + afi == AFI_IP ? "" : "v6", + plist->name, plist->count, VTY_NEWLINE); + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + struct prefix *p = &pentry->prefix; + char buf[BUFSIZ]; + + vty_out (vty, " seq %d %s %s/%d", pentry->seq, + prefix_list_type_str (pentry), + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen); + + if (pentry->ge) + vty_out (vty, " ge %d", pentry->ge); + if (pentry->le) + vty_out (vty, " le %d", pentry->le); + + vty_out (vty, "%s", VTY_NEWLINE); + } + return plist->count; +} + +void +prefix_list_reset_orf () +{ + struct prefix_list *plist; + struct prefix_list *next; + struct prefix_master *master; + + master = prefix_master_get (AFI_ORF_PREFIX); + if (master == NULL) + return; + + for (plist = master->num.head; plist; plist = next) + { + next = plist->next; + prefix_list_delete (plist); + } + for (plist = master->str.head; plist; plist = next) + { + next = plist->next; + prefix_list_delete (plist); + } + + assert (master->num.head == NULL); + assert (master->num.tail == NULL); + + assert (master->str.head == NULL); + assert (master->str.tail == NULL); + + master->seqnum = 1; + master->recent = NULL; +} + + +/* Prefix-list node. */ +struct cmd_node prefix_node = +{ + PREFIX_NODE, + "", /* Prefix list has no interface. */ + 1 +}; + +int +config_write_prefix_ipv4 (struct vty *vty) +{ + return config_write_prefix_afi (AFI_IP, vty); +} + +void +prefix_list_reset_ipv4 () +{ + struct prefix_list *plist; + struct prefix_list *next; + struct prefix_master *master; + + master = prefix_master_get (AFI_IP); + if (master == NULL) + return; + + for (plist = master->num.head; plist; plist = next) + { + next = plist->next; + prefix_list_delete (plist); + } + for (plist = master->str.head; plist; plist = next) + { + next = plist->next; + prefix_list_delete (plist); + } + + assert (master->num.head == NULL); + assert (master->num.tail == NULL); + + assert (master->str.head == NULL); + assert (master->str.tail == NULL); + + master->seqnum = 1; + master->recent = NULL; +} + +void +prefix_list_init_ipv4 () +{ + install_node (&prefix_node, config_write_prefix_ipv4); + + install_element (CONFIG_NODE, &ip_prefix_list_cmd); + install_element (CONFIG_NODE, &ip_prefix_list_ge_cmd); + install_element (CONFIG_NODE, &ip_prefix_list_ge_le_cmd); + install_element (CONFIG_NODE, &ip_prefix_list_le_cmd); + install_element (CONFIG_NODE, &ip_prefix_list_le_ge_cmd); + install_element (CONFIG_NODE, &ip_prefix_list_seq_cmd); + install_element (CONFIG_NODE, &ip_prefix_list_seq_ge_cmd); + install_element (CONFIG_NODE, &ip_prefix_list_seq_ge_le_cmd); + install_element (CONFIG_NODE, &ip_prefix_list_seq_le_cmd); + install_element (CONFIG_NODE, &ip_prefix_list_seq_le_ge_cmd); + + install_element (CONFIG_NODE, &no_ip_prefix_list_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_prefix_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_ge_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_ge_le_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_le_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_le_ge_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_seq_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_seq_ge_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_seq_ge_le_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_seq_le_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_seq_le_ge_cmd); + + install_element (CONFIG_NODE, &ip_prefix_list_description_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_description_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_description_arg_cmd); + + install_element (CONFIG_NODE, &ip_prefix_list_sequence_number_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_sequence_number_cmd); + + install_element (VIEW_NODE, &show_ip_prefix_list_cmd); + install_element (VIEW_NODE, &show_ip_prefix_list_name_cmd); + install_element (VIEW_NODE, &show_ip_prefix_list_name_seq_cmd); + install_element (VIEW_NODE, &show_ip_prefix_list_prefix_cmd); + install_element (VIEW_NODE, &show_ip_prefix_list_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ip_prefix_list_prefix_first_match_cmd); + install_element (VIEW_NODE, &show_ip_prefix_list_summary_cmd); + install_element (VIEW_NODE, &show_ip_prefix_list_summary_name_cmd); + install_element (VIEW_NODE, &show_ip_prefix_list_detail_cmd); + install_element (VIEW_NODE, &show_ip_prefix_list_detail_name_cmd); + + install_element (ENABLE_NODE, &show_ip_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ip_prefix_list_name_cmd); + install_element (ENABLE_NODE, &show_ip_prefix_list_name_seq_cmd); + install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_first_match_cmd); + install_element (ENABLE_NODE, &show_ip_prefix_list_summary_cmd); + install_element (ENABLE_NODE, &show_ip_prefix_list_summary_name_cmd); + install_element (ENABLE_NODE, &show_ip_prefix_list_detail_cmd); + install_element (ENABLE_NODE, &show_ip_prefix_list_detail_name_cmd); + + install_element (ENABLE_NODE, &clear_ip_prefix_list_cmd); + install_element (ENABLE_NODE, &clear_ip_prefix_list_name_cmd); + install_element (ENABLE_NODE, &clear_ip_prefix_list_name_prefix_cmd); +} + +#ifdef HAVE_IPV6 +/* Prefix-list node. */ +struct cmd_node prefix_ipv6_node = +{ + PREFIX_IPV6_NODE, + "", /* Prefix list has no interface. */ + 1 +}; + +int +config_write_prefix_ipv6 (struct vty *vty) +{ + return config_write_prefix_afi (AFI_IP6, vty); +} + +void +prefix_list_reset_ipv6 () +{ + struct prefix_list *plist; + struct prefix_list *next; + struct prefix_master *master; + + master = prefix_master_get (AFI_IP6); + if (master == NULL) + return; + + for (plist = master->num.head; plist; plist = next) + { + next = plist->next; + prefix_list_delete (plist); + } + for (plist = master->str.head; plist; plist = next) + { + next = plist->next; + prefix_list_delete (plist); + } + + assert (master->num.head == NULL); + assert (master->num.tail == NULL); + + assert (master->str.head == NULL); + assert (master->str.tail == NULL); + + master->seqnum = 1; + master->recent = NULL; +} + +void +prefix_list_init_ipv6 () +{ + install_node (&prefix_ipv6_node, config_write_prefix_ipv6); + + install_element (CONFIG_NODE, &ipv6_prefix_list_cmd); + install_element (CONFIG_NODE, &ipv6_prefix_list_ge_cmd); + install_element (CONFIG_NODE, &ipv6_prefix_list_ge_le_cmd); + install_element (CONFIG_NODE, &ipv6_prefix_list_le_cmd); + install_element (CONFIG_NODE, &ipv6_prefix_list_le_ge_cmd); + install_element (CONFIG_NODE, &ipv6_prefix_list_seq_cmd); + install_element (CONFIG_NODE, &ipv6_prefix_list_seq_ge_cmd); + install_element (CONFIG_NODE, &ipv6_prefix_list_seq_ge_le_cmd); + install_element (CONFIG_NODE, &ipv6_prefix_list_seq_le_cmd); + install_element (CONFIG_NODE, &ipv6_prefix_list_seq_le_ge_cmd); + + install_element (CONFIG_NODE, &no_ipv6_prefix_list_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_prefix_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_ge_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_ge_le_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_le_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_le_ge_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_ge_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_ge_le_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_le_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_le_ge_cmd); + + install_element (CONFIG_NODE, &ipv6_prefix_list_description_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_description_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_description_arg_cmd); + + install_element (CONFIG_NODE, &ipv6_prefix_list_sequence_number_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_sequence_number_cmd); + + install_element (VIEW_NODE, &show_ipv6_prefix_list_cmd); + install_element (VIEW_NODE, &show_ipv6_prefix_list_name_cmd); + install_element (VIEW_NODE, &show_ipv6_prefix_list_name_seq_cmd); + install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_cmd); + install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd); + install_element (VIEW_NODE, &show_ipv6_prefix_list_summary_cmd); + install_element (VIEW_NODE, &show_ipv6_prefix_list_summary_name_cmd); + install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_cmd); + install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_name_cmd); + + install_element (ENABLE_NODE, &show_ipv6_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_cmd); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_seq_cmd); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_cmd); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_cmd); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_name_cmd); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_cmd); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_name_cmd); + + install_element (ENABLE_NODE, &clear_ipv6_prefix_list_cmd); + install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_cmd); + install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_prefix_cmd); +} +#endif /* HAVE_IPV6 */ + +void +prefix_list_init () +{ + prefix_list_init_ipv4 (); +#ifdef HAVE_IPV6 + prefix_list_init_ipv6 (); +#endif /* HAVE_IPV6 */ +} + +void +prefix_list_reset () +{ + prefix_list_reset_ipv4 (); +#ifdef HAVE_IPV6 + prefix_list_reset_ipv6 (); +#endif /* HAVE_IPV6 */ + prefix_list_reset_orf (); +} diff --git a/lib/plist.h b/lib/plist.h new file mode 100644 index 00000000..9a9eb710 --- /dev/null +++ b/lib/plist.h @@ -0,0 +1,78 @@ +/* + * Prefix list functions. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#define AFI_ORF_PREFIX 65535 + +enum prefix_list_type +{ + PREFIX_DENY, + PREFIX_PERMIT, +}; + +enum prefix_name_type +{ + PREFIX_TYPE_STRING, + PREFIX_TYPE_NUMBER +}; + +struct prefix_list +{ + char *name; + char *desc; + + struct prefix_master *master; + + enum prefix_name_type type; + + int count; + int rangecount; + + struct prefix_list_entry *head; + struct prefix_list_entry *tail; + + struct prefix_list *next; + struct prefix_list *prev; +}; + +struct orf_prefix +{ + u_int32_t seq; + u_char ge; + u_char le; + struct prefix p; +}; + +/* Prototypes. */ +void prefix_list_init (void); +void prefix_list_reset (void); +void prefix_list_add_hook (void (*func) (struct prefix_list *)); +void prefix_list_delete_hook (void (*func) (struct prefix_list *)); + +struct prefix_list *prefix_list_lookup (afi_t, char *); +enum prefix_list_type prefix_list_apply (struct prefix_list *, void *); + +struct stream * +prefix_bgp_orf_entry (struct stream *, struct prefix_list *, + u_char, u_char, u_char); +int prefix_bgp_orf_set (char *, afi_t, struct orf_prefix *, int, int); +void prefix_bgp_orf_remove_all (char *); +int prefix_bgp_show_prefix_list (struct vty *, afi_t, char *); diff --git a/lib/prefix.c b/lib/prefix.c new file mode 100644 index 00000000..61e0f195 --- /dev/null +++ b/lib/prefix.c @@ -0,0 +1,696 @@ +/* + * Prefix related functions. + * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "vty.h" +#include "sockunion.h" +#include "memory.h" +#include "log.h" + +/* Maskbit. */ +static u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, + 0xf8, 0xfc, 0xfe, 0xff}; + +/* Number of bits in prefix type. */ +#ifndef PNBBY +#define PNBBY 8 +#endif /* PNBBY */ + +#define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff) + +/* Address Famiy Identifier to Address Family converter. */ +int +afi2family (int afi) +{ + if (afi == AFI_IP) + return AF_INET; +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6) + return AF_INET6; +#endif /* HAVE_IPV6 */ + return 0; +} + +int +family2afi (int family) +{ + if (family == AF_INET) + return AFI_IP; +#ifdef HAVE_IPV6 + else if (family == AF_INET6) + return AFI_IP6; +#endif /* HAVE_IPV6 */ + return 0; +} + +/* If n includes p prefix then return 1 else return 0. */ +int +prefix_match (struct prefix *n, struct prefix *p) +{ + int offset; + int shift; + + /* Set both prefix's head pointer. */ + u_char *np = (u_char *)&n->u.prefix; + u_char *pp = (u_char *)&p->u.prefix; + + /* If n's prefix is longer than p's one return 0. */ + if (n->prefixlen > p->prefixlen) + return 0; + + offset = n->prefixlen / PNBBY; + shift = n->prefixlen % PNBBY; + + if (shift) + if (maskbit[shift] & (np[offset] ^ pp[offset])) + return 0; + + while (offset--) + if (np[offset] != pp[offset]) + return 0; + return 1; +} + +/* Copy prefix from src to dest. */ +void +prefix_copy (struct prefix *dest, struct prefix *src) +{ + dest->family = src->family; + dest->prefixlen = src->prefixlen; + + if (src->family == AF_INET) + dest->u.prefix4 = src->u.prefix4; +#ifdef HAVE_IPV6 + else if (src->family == AF_INET6) + dest->u.prefix6 = src->u.prefix6; +#endif /* HAVE_IPV6 */ + else if (src->family == AF_UNSPEC) + { + dest->u.lp.id = src->u.lp.id; + dest->u.lp.adv_router = src->u.lp.adv_router; + } + else + { + zlog (NULL, LOG_INFO, "prefix_copy(): Unknown address family %d", + src->family); + assert (0); + } +} + +/* If both prefix structure is same then return 1 else return 0. */ +int +prefix_same (struct prefix *p1, struct prefix *p2) +{ + if (p1->family == p2->family && p1->prefixlen == p2->prefixlen) + { + if (p1->family == AF_INET) + if (IPV4_ADDR_SAME (&p1->u.prefix, &p2->u.prefix)) + return 1; +#ifdef HAVE_IPV6 + if (p1->family == AF_INET6 ) + if (IPV6_ADDR_SAME (&p1->u.prefix, &p2->u.prefix)) + return 1; +#endif /* HAVE_IPV6 */ + } + return 0; +} + +/* When both prefix structure is not same, but will be same after + applying mask, return 0. otherwise, return 1 */ +int +prefix_cmp (struct prefix *p1, struct prefix *p2) +{ + int offset; + int shift; + + /* Set both prefix's head pointer. */ + u_char *pp1 = (u_char *)&p1->u.prefix; + u_char *pp2 = (u_char *)&p2->u.prefix; + + if (p1->family != p2->family || p1->prefixlen != p2->prefixlen) + return 1; + + offset = p1->prefixlen / 8; + shift = p1->prefixlen % 8; + + if (shift) + if (maskbit[shift] & (pp1[offset] ^ pp2[offset])) + return 1; + + while (offset--) + if (pp1[offset] != pp2[offset]) + return 1; + + return 0; +} + +/* Return prefix family type string. */ +char * +prefix_family_str (struct prefix *p) +{ + if (p->family == AF_INET) + return "inet"; +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + return "inet6"; +#endif /* HAVE_IPV6 */ + return "unspec"; +} + +/* Allocate new prefix_ipv4 structure. */ +struct prefix_ipv4 * +prefix_ipv4_new () +{ + struct prefix_ipv4 *p; + + p = XCALLOC (MTYPE_PREFIX_IPV4, sizeof *p); + p->family = AF_INET; + return p; +} + +/* Free prefix_ipv4 structure. */ +void +prefix_ipv4_free (struct prefix_ipv4 *p) +{ + XFREE (MTYPE_PREFIX_IPV4, p); +} + +/* When string format is invalid return 0. */ +int +str2prefix_ipv4 (char *str, struct prefix_ipv4 *p) +{ + int ret; + int plen; + char *pnt; + char *cp; + + /* Find slash inside string. */ + pnt = strchr (str, '/'); + + /* String doesn't contail slash. */ + if (pnt == NULL) + { + /* Convert string to prefix. */ + ret = inet_aton (str, &p->prefix); + if (ret == 0) + return 0; + + /* If address doesn't contain slash we assume it host address. */ + p->family = AF_INET; + p->prefixlen = IPV4_MAX_BITLEN; + + return ret; + } + else + { + cp = XMALLOC (MTYPE_TMP, (pnt - str) + 1); + strncpy (cp, str, pnt - str); + *(cp + (pnt - str)) = '\0'; + ret = inet_aton (cp, &p->prefix); + XFREE (MTYPE_TMP, cp); + + /* Get prefix length. */ + plen = (u_char) atoi (++pnt); + if (plen > 32) + return 0; + + p->family = AF_INET; + p->prefixlen = plen; + } + + return ret; +} + +/* Convert masklen into IP address's netmask. */ +void +masklen2ip (int masklen, struct in_addr *netmask) +{ + u_char *pnt; + int bit; + int offset; + + memset (netmask, 0, sizeof (struct in_addr)); + pnt = (unsigned char *) netmask; + + offset = masklen / 8; + bit = masklen % 8; + + while (offset--) + *pnt++ = 0xff; + + if (bit) + *pnt = maskbit[bit]; +} + +/* Convert IP address's netmask into integer. We assume netmask is + sequential one. Argument netmask should be network byte order. */ +u_char +ip_masklen (struct in_addr netmask) +{ + u_char len; + u_char *pnt; + u_char *end; + u_char val; + + len = 0; + pnt = (u_char *) &netmask; + end = pnt + 4; + + while ((*pnt == 0xff) && pnt < end) + { + len+= 8; + pnt++; + } + + if (pnt < end) + { + val = *pnt; + while (val) + { + len++; + val <<= 1; + } + } + return len; +} + +/* Apply mask to IPv4 prefix. */ +void +apply_mask_ipv4 (struct prefix_ipv4 *p) +{ + u_char *pnt; + int index; + int offset; + + index = p->prefixlen / 8; + + if (index < 4) + { + pnt = (u_char *) &p->prefix; + offset = p->prefixlen % 8; + + pnt[index] &= maskbit[offset]; + index++; + + while (index < 4) + pnt[index++] = 0; + } +} + +/* If prefix is 0.0.0.0/0 then return 1 else return 0. */ +int +prefix_ipv4_any (struct prefix_ipv4 *p) +{ + return (p->prefix.s_addr == 0 && p->prefixlen == 0); +} + +#ifdef HAVE_IPV6 + +/* Allocate a new ip version 6 route */ +struct prefix_ipv6 * +prefix_ipv6_new () +{ + struct prefix_ipv6 *p; + + p = XCALLOC (MTYPE_PREFIX_IPV6, sizeof (struct prefix_ipv6)); + p->family = AF_INET6; + return p; +} + +/* Free prefix for IPv6. */ +void +prefix_ipv6_free (struct prefix_ipv6 *p) +{ + XFREE (MTYPE_PREFIX_IPV6, p); +} + +/* If given string is valid return pin6 else return NULL */ +int +str2prefix_ipv6 (char *str, struct prefix_ipv6 *p) +{ + char *pnt; + char *cp; + int ret; + + pnt = strchr (str, '/'); + + /* If string doesn't contain `/' treat it as host route. */ + if (pnt == NULL) + { + ret = inet_pton (AF_INET6, str, &p->prefix); + if (ret != 1) + return 0; + p->prefixlen = IPV6_MAX_BITLEN; + } + else + { + int plen; + + cp = XMALLOC (0, (pnt - str) + 1); + strncpy (cp, str, pnt - str); + *(cp + (pnt - str)) = '\0'; + ret = inet_pton (AF_INET6, cp, &p->prefix); + free (cp); + if (ret != 1) + return 0; + plen = (u_char) atoi (++pnt); + if (plen > 128) + return 0; + p->prefixlen = plen; + } + p->family = AF_INET6; + + return ret; +} + +/* Convert struct in6_addr netmask into integer. */ +int +ip6_masklen (struct in6_addr netmask) +{ + int len = 0; + unsigned char val; + unsigned char *pnt; + + pnt = (unsigned char *) & netmask; + + while ((*pnt == 0xff) && len < 128) + { + len += 8; + pnt++; + } + + if (len < 128) + { + val = *pnt; + while (val) + { + len++; + val <<= 1; + } + } + return len; +} + +void +masklen2ip6 (int masklen, struct in6_addr *netmask) +{ + unsigned char *pnt; + int bit; + int offset; + + memset (netmask, 0, sizeof (struct in6_addr)); + pnt = (unsigned char *) netmask; + + offset = masklen / 8; + bit = masklen % 8; + + while (offset--) + *pnt++ = 0xff; + + if (bit) + *pnt = maskbit[bit]; +} + +void +apply_mask_ipv6 (struct prefix_ipv6 *p) +{ + u_char *pnt; + int index; + int offset; + + index = p->prefixlen / 8; + + if (index < 16) + { + pnt = (u_char *) &p->prefix; + offset = p->prefixlen % 8; + + pnt[index] &= maskbit[offset]; + index++; + + while (index < 16) + pnt[index++] = 0; + } +} + +void +str2in6_addr (char *str, struct in6_addr *addr) +{ + int i; + unsigned int x; + + /* %x must point to unsinged int */ + for (i = 0; i < 16; i++) + { + sscanf (str + (i * 2), "%02x", &x); + addr->s6_addr[i] = x & 0xff; + } +} +#endif /* HAVE_IPV6 */ + +void +apply_mask (struct prefix *p) +{ + switch (p->family) + { + case AF_INET: + apply_mask_ipv4 ((struct prefix_ipv4 *)p); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + apply_mask_ipv6 ((struct prefix_ipv6 *)p); + break; +#endif /* HAVE_IPV6 */ + default: + break; + } + return; +} + +/* Utility function of convert between struct prefix <=> union sockunion */ +struct prefix * +sockunion2prefix (union sockunion *dest, + union sockunion *mask) +{ + if (dest->sa.sa_family == AF_INET) + { + struct prefix_ipv4 *p; + + p = prefix_ipv4_new (); + p->family = AF_INET; + p->prefix = dest->sin.sin_addr; + p->prefixlen = ip_masklen (mask->sin.sin_addr); + return (struct prefix *) p; + } +#ifdef HAVE_IPV6 + if (dest->sa.sa_family == AF_INET6) + { + struct prefix_ipv6 *p; + + p = prefix_ipv6_new (); + p->family = AF_INET6; + p->prefixlen = ip6_masklen (mask->sin6.sin6_addr); + memcpy (&p->prefix, &dest->sin6.sin6_addr, sizeof (struct in6_addr)); + return (struct prefix *) p; + } +#endif /* HAVE_IPV6 */ + return NULL; +} + +/* Utility function of convert between struct prefix <=> union sockunion */ +struct prefix * +sockunion2hostprefix (union sockunion *su) +{ + if (su->sa.sa_family == AF_INET) + { + struct prefix_ipv4 *p; + + p = prefix_ipv4_new (); + p->family = AF_INET; + p->prefix = su->sin.sin_addr; + p->prefixlen = IPV4_MAX_BITLEN; + return (struct prefix *) p; + } +#ifdef HAVE_IPV6 + if (su->sa.sa_family == AF_INET6) + { + struct prefix_ipv6 *p; + + p = prefix_ipv6_new (); + p->family = AF_INET6; + p->prefixlen = IPV6_MAX_BITLEN; + memcpy (&p->prefix, &su->sin6.sin6_addr, sizeof (struct in6_addr)); + return (struct prefix *) p; + } +#endif /* HAVE_IPV6 */ + return NULL; +} + +int +prefix_blen (struct prefix *p) +{ + switch (p->family) + { + case AF_INET: + return IPV4_MAX_BYTELEN; + break; +#ifdef HAVE_IPV6 + case AF_INET6: + return IPV6_MAX_BYTELEN; + break; +#endif /* HAVE_IPV6 */ + } + return 0; +} + +/* Generic function for conversion string to struct prefix. */ +int +str2prefix (char *str, struct prefix *p) +{ + int ret; + + /* First we try to convert string to struct prefix_ipv4. */ + ret = str2prefix_ipv4 (str, (struct prefix_ipv4 *) p); + if (ret) + return ret; + +#ifdef HAVE_IPV6 + /* Next we try to convert string to struct prefix_ipv6. */ + ret = str2prefix_ipv6 (str, (struct prefix_ipv6 *) p); + if (ret) + return ret; +#endif /* HAVE_IPV6 */ + + return 0; +} + +int +prefix2str (struct prefix *p, char *str, int size) +{ + char buf[BUFSIZ]; + + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ); + snprintf (str, size, "%s/%d", buf, p->prefixlen); + return 0; +} + +struct prefix * +prefix_new () +{ + struct prefix *p; + + p = XCALLOC (MTYPE_PREFIX, sizeof *p); + return p; +} + +/* Free prefix structure. */ +void +prefix_free (struct prefix *p) +{ + XFREE (MTYPE_PREFIX, p); +} + +/* Utility function. Check the string only contains digit + character. */ +int +all_digit (char *str) +{ + for (; *str != '\0'; str++) + if (!isdigit ((int) *str)) + return 0; + return 1; +} + +/* Utility function to convert ipv4 prefixes to Classful prefixes */ +void apply_classful_mask_ipv4 (struct prefix_ipv4 *p) +{ + + u_int32_t destination; + + destination = ntohl (p->prefix.s_addr); + + if (p->prefixlen == 32); + /* do nothing for host routes */ + else if (IN_CLASSC (destination)) + { + p->prefixlen=24; + apply_mask_ipv4(p); + } + else if (IN_CLASSB(destination)) + { + p->prefixlen=16; + apply_mask_ipv4(p); + } + else + { + p->prefixlen=8; + apply_mask_ipv4(p); + } +} + +/* Utility function to convert ipv4 netmask to prefixes + ex.) "1.1.0.0" "255.255.0.0" => "1.1.0.0/16" + ex.) "1.0.0.0" NULL => "1.0.0.0/8" */ +int +netmask_str2prefix_str (char *net_str, char *mask_str, char *prefix_str) +{ + struct in_addr network; + struct in_addr mask; + u_char prefixlen; + u_int32_t destination; + int ret; + + ret = inet_aton (net_str, &network); + if (! ret) + return 0; + + if (mask_str) + { + ret = inet_aton (mask_str, &mask); + if (! ret) + return 0; + + prefixlen = ip_masklen (mask); + } + else + { + destination = ntohl (network.s_addr); + + if (network.s_addr == 0) + prefixlen = 0; + else if (IN_CLASSC (destination)) + prefixlen = 24; + else if (IN_CLASSB (destination)) + prefixlen = 16; + else if (IN_CLASSA (destination)) + prefixlen = 8; + else + return 0; + } + + sprintf (prefix_str, "%s/%d", net_str, prefixlen); + + return 1; +} + diff --git a/lib/prefix.h b/lib/prefix.h new file mode 100644 index 00000000..7d7cde68 --- /dev/null +++ b/lib/prefix.h @@ -0,0 +1,161 @@ +/* + * Prefix structure. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_PREFIX_H +#define _ZEBRA_PREFIX_H + +/* IPv4 and IPv6 unified prefix structure. */ +struct prefix +{ + u_char family; + u_char prefixlen; + union + { + u_char prefix; + struct in_addr prefix4; +#ifdef HAVE_IPV6 + struct in6_addr prefix6; +#endif /* HAVE_IPV6 */ + struct + { + struct in_addr id; + struct in_addr adv_router; + } lp; + u_char val[8]; + } u __attribute__ ((aligned (8))); +}; + +/* IPv4 prefix structure. */ +struct prefix_ipv4 +{ + u_char family; + u_char prefixlen; + struct in_addr prefix __attribute__ ((aligned (8))); +}; + +/* IPv6 prefix structure. */ +#ifdef HAVE_IPV6 +struct prefix_ipv6 +{ + u_char family; + u_char prefixlen; + struct in6_addr prefix __attribute__ ((aligned (8))); +}; +#endif /* HAVE_IPV6 */ + +struct prefix_ls +{ + u_char family; + u_char prefixlen; + struct in_addr id __attribute__ ((aligned (8))); + struct in_addr adv_router; +}; + +/* Prefix for routing distinguisher. */ +struct prefix_rd +{ + u_char family; + u_char prefixlen; + u_char val[8] __attribute__ ((aligned (8))); +}; + +#ifndef INET_ADDRSTRLEN +#define INET_ADDRSTRLEN 16 +#endif /* INET_ADDRSTRLEN */ + +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN 46 +#endif /* INET6_ADDRSTRLEN */ + +#ifndef INET6_BUFSIZ +#define INET6_BUFSIZ 51 +#endif /* INET6_BUFSIZ */ + +/* Max bit/byte length of IPv4 address. */ +#define IPV4_MAX_BYTELEN 4 +#define IPV4_MAX_BITLEN 32 +#define IPV4_MAX_PREFIXLEN 32 +#define IPV4_ADDR_CMP(D,S) memcmp ((D), (S), IPV4_MAX_BYTELEN) +#define IPV4_ADDR_SAME(D,S) (memcmp ((D), (S), IPV4_MAX_BYTELEN) == 0) +#define IPV4_ADDR_COPY(D,S) memcpy ((D), (S), IPV4_MAX_BYTELEN) + +#define IPV4_NET0(a) ((((u_int32_t) (a)) & 0xff000000) == 0x00000000) +#define IPV4_NET127(a) ((((u_int32_t) (a)) & 0xff000000) == 0x7f000000) + +/* Max bit/byte length of IPv6 address. */ +#define IPV6_MAX_BYTELEN 16 +#define IPV6_MAX_BITLEN 128 +#define IPV6_MAX_PREFIXLEN 128 +#define IPV6_ADDR_CMP(D,S) memcmp ((D), (S), IPV6_MAX_BYTELEN) +#define IPV6_ADDR_SAME(D,S) (memcmp ((D), (S), IPV6_MAX_BYTELEN) == 0) +#define IPV6_ADDR_COPY(D,S) memcpy ((D), (S), IPV6_MAX_BYTELEN) + +/* Count prefix size from mask length */ +#define PSIZE(a) (((a) + 7) / (8)) + +/* Prefix's family member. */ +#define PREFIX_FAMILY(p) ((p)->family) + +/* Prototypes. */ +int afi2family (int); +int family2afi (int); + +int prefix2str (struct prefix *, char *, int); +int str2prefix (char *, struct prefix *); +struct prefix *prefix_new (); +void prefix_free (struct prefix *p); + +struct prefix_ipv4 *prefix_ipv4_new (); +void prefix_ipv4_free (); +int str2prefix_ipv4 (char *, struct prefix_ipv4 *); +void apply_mask_ipv4 (struct prefix_ipv4 *); +int prefix_blen (struct prefix *); +u_char ip_masklen (struct in_addr); +int prefix_ipv4_any (struct prefix_ipv4 *); +void masklen2ip (int, struct in_addr *); +void apply_classful_mask_ipv4 (struct prefix_ipv4 *); + +char *prefix_family_str (struct prefix *p); +struct prefix *sockunion2prefix (); +struct prefix *sockunion2hostprefix (); + +#ifdef HAVE_IPV6 +struct prefix_ipv6 *prefix_ipv6_new (); +void prefix_ipv6_free (); +struct prefix *str2routev6 (char *); +int str2prefix_ipv6 (char *str, struct prefix_ipv6 *p); +void apply_mask_ipv6 (struct prefix_ipv6 *p); +void str2in6_addr (char *str, struct in6_addr *addr); +void masklen2ip6 (int masklen, struct in6_addr *netmask); +int ip6_masklen (struct in6_addr netmask); +#endif /* HAVE_IPV6 */ + +void apply_mask (struct prefix *); +int prefix_match (struct prefix *n, struct prefix *p); +int prefix_same (struct prefix *, struct prefix *); +int prefix_cmp (struct prefix *, struct prefix *); +void prefix_copy (struct prefix *, struct prefix *); + +int all_digit (char *); +int netmask_str2prefix_str (char *, char *, char *); + +#endif /* _ZEBRA_PREFIX_H */ diff --git a/lib/print_version.c b/lib/print_version.c new file mode 100644 index 00000000..6b4064d3 --- /dev/null +++ b/lib/print_version.c @@ -0,0 +1,31 @@ +/* Print version function. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "version.h" + +void +print_version (char *progname) +{ + printf ("%s version %s (%s)\n", progname, ZEBRA_VERSION, host_name); + printf ("Copyright 1996-2001, Kunihiro Ishiguro\n"); +} diff --git a/lib/regex-gnu.h b/lib/regex-gnu.h new file mode 100644 index 00000000..d88ab92b --- /dev/null +++ b/lib/regex-gnu.h @@ -0,0 +1,542 @@ +/* Definitions for data structures and routines for the regular + expression library, version 0.12. + Copyright (C) 1985,89,90,91,92,93,95,96,97,98 Free Software Foundation, Inc. + + This file is part of the GNU C Library. Its master source is NOT part of + the C library, however. The master source lives in /gd/gnu/lib. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _REGEX_H +#define _REGEX_H 1 + +/* Allow the use in C++ code. */ +#ifdef __cplusplus +extern "C" { +#endif + +/* POSIX says that must be included (by the caller) before + . */ + +#if !defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE && defined VMS +/* VMS doesn't have `size_t' in , even though POSIX says it + should be there. */ +# include +#endif + +/* The following two types have to be signed and unsigned integer type + wide enough to hold a value of a pointer. For most ANSI compilers + ptrdiff_t and size_t should be likely OK. Still size of these two + types is 2 for Microsoft C. Ugh... */ +typedef long int s_reg_t; +typedef unsigned long int active_reg_t; + +/* The following bits are used to determine the regexp syntax we + recognize. The set/not-set meanings are chosen so that Emacs syntax + remains the value 0. The bits are given in alphabetical order, and + the definitions shifted by one from the previous bit; thus, when we + add or remove a bit, only one other definition need change. */ +typedef unsigned long int reg_syntax_t; + +/* If this bit is not set, then \ inside a bracket expression is literal. + If set, then such a \ quotes the following character. */ +#define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1) + +/* If this bit is not set, then + and ? are operators, and \+ and \? are + literals. + If set, then \+ and \? are operators and + and ? are literals. */ +#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) + +/* If this bit is set, then character classes are supported. They are: + [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], + [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. + If not set, then character classes are not supported. */ +#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) + +/* If this bit is set, then ^ and $ are always anchors (outside bracket + expressions, of course). + If this bit is not set, then it depends: + ^ is an anchor if it is at the beginning of a regular + expression or after an open-group or an alternation operator; + $ is an anchor if it is at the end of a regular expression, or + before a close-group or an alternation operator. + + This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because + POSIX draft 11.2 says that * etc. in leading positions is undefined. + We already implemented a previous draft which made those constructs + invalid, though, so we haven't changed the code back. */ +#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) + +/* If this bit is set, then special characters are always special + regardless of where they are in the pattern. + If this bit is not set, then special characters are special only in + some contexts; otherwise they are ordinary. Specifically, + * + ? and intervals are only special when not after the beginning, + open-group, or alternation operator. */ +#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) + +/* If this bit is set, then *, +, ?, and { cannot be first in an re or + immediately after an alternation or begin-group operator. */ +#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) + +/* If this bit is set, then . matches newline. + If not set, then it doesn't. */ +#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) + +/* If this bit is set, then . doesn't match NUL. + If not set, then it does. */ +#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) + +/* If this bit is set, nonmatching lists [^...] do not match newline. + If not set, they do. */ +#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) + +/* If this bit is set, either \{...\} or {...} defines an + interval, depending on RE_NO_BK_BRACES. + If not set, \{, \}, {, and } are literals. */ +#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) + +/* If this bit is set, +, ? and | aren't recognized as operators. + If not set, they are. */ +#define RE_LIMITED_OPS (RE_INTERVALS << 1) + +/* If this bit is set, newline is an alternation operator. + If not set, newline is literal. */ +#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) + +/* If this bit is set, then `{...}' defines an interval, and \{ and \} + are literals. + If not set, then `\{...\}' defines an interval. */ +#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) + +/* If this bit is set, (...) defines a group, and \( and \) are literals. + If not set, \(...\) defines a group, and ( and ) are literals. */ +#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) + +/* If this bit is set, then \ matches . + If not set, then \ is a back-reference. */ +#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) + +/* If this bit is set, then | is an alternation operator, and \| is literal. + If not set, then \| is an alternation operator, and | is literal. */ +#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) + +/* If this bit is set, then an ending range point collating higher + than the starting range point, as in [z-a], is invalid. + If not set, then when ending range point collates higher than the + starting range point, the range is ignored. */ +#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) + +/* If this bit is set, then an unmatched ) is ordinary. + If not set, then an unmatched ) is invalid. */ +#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) + +/* If this bit is set, succeed as soon as we match the whole pattern, + without further backtracking. */ +#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1) + +/* If this bit is set, do not process the GNU regex operators. + If not set, then the GNU regex operators are recognized. */ +#define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1) + +/* If this bit is set, turn on internal regex debugging. + If not set, and debugging was on, turn it off. + This only works if regex.c is compiled -DDEBUG. + We define this bit always, so that all that's needed to turn on + debugging is to recompile regex.c; the calling code can always have + this bit set, and it won't affect anything in the normal case. */ +#define RE_DEBUG (RE_NO_GNU_OPS << 1) + +/* This global variable defines the particular regexp syntax to use (for + some interfaces). When a regexp is compiled, the syntax used is + stored in the pattern buffer, so changing this does not affect + already-compiled regexps. */ +extern reg_syntax_t re_syntax_options; + +/* Define combinations of the above bits for the standard possibilities. + (The [[[ comments delimit what gets put into the Texinfo file, so + don't delete them!) */ +/* [[[begin syntaxes]]] */ +#define RE_SYNTAX_EMACS 0 + +#define RE_SYNTAX_AWK \ + (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ + | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \ + | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS) + +#define RE_SYNTAX_GNU_AWK \ + ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG) \ + & ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS)) + +#define RE_SYNTAX_POSIX_AWK \ + (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ + | RE_INTERVALS | RE_NO_GNU_OPS) + +#define RE_SYNTAX_GREP \ + (RE_BK_PLUS_QM | RE_CHAR_CLASSES \ + | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \ + | RE_NEWLINE_ALT) + +#define RE_SYNTAX_EGREP \ + (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \ + | RE_NEWLINE_ALT | RE_NO_BK_PARENS \ + | RE_NO_BK_VBAR) + +#define RE_SYNTAX_POSIX_EGREP \ + (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES) + +/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ +#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC + +#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC + +/* Syntax bits common to both basic and extended POSIX regex syntax. */ +#define _RE_SYNTAX_POSIX_COMMON \ + (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ + | RE_INTERVALS | RE_NO_EMPTY_RANGES) + +#define RE_SYNTAX_POSIX_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM) + +/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes + RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this + isn't minimal, since other operators, such as \`, aren't disabled. */ +#define RE_SYNTAX_POSIX_MINIMAL_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) + +#define RE_SYNTAX_POSIX_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ + | RE_UNMATCHED_RIGHT_PAREN_ORD) + +/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS + replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */ +#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) +/* [[[end syntaxes]]] */ + +/* Maximum number of duplicates an interval can allow. Some systems + (erroneously) define this in other header files, but we want our + value, so remove any previous define. */ +#ifdef RE_DUP_MAX +# undef RE_DUP_MAX +#endif +/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */ +#define RE_DUP_MAX (0x7fff) + + +/* POSIX `cflags' bits (i.e., information for `regcomp'). */ + +/* If this bit is set, then use extended regular expression syntax. + If not set, then use basic regular expression syntax. */ +#define REG_EXTENDED 1 + +/* If this bit is set, then ignore case when matching. + If not set, then case is significant. */ +#define REG_ICASE (REG_EXTENDED << 1) + +/* If this bit is set, then anchors do not match at newline + characters in the string. + If not set, then anchors do match at newlines. */ +#define REG_NEWLINE (REG_ICASE << 1) + +/* If this bit is set, then report only success or fail in regexec. + If not set, then returns differ between not matching and errors. */ +#define REG_NOSUB (REG_NEWLINE << 1) + + +/* POSIX `eflags' bits (i.e., information for regexec). */ + +/* If this bit is set, then the beginning-of-line operator doesn't match + the beginning of the string (presumably because it's not the + beginning of a line). + If not set, then the beginning-of-line operator does match the + beginning of the string. */ +#define REG_NOTBOL 1 + +/* Like REG_NOTBOL, except for the end-of-line. */ +#define REG_NOTEOL (1 << 1) + + +/* If any error codes are removed, changed, or added, update the + `re_error_msg' table in regex.c. */ +typedef enum +{ +#ifdef _XOPEN_SOURCE + REG_ENOSYS = -1, /* This will never happen for this implementation. */ +#endif + + REG_NOERROR = 0, /* Success. */ + REG_NOMATCH, /* Didn't find a match (for regexec). */ + + /* POSIX regcomp return error codes. (In the order listed in the + standard.) */ + REG_BADPAT, /* Invalid pattern. */ + REG_ECOLLATE, /* Not implemented. */ + REG_ECTYPE, /* Invalid character class name. */ + REG_EESCAPE, /* Trailing backslash. */ + REG_ESUBREG, /* Invalid back reference. */ + REG_EBRACK, /* Unmatched left bracket. */ + REG_EPAREN, /* Parenthesis imbalance. */ + REG_EBRACE, /* Unmatched \{. */ + REG_BADBR, /* Invalid contents of \{\}. */ + REG_ERANGE, /* Invalid range end. */ + REG_ESPACE, /* Ran out of memory. */ + REG_BADRPT, /* No preceding re for repetition op. */ + + /* Error codes we've added. */ + REG_EEND, /* Premature end. */ + REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ + REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ +} reg_errcode_t; + +/* This data structure represents a compiled pattern. Before calling + the pattern compiler, the fields `buffer', `allocated', `fastmap', + `translate', and `no_sub' can be set. After the pattern has been + compiled, the `re_nsub' field is available. All other fields are + private to the regex routines. */ + +#ifndef RE_TRANSLATE_TYPE +# define RE_TRANSLATE_TYPE char * +#endif + +struct re_pattern_buffer +{ +/* [[[begin pattern_buffer]]] */ + /* Space that holds the compiled pattern. It is declared as + `unsigned char *' because its elements are + sometimes used as array indexes. */ + unsigned char *buffer; + + /* Number of bytes to which `buffer' points. */ + unsigned long int allocated; + + /* Number of bytes actually used in `buffer'. */ + unsigned long int used; + + /* Syntax setting with which the pattern was compiled. */ + reg_syntax_t syntax; + + /* Pointer to a fastmap, if any, otherwise zero. re_search uses + the fastmap, if there is one, to skip over impossible + starting points for matches. */ + char *fastmap; + + /* Either a translate table to apply to all characters before + comparing them, or zero for no translation. The translation + is applied to a pattern when it is compiled and to a string + when it is matched. */ + RE_TRANSLATE_TYPE translate; + + /* Number of subexpressions found by the compiler. */ + size_t re_nsub; + + /* Zero if this pattern cannot match the empty string, one else. + Well, in truth it's used only in `re_search_2', to see + whether or not we should use the fastmap, so we don't set + this absolutely perfectly; see `re_compile_fastmap' (the + `duplicate' case). */ + unsigned can_be_null : 1; + + /* If REGS_UNALLOCATED, allocate space in the `regs' structure + for `max (RE_NREGS, re_nsub + 1)' groups. + If REGS_REALLOCATE, reallocate space if necessary. + If REGS_FIXED, use what's there. */ +#define REGS_UNALLOCATED 0 +#define REGS_REALLOCATE 1 +#define REGS_FIXED 2 + unsigned regs_allocated : 2; + + /* Set to zero when `regex_compile' compiles a pattern; set to one + by `re_compile_fastmap' if it updates the fastmap. */ + unsigned fastmap_accurate : 1; + + /* If set, `re_match_2' does not return information about + subexpressions. */ + unsigned no_sub : 1; + + /* If set, a beginning-of-line anchor doesn't match at the + beginning of the string. */ + unsigned not_bol : 1; + + /* Similarly for an end-of-line anchor. */ + unsigned not_eol : 1; + + /* If true, an anchor at a newline matches. */ + unsigned newline_anchor : 1; + +/* [[[end pattern_buffer]]] */ +}; + +typedef struct re_pattern_buffer regex_t; + +/* Type for byte offsets within the string. POSIX mandates this. */ +typedef int regoff_t; + + +/* This is the structure we store register match data in. See + regex.texinfo for a full description of what registers match. */ +struct re_registers +{ + unsigned num_regs; + regoff_t *start; + regoff_t *end; +}; + + +/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer, + `re_match_2' returns information about at least this many registers + the first time a `regs' structure is passed. */ +#ifndef RE_NREGS +# define RE_NREGS 30 +#endif + + +/* POSIX specification for registers. Aside from the different names than + `re_registers', POSIX uses an array of structures, instead of a + structure of arrays. */ +typedef struct +{ + regoff_t rm_so; /* Byte offset from string's start to substring's start. */ + regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ +} regmatch_t; + +/* Declarations for routines. */ + +/* To avoid duplicating every routine declaration -- once with a + prototype (if we are ANSI), and once without (if we aren't) -- we + use the following macro to declare argument types. This + unfortunately clutters up the declarations a bit, but I think it's + worth it. */ + +#if __STDC__ + +# define _RE_ARGS(args) args + +#else /* not __STDC__ */ + +# define _RE_ARGS(args) () + +#endif /* not __STDC__ */ + +/* Sets the current default syntax to SYNTAX, and return the old syntax. + You can also simply assign to the `re_syntax_options' variable. */ +extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax)); + +/* Compile the regular expression PATTERN, with length LENGTH + and syntax given by the global `re_syntax_options', into the buffer + BUFFER. Return NULL if successful, and an error string if not. */ +extern const char *re_compile_pattern + _RE_ARGS ((const char *pattern, size_t length, + struct re_pattern_buffer *buffer)); + + +/* Compile a fastmap for the compiled pattern in BUFFER; used to + accelerate searches. Return 0 if successful and -2 if was an + internal error. */ +extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer)); + + +/* Search in the string STRING (with length LENGTH) for the pattern + compiled into BUFFER. Start searching at position START, for RANGE + characters. Return the starting position of the match, -1 for no + match, or -2 for an internal error. Also return register + information in REGS (if REGS and BUFFER->no_sub are nonzero). */ +extern int re_search + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, + int length, int start, int range, struct re_registers *regs)); + + +/* Like `re_search', but search in the concatenation of STRING1 and + STRING2. Also, stop searching at index START + STOP. */ +extern int re_search_2 + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, + int length1, const char *string2, int length2, + int start, int range, struct re_registers *regs, int stop)); + + +/* Like `re_search', but return how many characters in STRING the regexp + in BUFFER matched, starting at position START. */ +extern int re_match + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, + int length, int start, struct re_registers *regs)); + + +/* Relates to `re_match' as `re_search_2' relates to `re_search'. */ +extern int re_match_2 + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, + int length1, const char *string2, int length2, + int start, struct re_registers *regs, int stop)); + + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using BUFFER and REGS will use this memory + for recording register information. STARTS and ENDS must be + allocated with malloc, and must each be at least `NUM_REGS * sizeof + (regoff_t)' bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ +extern void re_set_registers + _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs, + unsigned num_regs, regoff_t *starts, regoff_t *ends)); + +#if defined _REGEX_RE_COMP || defined _LIBC +# ifndef _CRAY +/* 4.2 bsd compatibility. */ +extern char *re_comp _RE_ARGS ((const char *)); +extern int re_exec _RE_ARGS ((const char *)); +# endif +#endif + +/* POSIX compatibility. */ +extern int regcomp _RE_ARGS ((regex_t *__preg, const char *__pattern, + int __cflags)); + +extern int regexec _RE_ARGS ((const regex_t *__preg, + const char *__string, size_t __nmatch, + regmatch_t __pmatch[], int __eflags)); + +extern size_t regerror _RE_ARGS ((int __errcode, const regex_t *__preg, + char *__errbuf, size_t __errbuf_size)); + +extern void regfree _RE_ARGS ((regex_t *__preg)); + + +#ifdef __cplusplus +} +#endif /* C++ */ + +#endif /* regex.h */ + +/* +Local variables: +make-backup-files: t +version-control: t +trim-versions-without-asking: nil +End: +*/ diff --git a/lib/regex.c b/lib/regex.c new file mode 100644 index 00000000..8c7acd54 --- /dev/null +++ b/lib/regex.c @@ -0,0 +1,5891 @@ +/* Extended regular expression matching and search library, + version 0.12. + (Implements POSIX draft P1003.2/D11.2, except for some of the + internationalization features.) + Copyright (C) 1993, 94, 95, 96, 97, 98, 99 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* AIX requires this to be the first thing in the file. */ +#if defined _AIX && !defined REGEX_MALLOC + #pragma alloca +#endif + +#undef _GNU_SOURCE +#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifndef PARAMS +# if defined __GNUC__ || (defined __STDC__ && __STDC__) +# define PARAMS(args) args +# else +# define PARAMS(args) () +# endif /* GCC. */ +#endif /* Not PARAMS. */ + +#if defined STDC_HEADERS && !defined emacs +# include +#else +/* We need this for `regex.h', and perhaps for the Emacs include files. */ +# include +#endif + +#define WIDE_CHAR_SUPPORT (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC) + +/* For platform which support the ISO C amendement 1 functionality we + support user defined character classes. */ +#if defined _LIBC || WIDE_CHAR_SUPPORT +/* Solaris 2.5 has a bug: must be included before . */ +# include +# include +#endif + +#ifdef _LIBC +/* We have to keep the namespace clean. */ +# define regfree(preg) __regfree (preg) +# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef) +# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags) +# define regerror(errcode, preg, errbuf, errbuf_size) \ + __regerror(errcode, preg, errbuf, errbuf_size) +# define re_set_registers(bu, re, nu, st, en) \ + __re_set_registers (bu, re, nu, st, en) +# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \ + __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) +# define re_match(bufp, string, size, pos, regs) \ + __re_match (bufp, string, size, pos, regs) +# define re_search(bufp, string, size, startpos, range, regs) \ + __re_search (bufp, string, size, startpos, range, regs) +# define re_compile_pattern(pattern, length, bufp) \ + __re_compile_pattern (pattern, length, bufp) +# define re_set_syntax(syntax) __re_set_syntax (syntax) +# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \ + __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop) +# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp) + +#define btowc __btowc +#endif + +/* This is for other GNU distributions with internationalized messages. */ +#if HAVE_LIBINTL_H || defined _LIBC +# include +#else +# define gettext(msgid) (msgid) +#endif + +#ifndef gettext_noop +/* This define is so xgettext can find the internationalizable + strings. */ +# define gettext_noop(String) String +#endif + +/* The `emacs' switch turns on certain matching commands + that make sense only in Emacs. */ +#ifdef emacs + +# include "lisp.h" +# include "buffer.h" +# include "syntax.h" + +#else /* not emacs */ + +/* If we are not linking with Emacs proper, + we can't use the relocating allocator + even if config.h says that we can. */ +# undef REL_ALLOC + +# if defined STDC_HEADERS || defined _LIBC +# include +# else +char *malloc (); +char *realloc (); +# endif + +/* When used in Emacs's lib-src, we need to get bzero and bcopy somehow. + If nothing else has been done, use the method below. */ +# ifdef INHIBIT_STRING_HEADER +# if !(defined HAVE_BZERO && defined HAVE_BCOPY) +# if !defined bzero && !defined bcopy +# undef INHIBIT_STRING_HEADER +# endif +# endif +# endif + +/* This is the normal way of making sure we have a bcopy and a bzero. + This is used in most programs--a few other programs avoid this + by defining INHIBIT_STRING_HEADER. */ +# ifndef INHIBIT_STRING_HEADER +# if defined HAVE_STRING_H || defined STDC_HEADERS || defined _LIBC +# include +# ifndef bzero +# ifndef _LIBC +# define bzero(s, n) (memset (s, '\0', n), (s)) +# else +# define bzero(s, n) __bzero (s, n) +# endif +# endif +# else +# include +# ifndef memcmp +# define memcmp(s1, s2, n) bcmp (s1, s2, n) +# endif +# ifndef memcpy +# define memcpy(d, s, n) (bcopy (s, d, n), (d)) +# endif +# endif +# endif + +/* Define the syntax stuff for \<, \>, etc. */ + +/* This must be nonzero for the wordchar and notwordchar pattern + commands in re_match_2. */ +# ifndef Sword +# define Sword 1 +# endif + +# ifdef SWITCH_ENUM_BUG +# define SWITCH_ENUM_CAST(x) ((int)(x)) +# else +# define SWITCH_ENUM_CAST(x) (x) +# endif + +/* How many characters in the character set. */ +# define CHAR_SET_SIZE 256 + +# ifdef SYNTAX_TABLE + +extern char *re_syntax_table; + +# else /* not SYNTAX_TABLE */ + +static char re_syntax_table[CHAR_SET_SIZE]; + +static void +init_syntax_once () +{ + register int c; + static int done; + + if (done) + return; + + bzero (re_syntax_table, sizeof re_syntax_table); + + for (c = 'a'; c <= 'z'; c++) + re_syntax_table[c] = Sword; + + for (c = 'A'; c <= 'Z'; c++) + re_syntax_table[c] = Sword; + + for (c = '0'; c <= '9'; c++) + re_syntax_table[c] = Sword; + + re_syntax_table['_'] = Sword; + + done = 1; +} + +# endif /* not SYNTAX_TABLE */ + +# define SYNTAX(c) re_syntax_table[c] + +#endif /* not emacs */ + +/* Get the interface, including the syntax bits. */ +#include + +/* isalpha etc. are used for the character classes. */ +#include + +/* Jim Meyering writes: + + "... Some ctype macros are valid only for character codes that + isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when + using /bin/cc or gcc but without giving an ansi option). So, all + ctype uses should be through macros like ISPRINT... If + STDC_HEADERS is defined, then autoconf has verified that the ctype + macros don't need to be guarded with references to isascii. ... + Defining isascii to 1 should let any compiler worth its salt + eliminate the && through constant folding." + Solaris defines some of these symbols so we must undefine them first. */ + +#undef ISASCII +#if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII) +# define ISASCII(c) 1 +#else +# define ISASCII(c) isascii(c) +#endif + +#ifdef isblank +# define ISBLANK(c) (ISASCII (c) && isblank (c)) +#else +# define ISBLANK(c) ((c) == ' ' || (c) == '\t') +#endif +#ifdef isgraph +# define ISGRAPH(c) (ISASCII (c) && isgraph (c)) +#else +# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c)) +#endif + +#undef ISPRINT +#define ISPRINT(c) (ISASCII (c) && isprint (c)) +#define ISDIGIT(c) (ISASCII (c) && isdigit (c)) +#define ISALNUM(c) (ISASCII (c) && isalnum (c)) +#define ISALPHA(c) (ISASCII (c) && isalpha (c)) +#define ISCNTRL(c) (ISASCII (c) && iscntrl (c)) +#define ISLOWER(c) (ISASCII (c) && islower (c)) +#define ISPUNCT(c) (ISASCII (c) && ispunct (c)) +#define ISSPACE(c) (ISASCII (c) && isspace (c)) +#define ISUPPER(c) (ISASCII (c) && isupper (c)) +#define ISXDIGIT(c) (ISASCII (c) && isxdigit (c)) + +#ifdef _tolower +# define TOLOWER(c) _tolower(c) +#else +# define TOLOWER(c) tolower(c) +#endif + +#ifndef NULL +# define NULL (void *)0 +#endif + +/* We remove any previous definition of `SIGN_EXTEND_CHAR', + since ours (we hope) works properly with all combinations of + machines, compilers, `char' and `unsigned char' argument types. + (Per Bothner suggested the basic approach.) */ +#undef SIGN_EXTEND_CHAR +#if __STDC__ +# define SIGN_EXTEND_CHAR(c) ((signed char) (c)) +#else /* not __STDC__ */ +/* As in Harbison and Steele. */ +# define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128) +#endif + +/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we + use `alloca' instead of `malloc'. This is because using malloc in + re_search* or re_match* could cause memory leaks when C-g is used in + Emacs; also, malloc is slower and causes storage fragmentation. On + the other hand, malloc is more portable, and easier to debug. + + Because we sometimes use alloca, some routines have to be macros, + not functions -- `alloca'-allocated space disappears at the end of the + function it is called in. */ + +#ifdef REGEX_MALLOC + +# define REGEX_ALLOCATE malloc +# define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize) +# define REGEX_FREE free + +#else /* not REGEX_MALLOC */ + +/* Emacs already defines alloca, sometimes. */ +# ifndef alloca + +/* Make alloca work the best possible way. */ +# ifdef __GNUC__ +# define alloca __builtin_alloca +# else /* not __GNUC__ */ +# if HAVE_ALLOCA_H +# include +# endif /* HAVE_ALLOCA_H */ +# endif /* not __GNUC__ */ + +# endif /* not alloca */ + +# define REGEX_ALLOCATE alloca + +/* Assumes a `char *destination' variable. */ +# define REGEX_REALLOCATE(source, osize, nsize) \ + (destination = (char *) alloca (nsize), \ + memcpy (destination, source, osize)) + +/* No need to do anything to free, after alloca. */ +# define REGEX_FREE(arg) ((void)0) /* Do nothing! But inhibit gcc warning. */ + +#endif /* not REGEX_MALLOC */ + +/* Define how to allocate the failure stack. */ + +#if defined REL_ALLOC && defined REGEX_MALLOC + +# define REGEX_ALLOCATE_STACK(size) \ + r_alloc (&failure_stack_ptr, (size)) +# define REGEX_REALLOCATE_STACK(source, osize, nsize) \ + r_re_alloc (&failure_stack_ptr, (nsize)) +# define REGEX_FREE_STACK(ptr) \ + r_alloc_free (&failure_stack_ptr) + +#else /* not using relocating allocator */ + +# ifdef REGEX_MALLOC + +# define REGEX_ALLOCATE_STACK malloc +# define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize) +# define REGEX_FREE_STACK free + +# else /* not REGEX_MALLOC */ + +# define REGEX_ALLOCATE_STACK alloca + +# define REGEX_REALLOCATE_STACK(source, osize, nsize) \ + REGEX_REALLOCATE (source, osize, nsize) +/* No need to explicitly free anything. */ +# define REGEX_FREE_STACK(arg) + +# endif /* not REGEX_MALLOC */ +#endif /* not using relocating allocator */ + + +/* True if `size1' is non-NULL and PTR is pointing anywhere inside + `string1' or just past its end. This works if PTR is NULL, which is + a good thing. */ +#define FIRST_STRING_P(ptr) \ + (size1 && string1 <= (ptr) && (ptr) <= string1 + size1) + +/* (Re)Allocate N items of type T using malloc, or fail. */ +#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t))) +#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t))) +#define RETALLOC_IF(addr, n, t) \ + if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t) +#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t))) + +#define BYTEWIDTH 8 /* In bits. */ + +#define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) + +#undef MAX +#undef MIN +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +typedef char boolean; +#define false 0 +#define true 1 + +static int re_match_2_internal PARAMS ((struct re_pattern_buffer *bufp, + const char *string1, int size1, + const char *string2, int size2, + int pos, + struct re_registers *regs, + int stop)); + +/* These are the command codes that appear in compiled regular + expressions. Some opcodes are followed by argument bytes. A + command code can specify any interpretation whatsoever for its + arguments. Zero bytes may appear in the compiled regular expression. */ + +typedef enum +{ + no_op = 0, + + /* Succeed right away--no more backtracking. */ + succeed, + + /* Followed by one byte giving n, then by n literal bytes. */ + exactn, + + /* Matches any (more or less) character. */ + anychar, + + /* Matches any one char belonging to specified set. First + following byte is number of bitmap bytes. Then come bytes + for a bitmap saying which chars are in. Bits in each byte + are ordered low-bit-first. A character is in the set if its + bit is 1. A character too large to have a bit in the map is + automatically not in the set. */ + charset, + + /* Same parameters as charset, but match any character that is + not one of those specified. */ + charset_not, + + /* Start remembering the text that is matched, for storing in a + register. Followed by one byte with the register number, in + the range 0 to one less than the pattern buffer's re_nsub + field. Then followed by one byte with the number of groups + inner to this one. (This last has to be part of the + start_memory only because we need it in the on_failure_jump + of re_match_2.) */ + start_memory, + + /* Stop remembering the text that is matched and store it in a + memory register. Followed by one byte with the register + number, in the range 0 to one less than `re_nsub' in the + pattern buffer, and one byte with the number of inner groups, + just like `start_memory'. (We need the number of inner + groups here because we don't have any easy way of finding the + corresponding start_memory when we're at a stop_memory.) */ + stop_memory, + + /* Match a duplicate of something remembered. Followed by one + byte containing the register number. */ + duplicate, + + /* Fail unless at beginning of line. */ + begline, + + /* Fail unless at end of line. */ + endline, + + /* Succeeds if at beginning of buffer (if emacs) or at beginning + of string to be matched (if not). */ + begbuf, + + /* Analogously, for end of buffer/string. */ + endbuf, + + /* Followed by two byte relative address to which to jump. */ + jump, + + /* Same as jump, but marks the end of an alternative. */ + jump_past_alt, + + /* Followed by two-byte relative address of place to resume at + in case of failure. */ + on_failure_jump, + + /* Like on_failure_jump, but pushes a placeholder instead of the + current string position when executed. */ + on_failure_keep_string_jump, + + /* Throw away latest failure point and then jump to following + two-byte relative address. */ + pop_failure_jump, + + /* Change to pop_failure_jump if know won't have to backtrack to + match; otherwise change to jump. This is used to jump + back to the beginning of a repeat. If what follows this jump + clearly won't match what the repeat does, such that we can be + sure that there is no use backtracking out of repetitions + already matched, then we change it to a pop_failure_jump. + Followed by two-byte address. */ + maybe_pop_jump, + + /* Jump to following two-byte address, and push a dummy failure + point. This failure point will be thrown away if an attempt + is made to use it for a failure. A `+' construct makes this + before the first repeat. Also used as an intermediary kind + of jump when compiling an alternative. */ + dummy_failure_jump, + + /* Push a dummy failure point and continue. Used at the end of + alternatives. */ + push_dummy_failure, + + /* Followed by two-byte relative address and two-byte number n. + After matching N times, jump to the address upon failure. */ + succeed_n, + + /* Followed by two-byte relative address, and two-byte number n. + Jump to the address N times, then fail. */ + jump_n, + + /* Set the following two-byte relative address to the + subsequent two-byte number. The address *includes* the two + bytes of number. */ + set_number_at, + + wordchar, /* Matches any word-constituent character. */ + notwordchar, /* Matches any char that is not a word-constituent. */ + + wordbeg, /* Succeeds if at word beginning. */ + wordend, /* Succeeds if at word end. */ + + wordbound, /* Succeeds if at a word boundary. */ + notwordbound /* Succeeds if not at a word boundary. */ + +#ifdef emacs + ,before_dot, /* Succeeds if before point. */ + at_dot, /* Succeeds if at point. */ + after_dot, /* Succeeds if after point. */ + + /* Matches any character whose syntax is specified. Followed by + a byte which contains a syntax code, e.g., Sword. */ + syntaxspec, + + /* Matches any character whose syntax is not that specified. */ + notsyntaxspec +#endif /* emacs */ +} re_opcode_t; + +/* Common operations on the compiled pattern. */ + +/* Store NUMBER in two contiguous bytes starting at DESTINATION. */ + +#define STORE_NUMBER(destination, number) \ + do { \ + (destination)[0] = (number) & 0377; \ + (destination)[1] = (number) >> 8; \ + } while (0) + +/* Same as STORE_NUMBER, except increment DESTINATION to + the byte after where the number is stored. Therefore, DESTINATION + must be an lvalue. */ + +#define STORE_NUMBER_AND_INCR(destination, number) \ + do { \ + STORE_NUMBER (destination, number); \ + (destination) += 2; \ + } while (0) + +/* Put into DESTINATION a number stored in two contiguous bytes starting + at SOURCE. */ + +#define EXTRACT_NUMBER(destination, source) \ + do { \ + (destination) = *(source) & 0377; \ + (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \ + } while (0) + +#ifdef DEBUG +static void extract_number _RE_ARGS ((int *dest, unsigned char *source)); +static void +extract_number (dest, source) + int *dest; + unsigned char *source; +{ + int temp = SIGN_EXTEND_CHAR (*(source + 1)); + *dest = *source & 0377; + *dest += temp << 8; +} + +# ifndef EXTRACT_MACROS /* To debug the macros. */ +# undef EXTRACT_NUMBER +# define EXTRACT_NUMBER(dest, src) extract_number (&dest, src) +# endif /* not EXTRACT_MACROS */ + +#endif /* DEBUG */ + +/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number. + SOURCE must be an lvalue. */ + +#define EXTRACT_NUMBER_AND_INCR(destination, source) \ + do { \ + EXTRACT_NUMBER (destination, source); \ + (source) += 2; \ + } while (0) + +#ifdef DEBUG +static void extract_number_and_incr _RE_ARGS ((int *destination, + unsigned char **source)); +static void +extract_number_and_incr (destination, source) + int *destination; + unsigned char **source; +{ + extract_number (destination, *source); + *source += 2; +} + +# ifndef EXTRACT_MACROS +# undef EXTRACT_NUMBER_AND_INCR +# define EXTRACT_NUMBER_AND_INCR(dest, src) \ + extract_number_and_incr (&dest, &src) +# endif /* not EXTRACT_MACROS */ + +#endif /* DEBUG */ + +/* If DEBUG is defined, Regex prints many voluminous messages about what + it is doing (if the variable `debug' is nonzero). If linked with the + main program in `iregex.c', you can enter patterns and strings + interactively. And if linked with the main program in `main.c' and + the other test files, you can run the already-written tests. */ + +#ifdef DEBUG + +/* We use standard I/O for debugging. */ +# include + +/* It is useful to test things that ``must'' be true when debugging. */ +# include + +static int debug; + +# define DEBUG_STATEMENT(e) e +# define DEBUG_PRINT1(x) if (debug) printf (x) +# define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2) +# define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3) +# define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4) +# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \ + if (debug) print_partial_compiled_pattern (s, e) +# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \ + if (debug) print_double_string (w, s1, sz1, s2, sz2) + + +/* Print the fastmap in human-readable form. */ + +void +print_fastmap (fastmap) + char *fastmap; +{ + unsigned was_a_range = 0; + unsigned i = 0; + + while (i < (1 << BYTEWIDTH)) + { + if (fastmap[i++]) + { + was_a_range = 0; + putchar (i - 1); + while (i < (1 << BYTEWIDTH) && fastmap[i]) + { + was_a_range = 1; + i++; + } + if (was_a_range) + { + printf ("-"); + putchar (i - 1); + } + } + } + putchar ('\n'); +} + + +/* Print a compiled pattern string in human-readable form, starting at + the START pointer into it and ending just before the pointer END. */ + +void +print_partial_compiled_pattern (start, end) + unsigned char *start; + unsigned char *end; +{ + int mcnt, mcnt2; + unsigned char *p1; + unsigned char *p = start; + unsigned char *pend = end; + + if (start == NULL) + { + printf ("(null)\n"); + return; + } + + /* Loop over pattern commands. */ + while (p < pend) + { + printf ("%d:\t", p - start); + + switch ((re_opcode_t) *p++) + { + case no_op: + printf ("/no_op"); + break; + + case exactn: + mcnt = *p++; + printf ("/exactn/%d", mcnt); + do + { + putchar ('/'); + putchar (*p++); + } + while (--mcnt); + break; + + case start_memory: + mcnt = *p++; + printf ("/start_memory/%d/%d", mcnt, *p++); + break; + + case stop_memory: + mcnt = *p++; + printf ("/stop_memory/%d/%d", mcnt, *p++); + break; + + case duplicate: + printf ("/duplicate/%d", *p++); + break; + + case anychar: + printf ("/anychar"); + break; + + case charset: + case charset_not: + { + register int c, last = -100; + register int in_range = 0; + + printf ("/charset [%s", + (re_opcode_t) *(p - 1) == charset_not ? "^" : ""); + + assert (p + *p < pend); + + for (c = 0; c < 256; c++) + if (c / 8 < *p + && (p[1 + (c/8)] & (1 << (c % 8)))) + { + /* Are we starting a range? */ + if (last + 1 == c && ! in_range) + { + putchar ('-'); + in_range = 1; + } + /* Have we broken a range? */ + else if (last + 1 != c && in_range) + { + putchar (last); + in_range = 0; + } + + if (! in_range) + putchar (c); + + last = c; + } + + if (in_range) + putchar (last); + + putchar (']'); + + p += 1 + *p; + } + break; + + case begline: + printf ("/begline"); + break; + + case endline: + printf ("/endline"); + break; + + case on_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/on_failure_jump to %d", p + mcnt - start); + break; + + case on_failure_keep_string_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/on_failure_keep_string_jump to %d", p + mcnt - start); + break; + + case dummy_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/dummy_failure_jump to %d", p + mcnt - start); + break; + + case push_dummy_failure: + printf ("/push_dummy_failure"); + break; + + case maybe_pop_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/maybe_pop_jump to %d", p + mcnt - start); + break; + + case pop_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/pop_failure_jump to %d", p + mcnt - start); + break; + + case jump_past_alt: + extract_number_and_incr (&mcnt, &p); + printf ("/jump_past_alt to %d", p + mcnt - start); + break; + + case jump: + extract_number_and_incr (&mcnt, &p); + printf ("/jump to %d", p + mcnt - start); + break; + + case succeed_n: + extract_number_and_incr (&mcnt, &p); + p1 = p + mcnt; + extract_number_and_incr (&mcnt2, &p); + printf ("/succeed_n to %d, %d times", p1 - start, mcnt2); + break; + + case jump_n: + extract_number_and_incr (&mcnt, &p); + p1 = p + mcnt; + extract_number_and_incr (&mcnt2, &p); + printf ("/jump_n to %d, %d times", p1 - start, mcnt2); + break; + + case set_number_at: + extract_number_and_incr (&mcnt, &p); + p1 = p + mcnt; + extract_number_and_incr (&mcnt2, &p); + printf ("/set_number_at location %d to %d", p1 - start, mcnt2); + break; + + case wordbound: + printf ("/wordbound"); + break; + + case notwordbound: + printf ("/notwordbound"); + break; + + case wordbeg: + printf ("/wordbeg"); + break; + + case wordend: + printf ("/wordend"); + +# ifdef emacs + case before_dot: + printf ("/before_dot"); + break; + + case at_dot: + printf ("/at_dot"); + break; + + case after_dot: + printf ("/after_dot"); + break; + + case syntaxspec: + printf ("/syntaxspec"); + mcnt = *p++; + printf ("/%d", mcnt); + break; + + case notsyntaxspec: + printf ("/notsyntaxspec"); + mcnt = *p++; + printf ("/%d", mcnt); + break; +# endif /* emacs */ + + case wordchar: + printf ("/wordchar"); + break; + + case notwordchar: + printf ("/notwordchar"); + break; + + case begbuf: + printf ("/begbuf"); + break; + + case endbuf: + printf ("/endbuf"); + break; + + default: + printf ("?%d", *(p-1)); + } + + putchar ('\n'); + } + + printf ("%d:\tend of pattern.\n", p - start); +} + + +void +print_compiled_pattern (bufp) + struct re_pattern_buffer *bufp; +{ + unsigned char *buffer = bufp->buffer; + + print_partial_compiled_pattern (buffer, buffer + bufp->used); + printf ("%ld bytes used/%ld bytes allocated.\n", + bufp->used, bufp->allocated); + + if (bufp->fastmap_accurate && bufp->fastmap) + { + printf ("fastmap: "); + print_fastmap (bufp->fastmap); + } + + printf ("re_nsub: %d\t", bufp->re_nsub); + printf ("regs_alloc: %d\t", bufp->regs_allocated); + printf ("can_be_null: %d\t", bufp->can_be_null); + printf ("newline_anchor: %d\n", bufp->newline_anchor); + printf ("no_sub: %d\t", bufp->no_sub); + printf ("not_bol: %d\t", bufp->not_bol); + printf ("not_eol: %d\t", bufp->not_eol); + printf ("syntax: %lx\n", bufp->syntax); + /* Perhaps we should print the translate table? */ +} + + +void +print_double_string (where, string1, size1, string2, size2) + const char *where; + const char *string1; + const char *string2; + int size1; + int size2; +{ + int this_char; + + if (where == NULL) + printf ("(null)"); + else + { + if (FIRST_STRING_P (where)) + { + for (this_char = where - string1; this_char < size1; this_char++) + putchar (string1[this_char]); + + where = string2; + } + + for (this_char = where - string2; this_char < size2; this_char++) + putchar (string2[this_char]); + } +} + +void +printchar (c) + int c; +{ + putc (c, stderr); +} + +#else /* not DEBUG */ + +# undef assert +# define assert(e) + +# define DEBUG_STATEMENT(e) +# define DEBUG_PRINT1(x) +# define DEBUG_PRINT2(x1, x2) +# define DEBUG_PRINT3(x1, x2, x3) +# define DEBUG_PRINT4(x1, x2, x3, x4) +# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) +# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) + +#endif /* not DEBUG */ + +/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can + also be assigned to arbitrarily: each pattern buffer stores its own + syntax, so it can be changed between regex compilations. */ +/* This has no initializer because initialized variables in Emacs + become read-only after dumping. */ +reg_syntax_t re_syntax_options; + + +/* Specify the precise syntax of regexps for compilation. This provides + for compatibility for various utilities which historically have + different, incompatible syntaxes. + + The argument SYNTAX is a bit mask comprised of the various bits + defined in regex.h. We return the old syntax. */ + +reg_syntax_t +re_set_syntax (syntax) + reg_syntax_t syntax; +{ + reg_syntax_t ret = re_syntax_options; + + re_syntax_options = syntax; +#ifdef DEBUG + if (syntax & RE_DEBUG) + debug = 1; + else if (debug) /* was on but now is not */ + debug = 0; +#endif /* DEBUG */ + return ret; +} +#ifdef _LIBC +weak_alias (__re_set_syntax, re_set_syntax) +#endif + +/* This table gives an error message for each of the error codes listed + in regex.h. Obviously the order here has to be same as there. + POSIX doesn't require that we do anything for REG_NOERROR, + but why not be nice? */ + +static const char re_error_msgid[] = + { +#define REG_NOERROR_IDX 0 + gettext_noop ("Success") /* REG_NOERROR */ + "\0" +#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success") + gettext_noop ("No match") /* REG_NOMATCH */ + "\0" +#define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match") + gettext_noop ("Invalid regular expression") /* REG_BADPAT */ + "\0" +#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression") + gettext_noop ("Invalid collation character"), /* REG_ECOLLATE */ + "\0" +#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character") + gettext_noop ("Invalid character class name") /* REG_ECTYPE */ + "\0" +#define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name") + gettext_noop ("Trailing backslash") /* REG_EESCAPE */ + "\0" +#define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash") + gettext_noop ("Invalid back reference") /* REG_ESUBREG */ + "\0" +#define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference") + gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */ + "\0" +#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^") + gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */ + "\0" +#define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(") + gettext_noop ("Unmatched \\{") /* REG_EBRACE */ + "\0" +#define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{") + gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */ + "\0" +#define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}") + gettext_noop ("Invalid range end") /* REG_ERANGE */ + "\0" +#define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end") + gettext_noop ("Memory exhausted") /* REG_ESPACE */ + "\0" +#define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted") + gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */ + "\0" +#define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression") + gettext_noop ("Premature end of regular expression") /* REG_EEND */ + "\0" +#define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression") + gettext_noop ("Regular expression too big") /* REG_ESIZE */ + "\0" +#define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big") + gettext_noop ("Unmatched ) or \\)"), /* REG_ERPAREN */ + }; + +static const size_t re_error_msgid_idx[] = + { + REG_NOERROR_IDX, + REG_NOMATCH_IDX, + REG_BADPAT_IDX, + REG_ECOLLATE_IDX, + REG_ECTYPE_IDX, + REG_EESCAPE_IDX, + REG_ESUBREG_IDX, + REG_EBRACK_IDX, + REG_EPAREN_IDX, + REG_EBRACE_IDX, + REG_BADBR_IDX, + REG_ERANGE_IDX, + REG_ESPACE_IDX, + REG_BADRPT_IDX, + REG_EEND_IDX, + REG_ESIZE_IDX, + REG_ERPAREN_IDX + }; + +/* Avoiding alloca during matching, to placate r_alloc. */ + +/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the + searching and matching functions should not call alloca. On some + systems, alloca is implemented in terms of malloc, and if we're + using the relocating allocator routines, then malloc could cause a + relocation, which might (if the strings being searched are in the + ralloc heap) shift the data out from underneath the regexp + routines. + + Here's another reason to avoid allocation: Emacs + processes input from X in a signal handler; processing X input may + call malloc; if input arrives while a matching routine is calling + malloc, then we're scrod. But Emacs can't just block input while + calling matching routines; then we don't notice interrupts when + they come in. So, Emacs blocks input around all regexp calls + except the matching calls, which it leaves unprotected, in the + faith that they will not malloc. */ + +/* Normally, this is fine. */ +#define MATCH_MAY_ALLOCATE + +/* When using GNU C, we are not REALLY using the C alloca, no matter + what config.h may say. So don't take precautions for it. */ +#ifdef __GNUC__ +# undef C_ALLOCA +#endif + +/* The match routines may not allocate if (1) they would do it with malloc + and (2) it's not safe for them to use malloc. + Note that if REL_ALLOC is defined, matching would not use malloc for the + failure stack, but we would still use it for the register vectors; + so REL_ALLOC should not affect this. */ +#if (defined C_ALLOCA || defined REGEX_MALLOC) && defined emacs +# undef MATCH_MAY_ALLOCATE +#endif + + +/* Failure stack declarations and macros; both re_compile_fastmap and + re_match_2 use a failure stack. These have to be macros because of + REGEX_ALLOCATE_STACK. */ + + +/* Number of failure points for which to initially allocate space + when matching. If this number is exceeded, we allocate more + space, so it is not a hard limit. */ +#ifndef INIT_FAILURE_ALLOC +# define INIT_FAILURE_ALLOC 5 +#endif + +/* Roughly the maximum number of failure points on the stack. Would be + exactly that if always used MAX_FAILURE_ITEMS items each time we failed. + This is a variable only so users of regex can assign to it; we never + change it ourselves. */ + +#ifdef INT_IS_16BIT + +# if defined MATCH_MAY_ALLOCATE +/* 4400 was enough to cause a crash on Alpha OSF/1, + whose default stack limit is 2mb. */ +long int re_max_failures = 4000; +# else +long int re_max_failures = 2000; +# endif + +union fail_stack_elt +{ + unsigned char *pointer; + long int integer; +}; + +typedef union fail_stack_elt fail_stack_elt_t; + +typedef struct +{ + fail_stack_elt_t *stack; + unsigned long int size; + unsigned long int avail; /* Offset of next open position. */ +} fail_stack_type; + +#else /* not INT_IS_16BIT */ + +# if defined MATCH_MAY_ALLOCATE +/* 4400 was enough to cause a crash on Alpha OSF/1, + whose default stack limit is 2mb. */ +int re_max_failures = 20000; +# else +int re_max_failures = 2000; +# endif + +union fail_stack_elt +{ + unsigned char *pointer; + int integer; +}; + +typedef union fail_stack_elt fail_stack_elt_t; + +typedef struct +{ + fail_stack_elt_t *stack; + unsigned size; + unsigned avail; /* Offset of next open position. */ +} fail_stack_type; + +#endif /* INT_IS_16BIT */ + +#define FAIL_STACK_EMPTY() (fail_stack.avail == 0) +#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0) +#define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size) + + +/* Define macros to initialize and free the failure stack. + Do `return -2' if the alloc fails. */ + +#ifdef MATCH_MAY_ALLOCATE +# define INIT_FAIL_STACK() \ + do { \ + fail_stack.stack = (fail_stack_elt_t *) \ + REGEX_ALLOCATE_STACK (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \ + \ + if (fail_stack.stack == NULL) \ + return -2; \ + \ + fail_stack.size = INIT_FAILURE_ALLOC; \ + fail_stack.avail = 0; \ + } while (0) + +# define RESET_FAIL_STACK() REGEX_FREE_STACK (fail_stack.stack) +#else +# define INIT_FAIL_STACK() \ + do { \ + fail_stack.avail = 0; \ + } while (0) + +# define RESET_FAIL_STACK() +#endif + + +/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items. + + Return 1 if succeeds, and 0 if either ran out of memory + allocating space for it or it was already too large. + + REGEX_REALLOCATE_STACK requires `destination' be declared. */ + +#define DOUBLE_FAIL_STACK(fail_stack) \ + ((fail_stack).size > (unsigned) (re_max_failures * MAX_FAILURE_ITEMS) \ + ? 0 \ + : ((fail_stack).stack = (fail_stack_elt_t *) \ + REGEX_REALLOCATE_STACK ((fail_stack).stack, \ + (fail_stack).size * sizeof (fail_stack_elt_t), \ + ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \ + \ + (fail_stack).stack == NULL \ + ? 0 \ + : ((fail_stack).size <<= 1, \ + 1))) + + +/* Push pointer POINTER on FAIL_STACK. + Return 1 if was able to do so and 0 if ran out of memory allocating + space to do so. */ +#define PUSH_PATTERN_OP(POINTER, FAIL_STACK) \ + ((FAIL_STACK_FULL () \ + && !DOUBLE_FAIL_STACK (FAIL_STACK)) \ + ? 0 \ + : ((FAIL_STACK).stack[(FAIL_STACK).avail++].pointer = POINTER, \ + 1)) + +/* Push a pointer value onto the failure stack. + Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +#define PUSH_FAILURE_POINTER(item) \ + fail_stack.stack[fail_stack.avail++].pointer = (unsigned char *) (item) + +/* This pushes an integer-valued item onto the failure stack. + Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +#define PUSH_FAILURE_INT(item) \ + fail_stack.stack[fail_stack.avail++].integer = (item) + +/* Push a fail_stack_elt_t value onto the failure stack. + Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +#define PUSH_FAILURE_ELT(item) \ + fail_stack.stack[fail_stack.avail++] = (item) + +/* These three POP... operations complement the three PUSH... operations. + All assume that `fail_stack' is nonempty. */ +#define POP_FAILURE_POINTER() fail_stack.stack[--fail_stack.avail].pointer +#define POP_FAILURE_INT() fail_stack.stack[--fail_stack.avail].integer +#define POP_FAILURE_ELT() fail_stack.stack[--fail_stack.avail] + +/* Used to omit pushing failure point id's when we're not debugging. */ +#ifdef DEBUG +# define DEBUG_PUSH PUSH_FAILURE_INT +# define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_INT () +#else +# define DEBUG_PUSH(item) +# define DEBUG_POP(item_addr) +#endif + + +/* Push the information about the state we will need + if we ever fail back to it. + + Requires variables fail_stack, regstart, regend, reg_info, and + num_regs_pushed be declared. DOUBLE_FAIL_STACK requires `destination' + be declared. + + Does `return FAILURE_CODE' if runs out of memory. */ + +#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \ + do { \ + char *destination; \ + /* Must be int, so when we don't save any registers, the arithmetic \ + of 0 + -1 isn't done as unsigned. */ \ + /* Can't be int, since there is not a shred of a guarantee that int \ + is wide enough to hold a value of something to which pointer can \ + be assigned */ \ + active_reg_t this_reg; \ + \ + DEBUG_STATEMENT (failure_id++); \ + DEBUG_STATEMENT (nfailure_points_pushed++); \ + DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \ + DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\ + DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\ + \ + DEBUG_PRINT2 (" slots needed: %ld\n", NUM_FAILURE_ITEMS); \ + DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \ + \ + /* Ensure we have enough space allocated for what we will push. */ \ + while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \ + { \ + if (!DOUBLE_FAIL_STACK (fail_stack)) \ + return failure_code; \ + \ + DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \ + (fail_stack).size); \ + DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\ + } \ + \ + /* Push the info, starting with the registers. */ \ + DEBUG_PRINT1 ("\n"); \ + \ + if (1) \ + for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \ + this_reg++) \ + { \ + DEBUG_PRINT2 (" Pushing reg: %lu\n", this_reg); \ + DEBUG_STATEMENT (num_regs_pushed++); \ + \ + DEBUG_PRINT2 (" start: %p\n", regstart[this_reg]); \ + PUSH_FAILURE_POINTER (regstart[this_reg]); \ + \ + DEBUG_PRINT2 (" end: %p\n", regend[this_reg]); \ + PUSH_FAILURE_POINTER (regend[this_reg]); \ + \ + DEBUG_PRINT2 (" info: %p\n ", \ + reg_info[this_reg].word.pointer); \ + DEBUG_PRINT2 (" match_null=%d", \ + REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \ + DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \ + DEBUG_PRINT2 (" matched_something=%d", \ + MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT2 (" ever_matched=%d", \ + EVER_MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT1 ("\n"); \ + PUSH_FAILURE_ELT (reg_info[this_reg].word); \ + } \ + \ + DEBUG_PRINT2 (" Pushing low active reg: %ld\n", lowest_active_reg);\ + PUSH_FAILURE_INT (lowest_active_reg); \ + \ + DEBUG_PRINT2 (" Pushing high active reg: %ld\n", highest_active_reg);\ + PUSH_FAILURE_INT (highest_active_reg); \ + \ + DEBUG_PRINT2 (" Pushing pattern %p:\n", pattern_place); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \ + PUSH_FAILURE_POINTER (pattern_place); \ + \ + DEBUG_PRINT2 (" Pushing string %p: `", string_place); \ + DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \ + size2); \ + DEBUG_PRINT1 ("'\n"); \ + PUSH_FAILURE_POINTER (string_place); \ + \ + DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \ + DEBUG_PUSH (failure_id); \ + } while (0) + +/* This is the number of items that are pushed and popped on the stack + for each register. */ +#define NUM_REG_ITEMS 3 + +/* Individual items aside from the registers. */ +#ifdef DEBUG +# define NUM_NONREG_ITEMS 5 /* Includes failure point id. */ +#else +# define NUM_NONREG_ITEMS 4 +#endif + +/* We push at most this many items on the stack. */ +/* We used to use (num_regs - 1), which is the number of registers + this regexp will save; but that was changed to 5 + to avoid stack overflow for a regexp with lots of parens. */ +#define MAX_FAILURE_ITEMS (5 * NUM_REG_ITEMS + NUM_NONREG_ITEMS) + +/* We actually push this many items. */ +#define NUM_FAILURE_ITEMS \ + (((0 \ + ? 0 : highest_active_reg - lowest_active_reg + 1) \ + * NUM_REG_ITEMS) \ + + NUM_NONREG_ITEMS) + +/* How many items can still be added to the stack without overflowing it. */ +#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail) + + +/* Pops what PUSH_FAIL_STACK pushes. + + We restore into the parameters, all of which should be lvalues: + STR -- the saved data position. + PAT -- the saved pattern position. + LOW_REG, HIGH_REG -- the highest and lowest active registers. + REGSTART, REGEND -- arrays of string positions. + REG_INFO -- array of information about each subexpression. + + Also assumes the variables `fail_stack' and (if debugging), `bufp', + `pend', `string1', `size1', `string2', and `size2'. */ + +#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\ +{ \ + DEBUG_STATEMENT (unsigned failure_id;) \ + active_reg_t this_reg; \ + const unsigned char *string_temp; \ + \ + assert (!FAIL_STACK_EMPTY ()); \ + \ + /* Remove failure points and point to how many regs pushed. */ \ + DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \ + DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \ + DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \ + \ + assert (fail_stack.avail >= NUM_NONREG_ITEMS); \ + \ + DEBUG_POP (&failure_id); \ + DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \ + \ + /* If the saved string location is NULL, it came from an \ + on_failure_keep_string_jump opcode, and we want to throw away the \ + saved NULL, thus retaining our current position in the string. */ \ + string_temp = POP_FAILURE_POINTER (); \ + if (string_temp != NULL) \ + str = (const char *) string_temp; \ + \ + DEBUG_PRINT2 (" Popping string %p: `", str); \ + DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \ + DEBUG_PRINT1 ("'\n"); \ + \ + pat = (unsigned char *) POP_FAILURE_POINTER (); \ + DEBUG_PRINT2 (" Popping pattern %p:\n", pat); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \ + \ + /* Restore register info. */ \ + high_reg = (active_reg_t) POP_FAILURE_INT (); \ + DEBUG_PRINT2 (" Popping high active reg: %ld\n", high_reg); \ + \ + low_reg = (active_reg_t) POP_FAILURE_INT (); \ + DEBUG_PRINT2 (" Popping low active reg: %ld\n", low_reg); \ + \ + if (1) \ + for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \ + { \ + DEBUG_PRINT2 (" Popping reg: %ld\n", this_reg); \ + \ + reg_info[this_reg].word = POP_FAILURE_ELT (); \ + DEBUG_PRINT2 (" info: %p\n", \ + reg_info[this_reg].word.pointer); \ + \ + regend[this_reg] = (const char *) POP_FAILURE_POINTER (); \ + DEBUG_PRINT2 (" end: %p\n", regend[this_reg]); \ + \ + regstart[this_reg] = (const char *) POP_FAILURE_POINTER (); \ + DEBUG_PRINT2 (" start: %p\n", regstart[this_reg]); \ + } \ + else \ + { \ + for (this_reg = highest_active_reg; this_reg > high_reg; this_reg--) \ + { \ + reg_info[this_reg].word.integer = 0; \ + regend[this_reg] = 0; \ + regstart[this_reg] = 0; \ + } \ + highest_active_reg = high_reg; \ + } \ + \ + set_regs_matched_done = 0; \ + DEBUG_STATEMENT (nfailure_points_popped++); \ +} /* POP_FAILURE_POINT */ + + + +/* Structure for per-register (a.k.a. per-group) information. + Other register information, such as the + starting and ending positions (which are addresses), and the list of + inner groups (which is a bits list) are maintained in separate + variables. + + We are making a (strictly speaking) nonportable assumption here: that + the compiler will pack our bit fields into something that fits into + the type of `word', i.e., is something that fits into one item on the + failure stack. */ + + +/* Declarations and macros for re_match_2. */ + +typedef union +{ + fail_stack_elt_t word; + struct + { + /* This field is one if this group can match the empty string, + zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */ +#define MATCH_NULL_UNSET_VALUE 3 + unsigned match_null_string_p : 2; + unsigned is_active : 1; + unsigned matched_something : 1; + unsigned ever_matched_something : 1; + } bits; +} register_info_type; + +#define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p) +#define IS_ACTIVE(R) ((R).bits.is_active) +#define MATCHED_SOMETHING(R) ((R).bits.matched_something) +#define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something) + + +/* Call this when have matched a real character; it sets `matched' flags + for the subexpressions which we are currently inside. Also records + that those subexprs have matched. */ +#define SET_REGS_MATCHED() \ + do \ + { \ + if (!set_regs_matched_done) \ + { \ + active_reg_t r; \ + set_regs_matched_done = 1; \ + for (r = lowest_active_reg; r <= highest_active_reg; r++) \ + { \ + MATCHED_SOMETHING (reg_info[r]) \ + = EVER_MATCHED_SOMETHING (reg_info[r]) \ + = 1; \ + } \ + } \ + } \ + while (0) + +/* Registers are set to a sentinel when they haven't yet matched. */ +static char reg_unset_dummy; +#define REG_UNSET_VALUE (®_unset_dummy) +#define REG_UNSET(e) ((e) == REG_UNSET_VALUE) + +/* Subroutine declarations and macros for regex_compile. */ + +static reg_errcode_t regex_compile _RE_ARGS ((const char *pattern, size_t size, + reg_syntax_t syntax, + struct re_pattern_buffer *bufp)); +static void store_op1 _RE_ARGS ((re_opcode_t op, unsigned char *loc, int arg)); +static void store_op2 _RE_ARGS ((re_opcode_t op, unsigned char *loc, + int arg1, int arg2)); +static void insert_op1 _RE_ARGS ((re_opcode_t op, unsigned char *loc, + int arg, unsigned char *end)); +static void insert_op2 _RE_ARGS ((re_opcode_t op, unsigned char *loc, + int arg1, int arg2, unsigned char *end)); +static boolean at_begline_loc_p _RE_ARGS ((const char *pattern, const char *p, + reg_syntax_t syntax)); +static boolean at_endline_loc_p _RE_ARGS ((const char *p, const char *pend, + reg_syntax_t syntax)); +static reg_errcode_t compile_range _RE_ARGS ((const char **p_ptr, + const char *pend, + char *translate, + reg_syntax_t syntax, + unsigned char *b)); + +/* Fetch the next character in the uncompiled pattern---translating it + if necessary. Also cast from a signed character in the constant + string passed to us by the user to an unsigned char that we can use + as an array index (in, e.g., `translate'). */ +#ifndef PATFETCH +# define PATFETCH(c) \ + do {if (p == pend) return REG_EEND; \ + c = (unsigned char) *p++; \ + if (translate) c = (unsigned char) translate[c]; \ + } while (0) +#endif + +/* Fetch the next character in the uncompiled pattern, with no + translation. */ +#define PATFETCH_RAW(c) \ + do {if (p == pend) return REG_EEND; \ + c = (unsigned char) *p++; \ + } while (0) + +/* Go backwards one character in the pattern. */ +#define PATUNFETCH p-- + + +/* If `translate' is non-null, return translate[D], else just D. We + cast the subscript to translate because some data is declared as + `char *', to avoid warnings when a string constant is passed. But + when we use a character as a subscript we must make it unsigned. */ +#ifndef TRANSLATE +# define TRANSLATE(d) \ + (translate ? (char) translate[(unsigned char) (d)] : (d)) +#endif + + +/* Macros for outputting the compiled pattern into `buffer'. */ + +/* If the buffer isn't allocated when it comes in, use this. */ +#define INIT_BUF_SIZE 32 + +/* Make sure we have at least N more bytes of space in buffer. */ +#define GET_BUFFER_SPACE(n) \ + while ((unsigned long) (b - bufp->buffer + (n)) > bufp->allocated) \ + EXTEND_BUFFER () + +/* Make sure we have one more byte of buffer space and then add C to it. */ +#define BUF_PUSH(c) \ + do { \ + GET_BUFFER_SPACE (1); \ + *b++ = (unsigned char) (c); \ + } while (0) + + +/* Ensure we have two more bytes of buffer space and then append C1 and C2. */ +#define BUF_PUSH_2(c1, c2) \ + do { \ + GET_BUFFER_SPACE (2); \ + *b++ = (unsigned char) (c1); \ + *b++ = (unsigned char) (c2); \ + } while (0) + + +/* As with BUF_PUSH_2, except for three bytes. */ +#define BUF_PUSH_3(c1, c2, c3) \ + do { \ + GET_BUFFER_SPACE (3); \ + *b++ = (unsigned char) (c1); \ + *b++ = (unsigned char) (c2); \ + *b++ = (unsigned char) (c3); \ + } while (0) + + +/* Store a jump with opcode OP at LOC to location TO. We store a + relative address offset by the three bytes the jump itself occupies. */ +#define STORE_JUMP(op, loc, to) \ + store_op1 (op, loc, (int) ((to) - (loc) - 3)) + +/* Likewise, for a two-argument jump. */ +#define STORE_JUMP2(op, loc, to, arg) \ + store_op2 (op, loc, (int) ((to) - (loc) - 3), arg) + +/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */ +#define INSERT_JUMP(op, loc, to) \ + insert_op1 (op, loc, (int) ((to) - (loc) - 3), b) + +/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */ +#define INSERT_JUMP2(op, loc, to, arg) \ + insert_op2 (op, loc, (int) ((to) - (loc) - 3), arg, b) + + +/* This is not an arbitrary limit: the arguments which represent offsets + into the pattern are two bytes long. So if 2^16 bytes turns out to + be too small, many things would have to change. */ +/* Any other compiler which, like MSC, has allocation limit below 2^16 + bytes will have to use approach similar to what was done below for + MSC and drop MAX_BUF_SIZE a bit. Otherwise you may end up + reallocating to 0 bytes. Such thing is not going to work too well. + You have been warned!! */ +#if defined _MSC_VER && !defined WIN32 +/* Microsoft C 16-bit versions limit malloc to approx 65512 bytes. + The REALLOC define eliminates a flurry of conversion warnings, + but is not required. */ +# define MAX_BUF_SIZE 65500L +# define REALLOC(p,s) realloc ((p), (size_t) (s)) +#else +# define MAX_BUF_SIZE (1L << 16) +# define REALLOC(p,s) realloc ((p), (s)) +#endif + +/* Extend the buffer by twice its current size via realloc and + reset the pointers that pointed into the old block to point to the + correct places in the new one. If extending the buffer results in it + being larger than MAX_BUF_SIZE, then flag memory exhausted. */ +#define EXTEND_BUFFER() \ + do { \ + unsigned char *old_buffer = bufp->buffer; \ + if (bufp->allocated == MAX_BUF_SIZE) \ + return REG_ESIZE; \ + bufp->allocated <<= 1; \ + if (bufp->allocated > MAX_BUF_SIZE) \ + bufp->allocated = MAX_BUF_SIZE; \ + bufp->buffer = (unsigned char *) REALLOC (bufp->buffer, bufp->allocated);\ + if (bufp->buffer == NULL) \ + return REG_ESPACE; \ + /* If the buffer moved, move all the pointers into it. */ \ + if (old_buffer != bufp->buffer) \ + { \ + b = (b - old_buffer) + bufp->buffer; \ + begalt = (begalt - old_buffer) + bufp->buffer; \ + if (fixup_alt_jump) \ + fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\ + if (laststart) \ + laststart = (laststart - old_buffer) + bufp->buffer; \ + if (pending_exact) \ + pending_exact = (pending_exact - old_buffer) + bufp->buffer; \ + } \ + } while (0) + + +/* Since we have one byte reserved for the register number argument to + {start,stop}_memory, the maximum number of groups we can report + things about is what fits in that byte. */ +#define MAX_REGNUM 255 + +/* But patterns can have more than `MAX_REGNUM' registers. We just + ignore the excess. */ +typedef unsigned regnum_t; + + +/* Macros for the compile stack. */ + +/* Since offsets can go either forwards or backwards, this type needs to + be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */ +/* int may be not enough when sizeof(int) == 2. */ +typedef long pattern_offset_t; + +typedef struct +{ + pattern_offset_t begalt_offset; + pattern_offset_t fixup_alt_jump; + pattern_offset_t inner_group_offset; + pattern_offset_t laststart_offset; + regnum_t regnum; +} compile_stack_elt_t; + + +typedef struct +{ + compile_stack_elt_t *stack; + unsigned size; + unsigned avail; /* Offset of next open position. */ +} compile_stack_type; + + +#define INIT_COMPILE_STACK_SIZE 32 + +#define COMPILE_STACK_EMPTY (compile_stack.avail == 0) +#define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size) + +/* The next available element. */ +#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail]) + + +/* Set the bit for character C in a list. */ +#define SET_LIST_BIT(c) \ + (b[((unsigned char) (c)) / BYTEWIDTH] \ + |= 1 << (((unsigned char) c) % BYTEWIDTH)) + + +/* Get the next unsigned number in the uncompiled pattern. */ +#define GET_UNSIGNED_NUMBER(num) \ + { if (p != pend) \ + { \ + PATFETCH (c); \ + while (ISDIGIT (c)) \ + { \ + if (num < 0) \ + num = 0; \ + num = num * 10 + c - '0'; \ + if (p == pend) \ + break; \ + PATFETCH (c); \ + } \ + } \ + } + +#if defined _LIBC || WIDE_CHAR_SUPPORT +/* The GNU C library provides support for user-defined character classes + and the functions from ISO C amendement 1. */ +# ifdef CHARCLASS_NAME_MAX +# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX +# else +/* This shouldn't happen but some implementation might still have this + problem. Use a reasonable default value. */ +# define CHAR_CLASS_MAX_LENGTH 256 +# endif + +# ifdef _LIBC +# define IS_CHAR_CLASS(string) __wctype (string) +# else +# define IS_CHAR_CLASS(string) wctype (string) +# endif +#else +# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ + +# define IS_CHAR_CLASS(string) \ + (STREQ (string, "alpha") || STREQ (string, "upper") \ + || STREQ (string, "lower") || STREQ (string, "digit") \ + || STREQ (string, "alnum") || STREQ (string, "xdigit") \ + || STREQ (string, "space") || STREQ (string, "print") \ + || STREQ (string, "punct") || STREQ (string, "graph") \ + || STREQ (string, "cntrl") || STREQ (string, "blank")) +#endif + +#ifndef MATCH_MAY_ALLOCATE + +/* If we cannot allocate large objects within re_match_2_internal, + we make the fail stack and register vectors global. + The fail stack, we grow to the maximum size when a regexp + is compiled. + The register vectors, we adjust in size each time we + compile a regexp, according to the number of registers it needs. */ + +static fail_stack_type fail_stack; + +/* Size with which the following vectors are currently allocated. + That is so we can make them bigger as needed, + but never make them smaller. */ +static int regs_allocated_size; + +static const char ** regstart, ** regend; +static const char ** old_regstart, ** old_regend; +static const char **best_regstart, **best_regend; +static register_info_type *reg_info; +static const char **reg_dummy; +static register_info_type *reg_info_dummy; + +/* Make the register vectors big enough for NUM_REGS registers, + but don't make them smaller. */ + +static +regex_grow_registers (num_regs) + int num_regs; +{ + if (num_regs > regs_allocated_size) + { + RETALLOC_IF (regstart, num_regs, const char *); + RETALLOC_IF (regend, num_regs, const char *); + RETALLOC_IF (old_regstart, num_regs, const char *); + RETALLOC_IF (old_regend, num_regs, const char *); + RETALLOC_IF (best_regstart, num_regs, const char *); + RETALLOC_IF (best_regend, num_regs, const char *); + RETALLOC_IF (reg_info, num_regs, register_info_type); + RETALLOC_IF (reg_dummy, num_regs, const char *); + RETALLOC_IF (reg_info_dummy, num_regs, register_info_type); + + regs_allocated_size = num_regs; + } +} + +#endif /* not MATCH_MAY_ALLOCATE */ + +static boolean group_in_compile_stack _RE_ARGS ((compile_stack_type + compile_stack, + regnum_t regnum)); + +/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX. + Returns one of error codes defined in `regex.h', or zero for success. + + Assumes the `allocated' (and perhaps `buffer') and `translate' + fields are set in BUFP on entry. + + If it succeeds, results are put in BUFP (if it returns an error, the + contents of BUFP are undefined): + `buffer' is the compiled pattern; + `syntax' is set to SYNTAX; + `used' is set to the length of the compiled pattern; + `fastmap_accurate' is zero; + `re_nsub' is the number of subexpressions in PATTERN; + `not_bol' and `not_eol' are zero; + + The `fastmap' and `newline_anchor' fields are neither + examined nor set. */ + +/* Return, freeing storage we allocated. */ +#define FREE_STACK_RETURN(value) \ + return (free (compile_stack.stack), value) + +static reg_errcode_t +regex_compile (pattern, size, syntax, bufp) + const char *pattern; + size_t size; + reg_syntax_t syntax; + struct re_pattern_buffer *bufp; +{ + /* We fetch characters from PATTERN here. Even though PATTERN is + `char *' (i.e., signed), we declare these variables as unsigned, so + they can be reliably used as array indices. */ + register unsigned char c, c1; + + /* A random temporary spot in PATTERN. */ + const char *p1; + + /* Points to the end of the buffer, where we should append. */ + register unsigned char *b; + + /* Keeps track of unclosed groups. */ + compile_stack_type compile_stack; + + /* Points to the current (ending) position in the pattern. */ + const char *p = pattern; + const char *pend = pattern + size; + + /* How to translate the characters in the pattern. */ + RE_TRANSLATE_TYPE translate = bufp->translate; + + /* Address of the count-byte of the most recently inserted `exactn' + command. This makes it possible to tell if a new exact-match + character can be added to that command or if the character requires + a new `exactn' command. */ + unsigned char *pending_exact = 0; + + /* Address of start of the most recently finished expression. + This tells, e.g., postfix * where to find the start of its + operand. Reset at the beginning of groups and alternatives. */ + unsigned char *laststart = 0; + + /* Address of beginning of regexp, or inside of last group. */ + unsigned char *begalt; + + /* Place in the uncompiled pattern (i.e., the {) to + which to go back if the interval is invalid. */ + const char *beg_interval; + + /* Address of the place where a forward jump should go to the end of + the containing expression. Each alternative of an `or' -- except the + last -- ends with a forward jump of this sort. */ + unsigned char *fixup_alt_jump = 0; + + /* Counts open-groups as they are encountered. Remembered for the + matching close-group on the compile stack, so the same register + number is put in the stop_memory as the start_memory. */ + regnum_t regnum = 0; + +#ifdef DEBUG + DEBUG_PRINT1 ("\nCompiling pattern: "); + if (debug) + { + unsigned debug_count; + + for (debug_count = 0; debug_count < size; debug_count++) + putchar (pattern[debug_count]); + putchar ('\n'); + } +#endif /* DEBUG */ + + /* Initialize the compile stack. */ + compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t); + if (compile_stack.stack == NULL) + return REG_ESPACE; + + compile_stack.size = INIT_COMPILE_STACK_SIZE; + compile_stack.avail = 0; + + /* Initialize the pattern buffer. */ + bufp->syntax = syntax; + bufp->fastmap_accurate = 0; + bufp->not_bol = bufp->not_eol = 0; + + /* Set `used' to zero, so that if we return an error, the pattern + printer (for debugging) will think there's no pattern. We reset it + at the end. */ + bufp->used = 0; + + /* Always count groups, whether or not bufp->no_sub is set. */ + bufp->re_nsub = 0; + +#if !defined emacs && !defined SYNTAX_TABLE + /* Initialize the syntax table. */ + init_syntax_once (); +#endif + + if (bufp->allocated == 0) + { + if (bufp->buffer) + { /* If zero allocated, but buffer is non-null, try to realloc + enough space. This loses if buffer's address is bogus, but + that is the user's responsibility. */ + RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char); + } + else + { /* Caller did not allocate a buffer. Do it for them. */ + bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char); + } + if (!bufp->buffer) FREE_STACK_RETURN (REG_ESPACE); + + bufp->allocated = INIT_BUF_SIZE; + } + + begalt = b = bufp->buffer; + + /* Loop through the uncompiled pattern until we're at the end. */ + while (p != pend) + { + PATFETCH (c); + + switch (c) + { + case '^': + { + if ( /* If at start of pattern, it's an operator. */ + p == pattern + 1 + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's come before. */ + || at_begline_loc_p (pattern, p, syntax)) + BUF_PUSH (begline); + else + goto normal_char; + } + break; + + + case '$': + { + if ( /* If at end of pattern, it's an operator. */ + p == pend + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's next. */ + || at_endline_loc_p (p, pend, syntax)) + BUF_PUSH (endline); + else + goto normal_char; + } + break; + + + case '+': + case '?': + if ((syntax & RE_BK_PLUS_QM) + || (syntax & RE_LIMITED_OPS)) + goto normal_char; + handle_plus: + case '*': + /* If there is no previous pattern... */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + FREE_STACK_RETURN (REG_BADRPT); + else if (!(syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + } + + { + /* Are we optimizing this jump? */ + boolean keep_string_p = false; + + /* 1 means zero (many) matches is allowed. */ + char zero_times_ok = 0, many_times_ok = 0; + + /* If there is a sequence of repetition chars, collapse it + down to just one (the right one). We can't combine + interval operators with these because of, e.g., `a{2}*', + which should only match an even number of `a's. */ + + for (;;) + { + zero_times_ok |= c != '+'; + many_times_ok |= c != '?'; + + if (p == pend) + break; + + PATFETCH (c); + + if (c == '*' + || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?'))) + ; + + else if (syntax & RE_BK_PLUS_QM && c == '\\') + { + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); + + PATFETCH (c1); + if (!(c1 == '+' || c1 == '?')) + { + PATUNFETCH; + PATUNFETCH; + break; + } + + c = c1; + } + else + { + PATUNFETCH; + break; + } + + /* If we get here, we found another repeat character. */ + } + + /* Star, etc. applied to an empty pattern is equivalent + to an empty pattern. */ + if (!laststart) + break; + + /* Now we know whether or not zero matches is allowed + and also whether or not two or more matches is allowed. */ + if (many_times_ok) + { /* More than one repetition is allowed, so put in at the + end a backward relative jump from `b' to before the next + jump we're going to put in below (which jumps from + laststart to after this jump). + + But if we are at the `*' in the exact sequence `.*\n', + insert an unconditional jump backwards to the ., + instead of the beginning of the loop. This way we only + push a failure point once, instead of every time + through the loop. */ + assert (p - 1 > pattern); + + /* Allocate the space for the jump. */ + GET_BUFFER_SPACE (3); + + /* We know we are not at the first character of the pattern, + because laststart was nonzero. And we've already + incremented `p', by the way, to be the character after + the `*'. Do we have to do something analogous here + for null bytes, because of RE_DOT_NOT_NULL? */ + if (TRANSLATE (*(p - 2)) == TRANSLATE ('.') + && zero_times_ok + && p < pend && TRANSLATE (*p) == TRANSLATE ('\n') + && !(syntax & RE_DOT_NEWLINE)) + { /* We have .*\n. */ + STORE_JUMP (jump, b, laststart); + keep_string_p = true; + } + else + /* Anything else. */ + STORE_JUMP (maybe_pop_jump, b, laststart - 3); + + /* We've added more stuff to the buffer. */ + b += 3; + } + + /* On failure, jump from laststart to b + 3, which will be the + end of the buffer after this jump is inserted. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump + : on_failure_jump, + laststart, b + 3); + pending_exact = 0; + b += 3; + + if (!zero_times_ok) + { + /* At least one repetition is required, so insert a + `dummy_failure_jump' before the initial + `on_failure_jump' instruction of the loop. This + effects a skip over that instruction the first time + we hit that loop. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6); + b += 3; + } + } + break; + + + case '.': + laststart = b; + BUF_PUSH (anychar); + break; + + + case '[': + { + boolean had_char_class = false; + + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + /* Ensure that we have enough space to push a charset: the + opcode, the length count, and the bitset; 34 bytes in all. */ + GET_BUFFER_SPACE (34); + + laststart = b; + + /* We test `*p == '^' twice, instead of using an if + statement, so we only need one BUF_PUSH. */ + BUF_PUSH (*p == '^' ? charset_not : charset); + if (*p == '^') + p++; + + /* Remember the first position in the bracket expression. */ + p1 = p; + + /* Push the number of bytes in the bitmap. */ + BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH); + + /* Clear the whole map. */ + bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); + + /* charset_not matches newline according to a syntax bit. */ + if ((re_opcode_t) b[-2] == charset_not + && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) + SET_LIST_BIT ('\n'); + + /* Read in characters and ranges, setting map bits. */ + for (;;) + { + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + PATFETCH (c); + + /* \ might escape characters inside [...] and [^...]. */ + if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') + { + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); + + PATFETCH (c1); + SET_LIST_BIT (c1); + continue; + } + + /* Could be the end of the bracket expression. If it's + not (i.e., when the bracket expression is `[]' so + far), the ']' character bit gets set way below. */ + if (c == ']' && p != p1 + 1) + break; + + /* Look ahead to see if it's a range when the last thing + was a character class. */ + if (had_char_class && c == '-' && *p != ']') + FREE_STACK_RETURN (REG_ERANGE); + + /* Look ahead to see if it's a range when the last thing + was a character: if this is a hyphen not at the + beginning or the end of a list, then it's the range + operator. */ + if (c == '-' + && !(p - 2 >= pattern && p[-2] == '[') + && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') + && *p != ']') + { + reg_errcode_t ret + = compile_range (&p, pend, translate, syntax, b); + if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); + } + + else if (p[0] == '-' && p[1] != ']') + { /* This handles ranges made up of characters only. */ + reg_errcode_t ret; + + /* Move past the `-'. */ + PATFETCH (c1); + + ret = compile_range (&p, pend, translate, syntax, b); + if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); + } + + /* See if we're at the beginning of a possible character + class. */ + + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') + { /* Leave room for the null. */ + char str[CHAR_CLASS_MAX_LENGTH + 1]; + + PATFETCH (c); + c1 = 0; + + /* If pattern is `[[:'. */ + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (;;) + { + PATFETCH (c); + if ((c == ':' && *p == ']') || p == pend) + break; + if (c1 < CHAR_CLASS_MAX_LENGTH) + str[c1++] = c; + else + /* This is in any case an invalid class name. */ + str[0] = '\0'; + } + str[c1] = '\0'; + + /* If isn't a word bracketed by `[:' and `:]': + undo the ending character, the letters, and leave + the leading `:' and `[' (but set bits for them). */ + if (c == ':' && *p == ']') + { +#if defined _LIBC || WIDE_CHAR_SUPPORT + boolean is_lower = STREQ (str, "lower"); + boolean is_upper = STREQ (str, "upper"); + wctype_t wt; + int ch; + + wt = IS_CHAR_CLASS (str); + if (wt == 0) + FREE_STACK_RETURN (REG_ECTYPE); + + /* Throw away the ] at the end of the character + class. */ + PATFETCH (c); + + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (ch = 0; ch < 1 << BYTEWIDTH; ++ch) + { +# ifdef _LIBC + if (__iswctype (__btowc (ch), wt)) + SET_LIST_BIT (ch); +# else + if (iswctype (btowc (ch), wt)) + SET_LIST_BIT (ch); +# endif + + if (translate && (is_upper || is_lower) + && (ISUPPER (ch) || ISLOWER (ch))) + SET_LIST_BIT (ch); + } + + had_char_class = true; +#else + int ch; + boolean is_alnum = STREQ (str, "alnum"); + boolean is_alpha = STREQ (str, "alpha"); + boolean is_blank = STREQ (str, "blank"); + boolean is_cntrl = STREQ (str, "cntrl"); + boolean is_digit = STREQ (str, "digit"); + boolean is_graph = STREQ (str, "graph"); + boolean is_lower = STREQ (str, "lower"); + boolean is_print = STREQ (str, "print"); + boolean is_punct = STREQ (str, "punct"); + boolean is_space = STREQ (str, "space"); + boolean is_upper = STREQ (str, "upper"); + boolean is_xdigit = STREQ (str, "xdigit"); + + if (!IS_CHAR_CLASS (str)) + FREE_STACK_RETURN (REG_ECTYPE); + + /* Throw away the ] at the end of the character + class. */ + PATFETCH (c); + + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (ch = 0; ch < 1 << BYTEWIDTH; ch++) + { + /* This was split into 3 if's to + avoid an arbitrary limit in some compiler. */ + if ( (is_alnum && ISALNUM (ch)) + || (is_alpha && ISALPHA (ch)) + || (is_blank && ISBLANK (ch)) + || (is_cntrl && ISCNTRL (ch))) + SET_LIST_BIT (ch); + if ( (is_digit && ISDIGIT (ch)) + || (is_graph && ISGRAPH (ch)) + || (is_lower && ISLOWER (ch)) + || (is_print && ISPRINT (ch))) + SET_LIST_BIT (ch); + if ( (is_punct && ISPUNCT (ch)) + || (is_space && ISSPACE (ch)) + || (is_upper && ISUPPER (ch)) + || (is_xdigit && ISXDIGIT (ch))) + SET_LIST_BIT (ch); + if ( translate && (is_upper || is_lower) + && (ISUPPER (ch) || ISLOWER (ch))) + SET_LIST_BIT (ch); + } + had_char_class = true; +#endif /* libc || wctype.h */ + } + else + { + c1++; + while (c1--) + PATUNFETCH; + SET_LIST_BIT ('['); + SET_LIST_BIT (':'); + had_char_class = false; + } + } + else + { + had_char_class = false; + SET_LIST_BIT (c); + } + } + + /* Discard any (non)matching list bytes that are all 0 at the + end of the map. Decrease the map-length byte too. */ + while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) + b[-1]--; + b += b[-1]; + } + break; + + + case '(': + if (syntax & RE_NO_BK_PARENS) + goto handle_open; + else + goto normal_char; + + + case ')': + if (syntax & RE_NO_BK_PARENS) + goto handle_close; + else + goto normal_char; + + + case '\n': + if (syntax & RE_NEWLINE_ALT) + goto handle_alt; + else + goto normal_char; + + + case '|': + if (syntax & RE_NO_BK_VBAR) + goto handle_alt; + else + goto normal_char; + + + case '{': + if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES) + goto handle_interval; + else + goto normal_char; + + + case '\\': + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); + + /* Do not translate the character after the \, so that we can + distinguish, e.g., \B from \b, even if we normally would + translate, e.g., B to b. */ + PATFETCH_RAW (c); + + switch (c) + { + case '(': + if (syntax & RE_NO_BK_PARENS) + goto normal_backslash; + + handle_open: + bufp->re_nsub++; + regnum++; + + if (COMPILE_STACK_FULL) + { + RETALLOC (compile_stack.stack, compile_stack.size << 1, + compile_stack_elt_t); + if (compile_stack.stack == NULL) return REG_ESPACE; + + compile_stack.size <<= 1; + } + + /* These are the values to restore when we hit end of this + group. They are all relative offsets, so that if the + whole pattern moves because of realloc, they will still + be valid. */ + COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer; + COMPILE_STACK_TOP.fixup_alt_jump + = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0; + COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer; + COMPILE_STACK_TOP.regnum = regnum; + + /* We will eventually replace the 0 with the number of + groups inner to this one. But do not push a + start_memory for groups beyond the last one we can + represent in the compiled pattern. */ + if (regnum <= MAX_REGNUM) + { + COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2; + BUF_PUSH_3 (start_memory, regnum, 0); + } + + compile_stack.avail++; + + fixup_alt_jump = 0; + laststart = 0; + begalt = b; + /* If we've reached MAX_REGNUM groups, then this open + won't actually generate any code, so we'll have to + clear pending_exact explicitly. */ + pending_exact = 0; + break; + + + case ')': + if (syntax & RE_NO_BK_PARENS) goto normal_backslash; + + if (COMPILE_STACK_EMPTY) + { + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_backslash; + else + FREE_STACK_RETURN (REG_ERPAREN); + } + + handle_close: + if (fixup_alt_jump) + { /* Push a dummy failure point at the end of the + alternative for a possible future + `pop_failure_jump' to pop. See comments at + `push_dummy_failure' in `re_match_2'. */ + BUF_PUSH (push_dummy_failure); + + /* We allocated space for this jump when we assigned + to `fixup_alt_jump', in the `handle_alt' case below. */ + STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1); + } + + /* See similar code for backslashed left paren above. */ + if (COMPILE_STACK_EMPTY) + { + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_char; + else + FREE_STACK_RETURN (REG_ERPAREN); + } + + /* Since we just checked for an empty stack above, this + ``can't happen''. */ + assert (compile_stack.avail != 0); + { + /* We don't just want to restore into `regnum', because + later groups should continue to be numbered higher, + as in `(ab)c(de)' -- the second group is #2. */ + regnum_t this_group_regnum; + + compile_stack.avail--; + begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset; + fixup_alt_jump + = COMPILE_STACK_TOP.fixup_alt_jump + ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 + : 0; + laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset; + this_group_regnum = COMPILE_STACK_TOP.regnum; + /* If we've reached MAX_REGNUM groups, then this open + won't actually generate any code, so we'll have to + clear pending_exact explicitly. */ + pending_exact = 0; + + /* We're at the end of the group, so now we know how many + groups were inside this one. */ + if (this_group_regnum <= MAX_REGNUM) + { + unsigned char *inner_group_loc + = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset; + + *inner_group_loc = regnum - this_group_regnum; + BUF_PUSH_3 (stop_memory, this_group_regnum, + regnum - this_group_regnum); + } + } + break; + + + case '|': /* `\|'. */ + if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR) + goto normal_backslash; + handle_alt: + if (syntax & RE_LIMITED_OPS) + goto normal_char; + + /* Insert before the previous alternative a jump which + jumps to this alternative if the former fails. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (on_failure_jump, begalt, b + 6); + pending_exact = 0; + b += 3; + + /* The alternative before this one has a jump after it + which gets executed if it gets matched. Adjust that + jump so it will jump to this alternative's analogous + jump (put in below, which in turn will jump to the next + (if any) alternative's such jump, etc.). The last such + jump jumps to the correct final destination. A picture: + _____ _____ + | | | | + | v | v + a | b | c + + If we are at `b', then fixup_alt_jump right now points to a + three-byte space after `a'. We'll put in the jump, set + fixup_alt_jump to right after `b', and leave behind three + bytes which we'll fill in when we get to after `c'. */ + + if (fixup_alt_jump) + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); + + /* Mark and leave space for a jump after this alternative, + to be filled in later either by next alternative or + when know we're at the end of a series of alternatives. */ + fixup_alt_jump = b; + GET_BUFFER_SPACE (3); + b += 3; + + laststart = 0; + begalt = b; + break; + + + case '{': + /* If \{ is a literal. */ + if (!(syntax & RE_INTERVALS) + /* If we're at `\{' and it's not the open-interval + operator. */ + || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) + || (p - 2 == pattern && p == pend)) + goto normal_backslash; + + handle_interval: + { + /* If got here, then the syntax allows intervals. */ + + /* At least (most) this many matches must be made. */ + int lower_bound = -1, upper_bound = -1; + + beg_interval = p - 1; + + if (p == pend) + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + FREE_STACK_RETURN (REG_EBRACE); + } + + GET_UNSIGNED_NUMBER (lower_bound); + + if (c == ',') + { + GET_UNSIGNED_NUMBER (upper_bound); + if (upper_bound < 0) upper_bound = RE_DUP_MAX; + } + else + /* Interval such as `{1}' => match exactly once. */ + upper_bound = lower_bound; + + if (lower_bound < 0 || upper_bound > RE_DUP_MAX + || lower_bound > upper_bound) + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + FREE_STACK_RETURN (REG_BADBR); + } + + if (!(syntax & RE_NO_BK_BRACES)) + { + if (c != '\\') FREE_STACK_RETURN (REG_EBRACE); + + PATFETCH (c); + } + + if (c != '}') + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + FREE_STACK_RETURN (REG_BADBR); + } + + /* We just parsed a valid interval. */ + + /* If it's invalid to have no preceding re. */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + FREE_STACK_RETURN (REG_BADRPT); + else if (syntax & RE_CONTEXT_INDEP_OPS) + laststart = b; + else + goto unfetch_interval; + } + + /* If the upper bound is zero, don't want to succeed at + all; jump from `laststart' to `b + 3', which will be + the end of the buffer after we insert the jump. */ + if (upper_bound == 0) + { + GET_BUFFER_SPACE (3); + INSERT_JUMP (jump, laststart, b + 3); + b += 3; + } + + /* Otherwise, we have a nontrivial interval. When + we're all done, the pattern will look like: + set_number_at + set_number_at + succeed_n + + jump_n + (The upper bound and `jump_n' are omitted if + `upper_bound' is 1, though.) */ + else + { /* If the upper bound is > 1, we need to insert + more at the end of the loop. */ + unsigned nbytes = 10 + (upper_bound > 1) * 10; + + GET_BUFFER_SPACE (nbytes); + + /* Initialize lower bound of the `succeed_n', even + though it will be set during matching by its + attendant `set_number_at' (inserted next), + because `re_compile_fastmap' needs to know. + Jump to the `jump_n' we might insert below. */ + INSERT_JUMP2 (succeed_n, laststart, + b + 5 + (upper_bound > 1) * 5, + lower_bound); + b += 5; + + /* Code to initialize the lower bound. Insert + before the `succeed_n'. The `5' is the last two + bytes of this `set_number_at', plus 3 bytes of + the following `succeed_n'. */ + insert_op2 (set_number_at, laststart, 5, lower_bound, b); + b += 5; + + if (upper_bound > 1) + { /* More than one repetition is allowed, so + append a backward jump to the `succeed_n' + that starts this interval. + + When we've reached this during matching, + we'll have matched the interval once, so + jump back only `upper_bound - 1' times. */ + STORE_JUMP2 (jump_n, b, laststart + 5, + upper_bound - 1); + b += 5; + + /* The location we want to set is the second + parameter of the `jump_n'; that is `b-2' as + an absolute address. `laststart' will be + the `set_number_at' we're about to insert; + `laststart+3' the number to set, the source + for the relative address. But we are + inserting into the middle of the pattern -- + so everything is getting moved up by 5. + Conclusion: (b - 2) - (laststart + 3) + 5, + i.e., b - laststart. + + We insert this at the beginning of the loop + so that if we fail during matching, we'll + reinitialize the bounds. */ + insert_op2 (set_number_at, laststart, b - laststart, + upper_bound - 1, b); + b += 5; + } + } + pending_exact = 0; + beg_interval = NULL; + } + break; + + unfetch_interval: + /* If an invalid interval, match the characters as literals. */ + assert (beg_interval); + p = beg_interval; + beg_interval = NULL; + + /* normal_char and normal_backslash need `c'. */ + PATFETCH (c); + + if (!(syntax & RE_NO_BK_BRACES)) + { + if (p > pattern && p[-1] == '\\') + goto normal_backslash; + } + goto normal_char; + +#ifdef emacs + /* There is no way to specify the before_dot and after_dot + operators. rms says this is ok. --karl */ + case '=': + BUF_PUSH (at_dot); + break; + + case 's': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]); + break; + + case 'S': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]); + break; +#endif /* emacs */ + + + case 'w': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + laststart = b; + BUF_PUSH (wordchar); + break; + + + case 'W': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + laststart = b; + BUF_PUSH (notwordchar); + break; + + + case '<': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (wordbeg); + break; + + case '>': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (wordend); + break; + + case 'b': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (wordbound); + break; + + case 'B': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (notwordbound); + break; + + case '`': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (begbuf); + break; + + case '\'': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (endbuf); + break; + + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + if (syntax & RE_NO_BK_REFS) + goto normal_char; + + c1 = c - '0'; + + if (c1 > regnum) + FREE_STACK_RETURN (REG_ESUBREG); + + /* Can't back reference to a subexpression if inside of it. */ + if (group_in_compile_stack (compile_stack, (regnum_t) c1)) + goto normal_char; + + laststart = b; + BUF_PUSH_2 (duplicate, c1); + break; + + + case '+': + case '?': + if (syntax & RE_BK_PLUS_QM) + goto handle_plus; + else + goto normal_backslash; + + default: + normal_backslash: + /* You might think it would be useful for \ to mean + not to translate; but if we don't translate it + it will never match anything. */ + c = TRANSLATE (c); + goto normal_char; + } + break; + + + default: + /* Expects the character in `c'. */ + normal_char: + /* If no exactn currently being built. */ + if (!pending_exact + + /* If last exactn not at current position. */ + || pending_exact + *pending_exact + 1 != b + + /* We have only one byte following the exactn for the count. */ + || *pending_exact == (1 << BYTEWIDTH) - 1 + + /* If followed by a repetition operator. */ + || *p == '*' || *p == '^' + || ((syntax & RE_BK_PLUS_QM) + ? *p == '\\' && (p[1] == '+' || p[1] == '?') + : (*p == '+' || *p == '?')) + || ((syntax & RE_INTERVALS) + && ((syntax & RE_NO_BK_BRACES) + ? *p == '{' + : (p[0] == '\\' && p[1] == '{')))) + { + /* Start building a new exactn. */ + + laststart = b; + + BUF_PUSH_2 (exactn, 0); + pending_exact = b - 1; + } + + BUF_PUSH (c); + (*pending_exact)++; + break; + } /* switch (c) */ + } /* while p != pend */ + + + /* Through the pattern now. */ + + if (fixup_alt_jump) + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); + + if (!COMPILE_STACK_EMPTY) + FREE_STACK_RETURN (REG_EPAREN); + + /* If we don't want backtracking, force success + the first time we reach the end of the compiled pattern. */ + if (syntax & RE_NO_POSIX_BACKTRACKING) + BUF_PUSH (succeed); + + free (compile_stack.stack); + + /* We have succeeded; set the length of the buffer. */ + bufp->used = b - bufp->buffer; + +#ifdef DEBUG + if (debug) + { + DEBUG_PRINT1 ("\nCompiled pattern: \n"); + print_compiled_pattern (bufp); + } +#endif /* DEBUG */ + +#ifndef MATCH_MAY_ALLOCATE + /* Initialize the failure stack to the largest possible stack. This + isn't necessary unless we're trying to avoid calling alloca in + the search and match routines. */ + { + int num_regs = bufp->re_nsub + 1; + + /* Since DOUBLE_FAIL_STACK refuses to double only if the current size + is strictly greater than re_max_failures, the largest possible stack + is 2 * re_max_failures failure points. */ + if (fail_stack.size < (2 * re_max_failures * MAX_FAILURE_ITEMS)) + { + fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS); + +# ifdef emacs + if (! fail_stack.stack) + fail_stack.stack + = (fail_stack_elt_t *) xmalloc (fail_stack.size + * sizeof (fail_stack_elt_t)); + else + fail_stack.stack + = (fail_stack_elt_t *) xrealloc (fail_stack.stack, + (fail_stack.size + * sizeof (fail_stack_elt_t))); +# else /* not emacs */ + if (! fail_stack.stack) + fail_stack.stack + = (fail_stack_elt_t *) malloc (fail_stack.size + * sizeof (fail_stack_elt_t)); + else + fail_stack.stack + = (fail_stack_elt_t *) realloc (fail_stack.stack, + (fail_stack.size + * sizeof (fail_stack_elt_t))); +# endif /* not emacs */ + } + + regex_grow_registers (num_regs); + } +#endif /* not MATCH_MAY_ALLOCATE */ + + return REG_NOERROR; +} /* regex_compile */ + +/* Subroutines for `regex_compile'. */ + +/* Store OP at LOC followed by two-byte integer parameter ARG. */ + +static void +store_op1 (op, loc, arg) + re_opcode_t op; + unsigned char *loc; + int arg; +{ + *loc = (unsigned char) op; + STORE_NUMBER (loc + 1, arg); +} + + +/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */ + +static void +store_op2 (op, loc, arg1, arg2) + re_opcode_t op; + unsigned char *loc; + int arg1, arg2; +{ + *loc = (unsigned char) op; + STORE_NUMBER (loc + 1, arg1); + STORE_NUMBER (loc + 3, arg2); +} + + +/* Copy the bytes from LOC to END to open up three bytes of space at LOC + for OP followed by two-byte integer parameter ARG. */ + +static void +insert_op1 (op, loc, arg, end) + re_opcode_t op; + unsigned char *loc; + int arg; + unsigned char *end; +{ + register unsigned char *pfrom = end; + register unsigned char *pto = end + 3; + + while (pfrom != loc) + *--pto = *--pfrom; + + store_op1 (op, loc, arg); +} + + +/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */ + +static void +insert_op2 (op, loc, arg1, arg2, end) + re_opcode_t op; + unsigned char *loc; + int arg1, arg2; + unsigned char *end; +{ + register unsigned char *pfrom = end; + register unsigned char *pto = end + 5; + + while (pfrom != loc) + *--pto = *--pfrom; + + store_op2 (op, loc, arg1, arg2); +} + + +/* P points to just after a ^ in PATTERN. Return true if that ^ comes + after an alternative or a begin-subexpression. We assume there is at + least one character before the ^. */ + +static boolean +at_begline_loc_p (pattern, p, syntax) + const char *pattern, *p; + reg_syntax_t syntax; +{ + const char *prev = p - 2; + boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; + + return + /* After a subexpression? */ + (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash)) + /* After an alternative? */ + || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash)); +} + + +/* The dual of at_begline_loc_p. This one is for $. We assume there is + at least one character after the $, i.e., `P < PEND'. */ + +static boolean +at_endline_loc_p (p, pend, syntax) + const char *p, *pend; + reg_syntax_t syntax; +{ + const char *next = p; + boolean next_backslash = *next == '\\'; + const char *next_next = p + 1 < pend ? p + 1 : 0; + + return + /* Before a subexpression? */ + (syntax & RE_NO_BK_PARENS ? *next == ')' + : next_backslash && next_next && *next_next == ')') + /* Before an alternative? */ + || (syntax & RE_NO_BK_VBAR ? *next == '|' + : next_backslash && next_next && *next_next == '|'); +} + + +/* Returns true if REGNUM is in one of COMPILE_STACK's elements and + false if it's not. */ + +static boolean +group_in_compile_stack (compile_stack, regnum) + compile_stack_type compile_stack; + regnum_t regnum; +{ + int this_element; + + for (this_element = compile_stack.avail - 1; + this_element >= 0; + this_element--) + if (compile_stack.stack[this_element].regnum == regnum) + return true; + + return false; +} + + +/* Read the ending character of a range (in a bracket expression) from the + uncompiled pattern *P_PTR (which ends at PEND). We assume the + starting character is in `P[-2]'. (`P[-1]' is the character `-'.) + Then we set the translation of all bits between the starting and + ending characters (inclusive) in the compiled pattern B. + + Return an error code. + + We use these short variable names so we can use the same macros as + `regex_compile' itself. */ + +static reg_errcode_t +compile_range (p_ptr, pend, translate, syntax, b) + const char **p_ptr, *pend; + RE_TRANSLATE_TYPE translate; + reg_syntax_t syntax; + unsigned char *b; +{ + unsigned this_char; + + const char *p = *p_ptr; + unsigned int range_start, range_end; + + if (p == pend) + return REG_ERANGE; + + /* Even though the pattern is a signed `char *', we need to fetch + with unsigned char *'s; if the high bit of the pattern character + is set, the range endpoints will be negative if we fetch using a + signed char *. + + We also want to fetch the endpoints without translating them; the + appropriate translation is done in the bit-setting loop below. */ + /* The SVR4 compiler on the 3B2 had trouble with unsigned const char *. */ + range_start = ((const unsigned char *) p)[-2]; + range_end = ((const unsigned char *) p)[0]; + + /* Have to increment the pointer into the pattern string, so the + caller isn't still at the ending character. */ + (*p_ptr)++; + + /* If the start is after the end, the range is empty. */ + if (range_start > range_end) + return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR; + + /* Here we see why `this_char' has to be larger than an `unsigned + char' -- the range is inclusive, so if `range_end' == 0xff + (assuming 8-bit characters), we would otherwise go into an infinite + loop, since all characters <= 0xff. */ + for (this_char = range_start; this_char <= range_end; this_char++) + { + SET_LIST_BIT (TRANSLATE (this_char)); + } + + return REG_NOERROR; +} + +/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in + BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible + characters can start a string that matches the pattern. This fastmap + is used by re_search to skip quickly over impossible starting points. + + The caller must supply the address of a (1 << BYTEWIDTH)-byte data + area as BUFP->fastmap. + + We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in + the pattern buffer. + + Returns 0 if we succeed, -2 if an internal error. */ + +int +re_compile_fastmap (bufp) + struct re_pattern_buffer *bufp; +{ + int j, k; +#ifdef MATCH_MAY_ALLOCATE + fail_stack_type fail_stack; +#endif +#ifndef REGEX_MALLOC + char *destination; +#endif + + register char *fastmap = bufp->fastmap; + unsigned char *pattern = bufp->buffer; + unsigned char *p = pattern; + register unsigned char *pend = pattern + bufp->used; + +#ifdef REL_ALLOC + /* This holds the pointer to the failure stack, when + it is allocated relocatably. */ + fail_stack_elt_t *failure_stack_ptr; +#endif + + /* Assume that each path through the pattern can be null until + proven otherwise. We set this false at the bottom of switch + statement, to which we get only if a particular path doesn't + match the empty string. */ + boolean path_can_be_null = true; + + /* We aren't doing a `succeed_n' to begin with. */ + boolean succeed_n_p = false; + + assert (fastmap != NULL && p != NULL); + + INIT_FAIL_STACK (); + bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */ + bufp->fastmap_accurate = 1; /* It will be when we're done. */ + bufp->can_be_null = 0; + + while (1) + { + if (p == pend || *p == succeed) + { + /* We have reached the (effective) end of pattern. */ + if (!FAIL_STACK_EMPTY ()) + { + bufp->can_be_null |= path_can_be_null; + + /* Reset for next path. */ + path_can_be_null = true; + + p = fail_stack.stack[--fail_stack.avail].pointer; + + continue; + } + else + break; + } + + /* We should never be about to go beyond the end of the pattern. */ + assert (p < pend); + + switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++)) + { + + /* I guess the idea here is to simply not bother with a fastmap + if a backreference is used, since it's too hard to figure out + the fastmap for the corresponding group. Setting + `can_be_null' stops `re_search_2' from using the fastmap, so + that is all we do. */ + case duplicate: + bufp->can_be_null = 1; + goto done; + + + /* Following are the cases which match a character. These end + with `break'. */ + + case exactn: + fastmap[p[1]] = 1; + break; + + + case charset: + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) + fastmap[j] = 1; + break; + + + case charset_not: + /* Chars beyond end of map must be allowed. */ + for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) + fastmap[j] = 1; + + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) + fastmap[j] = 1; + break; + + + case wordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == Sword) + fastmap[j] = 1; + break; + + + case notwordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != Sword) + fastmap[j] = 1; + break; + + + case anychar: + { + int fastmap_newline = fastmap['\n']; + + /* `.' matches anything ... */ + for (j = 0; j < (1 << BYTEWIDTH); j++) + fastmap[j] = 1; + + /* ... except perhaps newline. */ + if (!(bufp->syntax & RE_DOT_NEWLINE)) + fastmap['\n'] = fastmap_newline; + + /* Return if we have already set `can_be_null'; if we have, + then the fastmap is irrelevant. Something's wrong here. */ + else if (bufp->can_be_null) + goto done; + + /* Otherwise, have to check alternative paths. */ + break; + } + +#ifdef emacs + case syntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == (enum syntaxcode) k) + fastmap[j] = 1; + break; + + + case notsyntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != (enum syntaxcode) k) + fastmap[j] = 1; + break; + + + /* All cases after this match the empty string. These end with + `continue'. */ + + + case before_dot: + case at_dot: + case after_dot: + continue; +#endif /* emacs */ + + + case no_op: + case begline: + case endline: + case begbuf: + case endbuf: + case wordbound: + case notwordbound: + case wordbeg: + case wordend: + case push_dummy_failure: + continue; + + + case jump_n: + case pop_failure_jump: + case maybe_pop_jump: + case jump: + case jump_past_alt: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + if (j > 0) + continue; + + /* Jump backward implies we just went through the body of a + loop and matched nothing. Opcode jumped to should be + `on_failure_jump' or `succeed_n'. Just treat it like an + ordinary jump. For a * loop, it has pushed its failure + point already; if so, discard that as redundant. */ + if ((re_opcode_t) *p != on_failure_jump + && (re_opcode_t) *p != succeed_n) + continue; + + p++; + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + + /* If what's on the stack is where we are now, pop it. */ + if (!FAIL_STACK_EMPTY () + && fail_stack.stack[fail_stack.avail - 1].pointer == p) + fail_stack.avail--; + + continue; + + + case on_failure_jump: + case on_failure_keep_string_jump: + handle_on_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + + /* For some patterns, e.g., `(a?)?', `p+j' here points to the + end of the pattern. We don't want to push such a point, + since when we restore it above, entering the switch will + increment `p' past the end of the pattern. We don't need + to push such a point since we obviously won't find any more + fastmap entries beyond `pend'. Such a pattern can match + the null string, though. */ + if (p + j < pend) + { + if (!PUSH_PATTERN_OP (p + j, fail_stack)) + { + RESET_FAIL_STACK (); + return -2; + } + } + else + bufp->can_be_null = 1; + + if (succeed_n_p) + { + EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */ + succeed_n_p = false; + } + + continue; + + + case succeed_n: + /* Get to the number of times to succeed. */ + p += 2; + + /* Increment p past the n for when k != 0. */ + EXTRACT_NUMBER_AND_INCR (k, p); + if (k == 0) + { + p -= 4; + succeed_n_p = true; /* Spaghetti code alert. */ + goto handle_on_failure_jump; + } + continue; + + + case set_number_at: + p += 4; + continue; + + + case start_memory: + case stop_memory: + p += 2; + continue; + + + default: + abort (); /* We have listed all the cases. */ + } /* switch *p++ */ + + /* Getting here means we have found the possible starting + characters for one path of the pattern -- and that the empty + string does not match. We need not follow this path further. + Instead, look at the next alternative (remembered on the + stack), or quit if no more. The test at the top of the loop + does these things. */ + path_can_be_null = false; + p = pend; + } /* while p */ + + /* Set `can_be_null' for the last path (also the first path, if the + pattern is empty). */ + bufp->can_be_null |= path_can_be_null; + + done: + RESET_FAIL_STACK (); + return 0; +} /* re_compile_fastmap */ +#ifdef _LIBC +weak_alias (__re_compile_fastmap, re_compile_fastmap) +#endif + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use + this memory for recording register information. STARTS and ENDS + must be allocated using the malloc library routine, and must each + be at least NUM_REGS * sizeof (regoff_t) bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ + +void +re_set_registers (bufp, regs, num_regs, starts, ends) + struct re_pattern_buffer *bufp; + struct re_registers *regs; + unsigned num_regs; + regoff_t *starts, *ends; +{ + if (num_regs) + { + bufp->regs_allocated = REGS_REALLOCATE; + regs->num_regs = num_regs; + regs->start = starts; + regs->end = ends; + } + else + { + bufp->regs_allocated = REGS_UNALLOCATED; + regs->num_regs = 0; + regs->start = regs->end = (regoff_t *) 0; + } +} +#ifdef _LIBC +weak_alias (__re_set_registers, re_set_registers) +#endif + +/* Searching routines. */ + +/* Like re_search_2, below, but only one string is specified, and + doesn't let you say where to stop matching. */ + +int +re_search (bufp, string, size, startpos, range, regs) + struct re_pattern_buffer *bufp; + const char *string; + int size, startpos, range; + struct re_registers *regs; +{ + return re_search_2 (bufp, NULL, 0, string, size, startpos, range, + regs, size); +} +#ifdef _LIBC +weak_alias (__re_search, re_search) +#endif + + +/* Using the compiled pattern in BUFP->buffer, first tries to match the + virtual concatenation of STRING1 and STRING2, starting first at index + STARTPOS, then at STARTPOS + 1, and so on. + + STRING1 and STRING2 have length SIZE1 and SIZE2, respectively. + + RANGE is how far to scan while trying to match. RANGE = 0 means try + only at STARTPOS; in general, the last start tried is STARTPOS + + RANGE. + + In REGS, return the indices of the virtual concatenation of STRING1 + and STRING2 that matched the entire BUFP->buffer and its contained + subexpressions. + + Do not consider matching one past the index STOP in the virtual + concatenation of STRING1 and STRING2. + + We return either the position in the strings at which the match was + found, -1 if no match, or -2 if error (such as failure + stack overflow). */ + +int +re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + int size1, size2; + int startpos; + int range; + struct re_registers *regs; + int stop; +{ + int val; + register char *fastmap = bufp->fastmap; + register RE_TRANSLATE_TYPE translate = bufp->translate; + int total_size = size1 + size2; + int endpos = startpos + range; + + /* Check for out-of-range STARTPOS. */ + if (startpos < 0 || startpos > total_size) + return -1; + + /* Fix up RANGE if it might eventually take us outside + the virtual concatenation of STRING1 and STRING2. + Make sure we won't move STARTPOS below 0 or above TOTAL_SIZE. */ + if (endpos < 0) + range = 0 - startpos; + else if (endpos > total_size) + range = total_size - startpos; + + /* If the search isn't to be a backwards one, don't waste time in a + search for a pattern that must be anchored. */ + if (bufp->used > 0 && range > 0 + && ((re_opcode_t) bufp->buffer[0] == begbuf + /* `begline' is like `begbuf' if it cannot match at newlines. */ + || ((re_opcode_t) bufp->buffer[0] == begline + && !bufp->newline_anchor))) + { + if (startpos > 0) + return -1; + else + range = 1; + } + +#ifdef emacs + /* In a forward search for something that starts with \=. + don't keep searching past point. */ + if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == at_dot && range > 0) + { + range = PT - startpos; + if (range <= 0) + return -1; + } +#endif /* emacs */ + + /* Update the fastmap now if not correct already. */ + if (fastmap && !bufp->fastmap_accurate) + if (re_compile_fastmap (bufp) == -2) + return -2; + + /* Loop through the string, looking for a place to start matching. */ + for (;;) + { + /* If a fastmap is supplied, skip quickly over characters that + cannot be the start of a match. If the pattern can match the + null string, however, we don't need to skip characters; we want + the first null string. */ + if (fastmap && startpos < total_size && !bufp->can_be_null) + { + if (range > 0) /* Searching forwards. */ + { + register const char *d; + register int lim = 0; + int irange = range; + + if (startpos < size1 && startpos + range >= size1) + lim = range - (size1 - startpos); + + d = (startpos >= size1 ? string2 - size1 : string1) + startpos; + + /* Written out as an if-else to avoid testing `translate' + inside the loop. */ + if (translate) + while (range > lim + && !fastmap[(unsigned char) + translate[(unsigned char) *d++]]) + range--; + else + while (range > lim && !fastmap[(unsigned char) *d++]) + range--; + + startpos += irange - range; + } + else /* Searching backwards. */ + { + register char c = (size1 == 0 || startpos >= size1 + ? string2[startpos - size1] + : string1[startpos]); + + if (!fastmap[(unsigned char) TRANSLATE (c)]) + goto advance; + } + } + + /* If can't match the null string, and that's all we have left, fail. */ + if (range >= 0 && startpos == total_size && fastmap + && !bufp->can_be_null) + return -1; + + val = re_match_2_internal (bufp, string1, size1, string2, size2, + startpos, regs, stop); +#ifndef REGEX_MALLOC +# ifdef C_ALLOCA + alloca (0); +# endif +#endif + + if (val >= 0) + return startpos; + + if (val == -2) + return -2; + + advance: + if (!range) + break; + else if (range > 0) + { + range--; + startpos++; + } + else + { + range++; + startpos--; + } + } + return -1; +} /* re_search_2 */ +#ifdef _LIBC +weak_alias (__re_search_2, re_search_2) +#endif + +/* This converts PTR, a pointer into one of the search strings `string1' + and `string2' into an offset from the beginning of that string. */ +#define POINTER_TO_OFFSET(ptr) \ + (FIRST_STRING_P (ptr) \ + ? ((regoff_t) ((ptr) - string1)) \ + : ((regoff_t) ((ptr) - string2 + size1))) + +/* Macros for dealing with the split strings in re_match_2. */ + +#define MATCHING_IN_FIRST_STRING (dend == end_match_1) + +/* Call before fetching a character with *d. This switches over to + string2 if necessary. */ +#define PREFETCH() \ + while (d == dend) \ + { \ + /* End of string2 => fail. */ \ + if (dend == end_match_2) \ + goto fail; \ + /* End of string1 => advance to string2. */ \ + d = string2; \ + dend = end_match_2; \ + } + + +/* Test if at very beginning or at very end of the virtual concatenation + of `string1' and `string2'. If only one string, it's `string2'. */ +#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2) +#define AT_STRINGS_END(d) ((d) == end2) + + +/* Test if D points to a character which is word-constituent. We have + two special cases to check for: if past the end of string1, look at + the first character in string2; and if before the beginning of + string2, look at the last character in string1. */ +#define WORDCHAR_P(d) \ + (SYNTAX ((d) == end1 ? *string2 \ + : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ + == Sword) + +/* Disabled due to a compiler bug -- see comment at case wordbound */ +#if 0 +/* Test if the character before D and the one at D differ with respect + to being word-constituent. */ +#define AT_WORD_BOUNDARY(d) \ + (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \ + || WORDCHAR_P (d - 1) != WORDCHAR_P (d)) +#endif + +/* Free everything we malloc. */ +#ifdef MATCH_MAY_ALLOCATE +# define FREE_VAR(var) if (var) REGEX_FREE (var); var = NULL +# define FREE_VARIABLES() \ + do { \ + REGEX_FREE_STACK (fail_stack.stack); \ + FREE_VAR (regstart); \ + FREE_VAR (regend); \ + FREE_VAR (old_regstart); \ + FREE_VAR (old_regend); \ + FREE_VAR (best_regstart); \ + FREE_VAR (best_regend); \ + FREE_VAR (reg_info); \ + FREE_VAR (reg_dummy); \ + FREE_VAR (reg_info_dummy); \ + } while (0) +#else +# define FREE_VARIABLES() ((void)0) /* Do nothing! But inhibit gcc warning. */ +#endif /* not MATCH_MAY_ALLOCATE */ + +/* These values must meet several constraints. They must not be valid + register values; since we have a limit of 255 registers (because + we use only one byte in the pattern for the register number), we can + use numbers larger than 255. They must differ by 1, because of + NUM_FAILURE_ITEMS above. And the value for the lowest register must + be larger than the value for the highest register, so we do not try + to actually save any registers when none are active. */ +#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH) +#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1) + +/* Matching routines. */ + +#ifndef emacs /* Emacs never uses this. */ +/* re_match is like re_match_2 except it takes only a single string. */ + +int +re_match (bufp, string, size, pos, regs) + struct re_pattern_buffer *bufp; + const char *string; + int size, pos; + struct re_registers *regs; +{ + int result = re_match_2_internal (bufp, NULL, 0, string, size, + pos, regs, size); +# ifndef REGEX_MALLOC +# ifdef C_ALLOCA + alloca (0); +# endif +# endif + return result; +} +# ifdef _LIBC +weak_alias (__re_match, re_match) +# endif +#endif /* not emacs */ + +static boolean group_match_null_string_p _RE_ARGS ((unsigned char **p, + unsigned char *end, + register_info_type *reg_info)); +static boolean alt_match_null_string_p _RE_ARGS ((unsigned char *p, + unsigned char *end, + register_info_type *reg_info)); +static boolean common_op_match_null_string_p _RE_ARGS ((unsigned char **p, + unsigned char *end, + register_info_type *reg_info)); +static int bcmp_translate _RE_ARGS ((const char *s1, const char *s2, + int len, char *translate)); + +/* re_match_2 matches the compiled pattern in BUFP against the + the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 + and SIZE2, respectively). We start matching at POS, and stop + matching at STOP. + + If REGS is non-null and the `no_sub' field of BUFP is nonzero, we + store offsets for the substring each group matched in REGS. See the + documentation for exactly how many groups we fill. + + We return -1 if no match, -2 if an internal error (such as the + failure stack overflowing). Otherwise, we return the length of the + matched substring. */ + +int +re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + int size1, size2; + int pos; + struct re_registers *regs; + int stop; +{ + int result = re_match_2_internal (bufp, string1, size1, string2, size2, + pos, regs, stop); +#ifndef REGEX_MALLOC +# ifdef C_ALLOCA + alloca (0); +# endif +#endif + return result; +} +#ifdef _LIBC +weak_alias (__re_match_2, re_match_2) +#endif + +/* This is a separate function so that we can force an alloca cleanup + afterwards. */ +static int +re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + int size1, size2; + int pos; + struct re_registers *regs; + int stop; +{ + /* General temporaries. */ + int mcnt; + unsigned char *p1; + + /* Just past the end of the corresponding string. */ + const char *end1, *end2; + + /* Pointers into string1 and string2, just past the last characters in + each to consider matching. */ + const char *end_match_1, *end_match_2; + + /* Where we are in the data, and the end of the current string. */ + const char *d, *dend; + + /* Where we are in the pattern, and the end of the pattern. */ + unsigned char *p = bufp->buffer; + register unsigned char *pend = p + bufp->used; + + /* Mark the opcode just after a start_memory, so we can test for an + empty subpattern when we get to the stop_memory. */ + unsigned char *just_past_start_mem = 0; + + /* We use this to map every character in the string. */ + RE_TRANSLATE_TYPE translate = bufp->translate; + + /* Failure point stack. Each place that can handle a failure further + down the line pushes a failure point on this stack. It consists of + restart, regend, and reg_info for all registers corresponding to + the subexpressions we're currently inside, plus the number of such + registers, and, finally, two char *'s. The first char * is where + to resume scanning the pattern; the second one is where to resume + scanning the strings. If the latter is zero, the failure point is + a ``dummy''; if a failure happens and the failure point is a dummy, + it gets discarded and the next next one is tried. */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */ + fail_stack_type fail_stack; +#endif +#ifdef DEBUG + static unsigned failure_id; + unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0; +#endif + +#ifdef REL_ALLOC + /* This holds the pointer to the failure stack, when + it is allocated relocatably. */ + fail_stack_elt_t *failure_stack_ptr; +#endif + + /* We fill all the registers internally, independent of what we + return, for use in backreferences. The number here includes + an element for register zero. */ + size_t num_regs = bufp->re_nsub + 1; + + /* The currently active registers. */ + active_reg_t lowest_active_reg = NO_LOWEST_ACTIVE_REG; + active_reg_t highest_active_reg = NO_HIGHEST_ACTIVE_REG; + + /* Information on the contents of registers. These are pointers into + the input strings; they record just what was matched (on this + attempt) by a subexpression part of the pattern, that is, the + regnum-th regstart pointer points to where in the pattern we began + matching and the regnum-th regend points to right after where we + stopped matching the regnum-th subexpression. (The zeroth register + keeps track of what the whole pattern matches.) */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ + const char **regstart, **regend; +#endif + + /* If a group that's operated upon by a repetition operator fails to + match anything, then the register for its start will need to be + restored because it will have been set to wherever in the string we + are when we last see its open-group operator. Similarly for a + register's end. */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ + const char **old_regstart, **old_regend; +#endif + + /* The is_active field of reg_info helps us keep track of which (possibly + nested) subexpressions we are currently in. The matched_something + field of reg_info[reg_num] helps us tell whether or not we have + matched any of the pattern so far this time through the reg_num-th + subexpression. These two fields get reset each time through any + loop their register is in. */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */ + register_info_type *reg_info; +#endif + + /* The following record the register info as found in the above + variables when we find a match better than any we've seen before. + This happens as we backtrack through the failure points, which in + turn happens only if we have not yet matched the entire string. */ + unsigned best_regs_set = false; +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ + const char **best_regstart, **best_regend; +#endif + + /* Logically, this is `best_regend[0]'. But we don't want to have to + allocate space for that if we're not allocating space for anything + else (see below). Also, we never need info about register 0 for + any of the other register vectors, and it seems rather a kludge to + treat `best_regend' differently than the rest. So we keep track of + the end of the best match so far in a separate variable. We + initialize this to NULL so that when we backtrack the first time + and need to test it, it's not garbage. */ + const char *match_end = NULL; + + /* This helps SET_REGS_MATCHED avoid doing redundant work. */ + int set_regs_matched_done = 0; + + /* Used when we pop values we don't care about. */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ + const char **reg_dummy; + register_info_type *reg_info_dummy; +#endif + +#ifdef DEBUG + /* Counts the total number of registers pushed. */ + unsigned num_regs_pushed = 0; +#endif + + DEBUG_PRINT1 ("\n\nEntering re_match_2.\n"); + + INIT_FAIL_STACK (); + +#ifdef MATCH_MAY_ALLOCATE + /* Do not bother to initialize all the register variables if there are + no groups in the pattern, as it takes a fair amount of time. If + there are groups, we include space for register 0 (the whole + pattern), even though we never use it, since it simplifies the + array indexing. We should fix this. */ + if (bufp->re_nsub) + { + regstart = REGEX_TALLOC (num_regs, const char *); + regend = REGEX_TALLOC (num_regs, const char *); + old_regstart = REGEX_TALLOC (num_regs, const char *); + old_regend = REGEX_TALLOC (num_regs, const char *); + best_regstart = REGEX_TALLOC (num_regs, const char *); + best_regend = REGEX_TALLOC (num_regs, const char *); + reg_info = REGEX_TALLOC (num_regs, register_info_type); + reg_dummy = REGEX_TALLOC (num_regs, const char *); + reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type); + + if (!(regstart && regend && old_regstart && old_regend && reg_info + && best_regstart && best_regend && reg_dummy && reg_info_dummy)) + { + FREE_VARIABLES (); + return -2; + } + } + else + { + /* We must initialize all our variables to NULL, so that + `FREE_VARIABLES' doesn't try to free them. */ + regstart = regend = old_regstart = old_regend = best_regstart + = best_regend = reg_dummy = NULL; + reg_info = reg_info_dummy = (register_info_type *) NULL; + } +#endif /* MATCH_MAY_ALLOCATE */ + + /* The starting position is bogus. */ + if (pos < 0 || pos > size1 + size2) + { + FREE_VARIABLES (); + return -1; + } + + /* Initialize subexpression text positions to -1 to mark ones that no + start_memory/stop_memory has been seen for. Also initialize the + register information struct. */ + for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++) + { + regstart[mcnt] = regend[mcnt] + = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE; + + REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE; + IS_ACTIVE (reg_info[mcnt]) = 0; + MATCHED_SOMETHING (reg_info[mcnt]) = 0; + EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0; + } + + /* We move `string1' into `string2' if the latter's empty -- but not if + `string1' is null. */ + if (size2 == 0 && string1 != NULL) + { + string2 = string1; + size2 = size1; + string1 = 0; + size1 = 0; + } + end1 = string1 + size1; + end2 = string2 + size2; + + /* Compute where to stop matching, within the two strings. */ + if (stop <= size1) + { + end_match_1 = string1 + stop; + end_match_2 = string2; + } + else + { + end_match_1 = end1; + end_match_2 = string2 + stop - size1; + } + + /* `p' scans through the pattern as `d' scans through the data. + `dend' is the end of the input string that `d' points within. `d' + is advanced into the following input string whenever necessary, but + this happens before fetching; therefore, at the beginning of the + loop, `d' can be pointing at the end of a string, but it cannot + equal `string2'. */ + if (size1 > 0 && pos <= size1) + { + d = string1 + pos; + dend = end_match_1; + } + else + { + d = string2 + pos - size1; + dend = end_match_2; + } + + DEBUG_PRINT1 ("The compiled pattern is:\n"); + DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend); + DEBUG_PRINT1 ("The string to match is: `"); + DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2); + DEBUG_PRINT1 ("'\n"); + + /* This loops over pattern commands. It exits by returning from the + function if the match is complete, or it drops through if the match + fails at this starting point in the input data. */ + for (;;) + { +#ifdef _LIBC + DEBUG_PRINT2 ("\n%p: ", p); +#else + DEBUG_PRINT2 ("\n0x%x: ", p); +#endif + + if (p == pend) + { /* End of pattern means we might have succeeded. */ + DEBUG_PRINT1 ("end of pattern ... "); + + /* If we haven't matched the entire string, and we want the + longest match, try backtracking. */ + if (d != end_match_2) + { + /* 1 if this match ends in the same string (string1 or string2) + as the best previous match. */ + boolean same_str_p = (FIRST_STRING_P (match_end) + == MATCHING_IN_FIRST_STRING); + /* 1 if this match is the best seen so far. */ + boolean best_match_p; + + /* AIX compiler got confused when this was combined + with the previous declaration. */ + if (same_str_p) + best_match_p = d > match_end; + else + best_match_p = !MATCHING_IN_FIRST_STRING; + + DEBUG_PRINT1 ("backtracking.\n"); + + if (!FAIL_STACK_EMPTY ()) + { /* More failure points to try. */ + + /* If exceeds best match so far, save it. */ + if (!best_regs_set || best_match_p) + { + best_regs_set = true; + match_end = d; + + DEBUG_PRINT1 ("\nSAVING match as best so far.\n"); + + for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++) + { + best_regstart[mcnt] = regstart[mcnt]; + best_regend[mcnt] = regend[mcnt]; + } + } + goto fail; + } + + /* If no failure points, don't restore garbage. And if + last match is real best match, don't restore second + best one. */ + else if (best_regs_set && !best_match_p) + { + restore_best_regs: + /* Restore best match. It may happen that `dend == + end_match_1' while the restored d is in string2. + For example, the pattern `x.*y.*z' against the + strings `x-' and `y-z-', if the two strings are + not consecutive in memory. */ + DEBUG_PRINT1 ("Restoring best registers.\n"); + + d = match_end; + dend = ((d >= string1 && d <= end1) + ? end_match_1 : end_match_2); + + for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++) + { + regstart[mcnt] = best_regstart[mcnt]; + regend[mcnt] = best_regend[mcnt]; + } + } + } /* d != end_match_2 */ + + succeed_label: + DEBUG_PRINT1 ("Accepting match.\n"); + + /* If caller wants register contents data back, do it. */ + if (regs && !bufp->no_sub) + { + /* Have the register data arrays been allocated? */ + if (bufp->regs_allocated == REGS_UNALLOCATED) + { /* No. So allocate them with malloc. We need one + extra element beyond `num_regs' for the `-1' marker + GNU code uses. */ + regs->num_regs = MAX (RE_NREGS, num_regs + 1); + regs->start = TALLOC (regs->num_regs, regoff_t); + regs->end = TALLOC (regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + { + FREE_VARIABLES (); + return -2; + } + bufp->regs_allocated = REGS_REALLOCATE; + } + else if (bufp->regs_allocated == REGS_REALLOCATE) + { /* Yes. If we need more elements than were already + allocated, reallocate them. If we need fewer, just + leave it alone. */ + if (regs->num_regs < num_regs + 1) + { + regs->num_regs = num_regs + 1; + RETALLOC (regs->start, regs->num_regs, regoff_t); + RETALLOC (regs->end, regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + { + FREE_VARIABLES (); + return -2; + } + } + } + else + { + /* These braces fend off a "empty body in an else-statement" + warning under GCC when assert expands to nothing. */ + assert (bufp->regs_allocated == REGS_FIXED); + } + + /* Convert the pointer data in `regstart' and `regend' to + indices. Register zero has to be set differently, + since we haven't kept track of any info for it. */ + if (regs->num_regs > 0) + { + regs->start[0] = pos; + regs->end[0] = (MATCHING_IN_FIRST_STRING + ? ((regoff_t) (d - string1)) + : ((regoff_t) (d - string2 + size1))); + } + + /* Go through the first `min (num_regs, regs->num_regs)' + registers, since that is all we initialized. */ + for (mcnt = 1; (unsigned) mcnt < MIN (num_regs, regs->num_regs); + mcnt++) + { + if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt])) + regs->start[mcnt] = regs->end[mcnt] = -1; + else + { + regs->start[mcnt] + = (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]); + regs->end[mcnt] + = (regoff_t) POINTER_TO_OFFSET (regend[mcnt]); + } + } + + /* If the regs structure we return has more elements than + were in the pattern, set the extra elements to -1. If + we (re)allocated the registers, this is the case, + because we always allocate enough to have at least one + -1 at the end. */ + for (mcnt = num_regs; (unsigned) mcnt < regs->num_regs; mcnt++) + regs->start[mcnt] = regs->end[mcnt] = -1; + } /* regs && !bufp->no_sub */ + + DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", + nfailure_points_pushed, nfailure_points_popped, + nfailure_points_pushed - nfailure_points_popped); + DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); + + mcnt = d - pos - (MATCHING_IN_FIRST_STRING + ? string1 + : string2 - size1); + + DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt); + + FREE_VARIABLES (); + return mcnt; + } + + /* Otherwise match next pattern command. */ + switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++)) + { + /* Ignore these. Used to ignore the n of succeed_n's which + currently have n == 0. */ + case no_op: + DEBUG_PRINT1 ("EXECUTING no_op.\n"); + break; + + case succeed: + DEBUG_PRINT1 ("EXECUTING succeed.\n"); + goto succeed_label; + + /* Match the next n pattern characters exactly. The following + byte in the pattern defines n, and the n bytes after that + are the characters to match. */ + case exactn: + mcnt = *p++; + DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt); + + /* This is written out as an if-else so we don't waste time + testing `translate' inside the loop. */ + if (translate) + { + do + { + PREFETCH (); + if ((unsigned char) translate[(unsigned char) *d++] + != (unsigned char) *p++) + goto fail; + } + while (--mcnt); + } + else + { + do + { + PREFETCH (); + if (*d++ != (char) *p++) goto fail; + } + while (--mcnt); + } + SET_REGS_MATCHED (); + break; + + + /* Match any character except possibly a newline or a null. */ + case anychar: + DEBUG_PRINT1 ("EXECUTING anychar.\n"); + + PREFETCH (); + + if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n') + || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000')) + goto fail; + + SET_REGS_MATCHED (); + DEBUG_PRINT2 (" Matched `%d'.\n", *d); + d++; + break; + + + case charset: + case charset_not: + { + register unsigned char c; + boolean not = (re_opcode_t) *(p - 1) == charset_not; + + DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : ""); + + PREFETCH (); + c = TRANSLATE (*d); /* The character to match. */ + + /* Cast to `unsigned' instead of `unsigned char' in case the + bit list is a full 32 bytes long. */ + if (c < (unsigned) (*p * BYTEWIDTH) + && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + p += 1 + *p; + + if (!not) goto fail; + + SET_REGS_MATCHED (); + d++; + break; + } + + + /* The beginning of a group is represented by start_memory. + The arguments are the register number in the next byte, and the + number of groups inner to this one in the next. The text + matched within the group is recorded (in the internal + registers data structure) under the register number. */ + case start_memory: + DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]); + + /* Find out if this group can match the empty string. */ + p1 = p; /* To send to group_match_null_string_p. */ + + if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[*p]) + = group_match_null_string_p (&p1, pend, reg_info); + + /* Save the position in the string where we were the last time + we were at this open-group operator in case the group is + operated upon by a repetition operator, e.g., with `(a*)*b' + against `ab'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regstart[*p]) ? d : regstart[*p] + : regstart[*p]; + DEBUG_PRINT2 (" old_regstart: %d\n", + POINTER_TO_OFFSET (old_regstart[*p])); + + regstart[*p] = d; + DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p])); + + IS_ACTIVE (reg_info[*p]) = 1; + MATCHED_SOMETHING (reg_info[*p]) = 0; + + /* Clear this whenever we change the register activity status. */ + set_regs_matched_done = 0; + + /* This is the new highest active register. */ + highest_active_reg = *p; + + /* If nothing was active before, this is the new lowest active + register. */ + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *p; + + /* Move past the register number and inner group count. */ + p += 2; + just_past_start_mem = p; + + break; + + + /* The stop_memory opcode represents the end of a group. Its + arguments are the same as start_memory's: the register + number, and the number of inner groups. */ + case stop_memory: + DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]); + + /* We need to save the string position the last time we were at + this close-group operator in case the group is operated + upon by a repetition operator, e.g., with `((a*)*(b*)*)*' + against `aba'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regend[*p]) ? d : regend[*p] + : regend[*p]; + DEBUG_PRINT2 (" old_regend: %d\n", + POINTER_TO_OFFSET (old_regend[*p])); + + regend[*p] = d; + DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p])); + + /* This register isn't active anymore. */ + IS_ACTIVE (reg_info[*p]) = 0; + + /* Clear this whenever we change the register activity status. */ + set_regs_matched_done = 0; + + /* If this was the only register active, nothing is active + anymore. */ + if (lowest_active_reg == highest_active_reg) + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + { /* We must scan for the new highest active register, since + it isn't necessarily one less than now: consider + (a(b)c(d(e)f)g). When group 3 ends, after the f), the + new highest active register is 1. */ + unsigned char r = *p - 1; + while (r > 0 && !IS_ACTIVE (reg_info[r])) + r--; + + /* If we end up at register zero, that means that we saved + the registers as the result of an `on_failure_jump', not + a `start_memory', and we jumped to past the innermost + `stop_memory'. For example, in ((.)*) we save + registers 1 and 2 as a result of the *, but when we pop + back to the second ), we are at the stop_memory 1. + Thus, nothing is active. */ + if (r == 0) + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + highest_active_reg = r; + } + + /* If just failed to match something this time around with a + group that's operated on by a repetition operator, try to + force exit from the ``loop'', and restore the register + information for this group that we had before trying this + last match. */ + if ((!MATCHED_SOMETHING (reg_info[*p]) + || just_past_start_mem == p - 1) + && (p + 2) < pend) + { + boolean is_a_jump_n = false; + + p1 = p + 2; + mcnt = 0; + switch ((re_opcode_t) *p1++) + { + case jump_n: + is_a_jump_n = true; + case pop_failure_jump: + case maybe_pop_jump: + case jump: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if (is_a_jump_n) + p1 += 2; + break; + + default: + /* do nothing */ ; + } + p1 += mcnt; + + /* If the next operation is a jump backwards in the pattern + to an on_failure_jump right before the start_memory + corresponding to this stop_memory, exit from the loop + by forcing a failure after pushing on the stack the + on_failure_jump's jump in the pattern, and d. */ + if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump + && (re_opcode_t) p1[3] == start_memory && p1[4] == *p) + { + /* If this group ever matched anything, then restore + what its registers were before trying this last + failed match, e.g., with `(a*)*b' against `ab' for + regstart[1], and, e.g., with `((a*)*(b*)*)*' + against `aba' for regend[3]. + + Also restore the registers for inner groups for, + e.g., `((a*)(b*))*' against `aba' (register 3 would + otherwise get trashed). */ + + if (EVER_MATCHED_SOMETHING (reg_info[*p])) + { + unsigned r; + + EVER_MATCHED_SOMETHING (reg_info[*p]) = 0; + + /* Restore this and inner groups' (if any) registers. */ + for (r = *p; r < (unsigned) *p + (unsigned) *(p + 1); + r++) + { + regstart[r] = old_regstart[r]; + + /* xx why this test? */ + if (old_regend[r] >= regstart[r]) + regend[r] = old_regend[r]; + } + } + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + PUSH_FAILURE_POINT (p1 + mcnt, d, -2); + + goto fail; + } + } + + /* Move past the register number and the inner group count. */ + p += 2; + break; + + + /* \ has been turned into a `duplicate' command which is + followed by the numeric value of as the register number. */ + case duplicate: + { + register const char *d2, *dend2; + int regno = *p++; /* Get which register to match against. */ + DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno); + + /* Can't back reference a group which we've never matched. */ + if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno])) + goto fail; + + /* Where in input to try to start matching. */ + d2 = regstart[regno]; + + /* Where to stop matching; if both the place to start and + the place to stop matching are in the same string, then + set to the place to stop, otherwise, for now have to use + the end of the first string. */ + + dend2 = ((FIRST_STRING_P (regstart[regno]) + == FIRST_STRING_P (regend[regno])) + ? regend[regno] : end_match_1); + for (;;) + { + /* If necessary, advance to next segment in register + contents. */ + while (d2 == dend2) + { + if (dend2 == end_match_2) break; + if (dend2 == regend[regno]) break; + + /* End of string1 => advance to string2. */ + d2 = string2; + dend2 = regend[regno]; + } + /* At end of register contents => success */ + if (d2 == dend2) break; + + /* If necessary, advance to next segment in data. */ + PREFETCH (); + + /* How many characters left in this segment to match. */ + mcnt = dend - d; + + /* Want how many consecutive characters we can match in + one shot, so, if necessary, adjust the count. */ + if (mcnt > dend2 - d2) + mcnt = dend2 - d2; + + /* Compare that many; failure if mismatch, else move + past them. */ + if (translate + ? bcmp_translate (d, d2, mcnt, translate) + : memcmp (d, d2, mcnt)) + goto fail; + d += mcnt, d2 += mcnt; + + /* Do this because we've match some characters. */ + SET_REGS_MATCHED (); + } + } + break; + + + /* begline matches the empty string at the beginning of the string + (unless `not_bol' is set in `bufp'), and, if + `newline_anchor' is set, after newlines. */ + case begline: + DEBUG_PRINT1 ("EXECUTING begline.\n"); + + if (AT_STRINGS_BEG (d)) + { + if (!bufp->not_bol) break; + } + else if (d[-1] == '\n' && bufp->newline_anchor) + { + break; + } + /* In all other cases, we fail. */ + goto fail; + + + /* endline is the dual of begline. */ + case endline: + DEBUG_PRINT1 ("EXECUTING endline.\n"); + + if (AT_STRINGS_END (d)) + { + if (!bufp->not_eol) break; + } + + /* We have to ``prefetch'' the next character. */ + else if ((d == end1 ? *string2 : *d) == '\n' + && bufp->newline_anchor) + { + break; + } + goto fail; + + + /* Match at the very beginning of the data. */ + case begbuf: + DEBUG_PRINT1 ("EXECUTING begbuf.\n"); + if (AT_STRINGS_BEG (d)) + break; + goto fail; + + + /* Match at the very end of the data. */ + case endbuf: + DEBUG_PRINT1 ("EXECUTING endbuf.\n"); + if (AT_STRINGS_END (d)) + break; + goto fail; + + + /* on_failure_keep_string_jump is used to optimize `.*\n'. It + pushes NULL as the value for the string on the stack. Then + `pop_failure_point' will keep the current value for the + string, instead of restoring it. To see why, consider + matching `foo\nbar' against `.*\n'. The .* matches the foo; + then the . fails against the \n. But the next thing we want + to do is match the \n against the \n; if we restored the + string value, we would be back at the foo. + + Because this is used only in specific cases, we don't need to + check all the things that `on_failure_jump' does, to make + sure the right things get saved on the stack. Hence we don't + share its code. The only reason to push anything on the + stack at all is that otherwise we would have to change + `anychar's code to do something besides goto fail in this + case; that seems worse than this. */ + case on_failure_keep_string_jump: + DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); +#ifdef _LIBC + DEBUG_PRINT3 (" %d (to %p):\n", mcnt, p + mcnt); +#else + DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt); +#endif + + PUSH_FAILURE_POINT (p + mcnt, NULL, -2); + break; + + + /* Uses of on_failure_jump: + + Each alternative starts with an on_failure_jump that points + to the beginning of the next alternative. Each alternative + except the last ends with a jump that in effect jumps past + the rest of the alternatives. (They really jump to the + ending jump of the following alternative, because tensioning + these jumps is a hassle.) + + Repeats start with an on_failure_jump that points past both + the repetition text and either the following jump or + pop_failure_jump back to this on_failure_jump. */ + case on_failure_jump: + on_failure: + DEBUG_PRINT1 ("EXECUTING on_failure_jump"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); +#ifdef _LIBC + DEBUG_PRINT3 (" %d (to %p)", mcnt, p + mcnt); +#else + DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt); +#endif + + /* If this on_failure_jump comes right before a group (i.e., + the original * applied to a group), save the information + for that group and all inner ones, so that if we fail back + to this point, the group's information will be correct. + For example, in \(a*\)*\1, we need the preceding group, + and in \(zz\(a*\)b*\)\2, we need the inner group. */ + + /* We can't use `p' to check ahead because we push + a failure point to `p + mcnt' after we do this. */ + p1 = p; + + /* We need to skip no_op's before we look for the + start_memory in case this on_failure_jump is happening as + the result of a completed succeed_n, as in \(a\)\{1,3\}b\1 + against aba. */ + while (p1 < pend && (re_opcode_t) *p1 == no_op) + p1++; + + if (p1 < pend && (re_opcode_t) *p1 == start_memory) + { + /* We have a new highest active register now. This will + get reset at the start_memory we are about to get to, + but we will have saved all the registers relevant to + this repetition op, as described above. */ + highest_active_reg = *(p1 + 1) + *(p1 + 2); + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *(p1 + 1); + } + + DEBUG_PRINT1 (":\n"); + PUSH_FAILURE_POINT (p + mcnt, d, -2); + break; + + + /* A smart repeat ends with `maybe_pop_jump'. + We change it to either `pop_failure_jump' or `jump'. */ + case maybe_pop_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt); + { + register unsigned char *p2 = p; + + /* Compare the beginning of the repeat with what in the + pattern follows its end. If we can establish that there + is nothing that they would both match, i.e., that we + would have to backtrack because of (as in, e.g., `a*a') + then we can change to pop_failure_jump, because we'll + never have to backtrack. + + This is not true in the case of alternatives: in + `(a|ab)*' we do need to backtrack to the `ab' alternative + (e.g., if the string was `ab'). But instead of trying to + detect that here, the alternative has put on a dummy + failure point which is what we will end up popping. */ + + /* Skip over open/close-group commands. + If what follows this loop is a ...+ construct, + look at what begins its body, since we will have to + match at least one of that. */ + while (1) + { + if (p2 + 2 < pend + && ((re_opcode_t) *p2 == stop_memory + || (re_opcode_t) *p2 == start_memory)) + p2 += 3; + else if (p2 + 6 < pend + && (re_opcode_t) *p2 == dummy_failure_jump) + p2 += 6; + else + break; + } + + p1 = p + mcnt; + /* p1[0] ... p1[2] are the `on_failure_jump' corresponding + to the `maybe_finalize_jump' of this case. Examine what + follows. */ + + /* If we're at the end of the pattern, we can change. */ + if (p2 == pend) + { + /* Consider what happens when matching ":\(.*\)" + against ":/". I don't really understand this code + yet. */ + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 + (" End of pattern: change to `pop_failure_jump'.\n"); + } + + else if ((re_opcode_t) *p2 == exactn + || (bufp->newline_anchor && (re_opcode_t) *p2 == endline)) + { + register unsigned char c + = *p2 == (unsigned char) endline ? '\n' : p2[2]; + + if ((re_opcode_t) p1[3] == exactn && p1[5] != c) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", + c, p1[5]); + } + + else if ((re_opcode_t) p1[3] == charset + || (re_opcode_t) p1[3] == charset_not) + { + int not = (re_opcode_t) p1[3] == charset_not; + + if (c < (unsigned char) (p1[4] * BYTEWIDTH) + && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + /* `not' is equal to 1 if c would match, which means + that we can't change to pop_failure_jump. */ + if (!not) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } + } + } + else if ((re_opcode_t) *p2 == charset) + { +#ifdef DEBUG + register unsigned char c + = *p2 == (unsigned char) endline ? '\n' : p2[2]; +#endif + +#if 0 + if ((re_opcode_t) p1[3] == exactn + && ! ((int) p2[1] * BYTEWIDTH > (int) p1[5] + && (p2[2 + p1[5] / BYTEWIDTH] + & (1 << (p1[5] % BYTEWIDTH))))) +#else + if ((re_opcode_t) p1[3] == exactn + && ! ((int) p2[1] * BYTEWIDTH > (int) p1[4] + && (p2[2 + p1[4] / BYTEWIDTH] + & (1 << (p1[4] % BYTEWIDTH))))) +#endif + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", + c, p1[5]); + } + + else if ((re_opcode_t) p1[3] == charset_not) + { + int idx; + /* We win if the charset_not inside the loop + lists every character listed in the charset after. */ + for (idx = 0; idx < (int) p2[1]; idx++) + if (! (p2[2 + idx] == 0 + || (idx < (int) p1[4] + && ((p2[2 + idx] & ~ p1[5 + idx]) == 0)))) + break; + + if (idx == p2[1]) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } + } + else if ((re_opcode_t) p1[3] == charset) + { + int idx; + /* We win if the charset inside the loop + has no overlap with the one after the loop. */ + for (idx = 0; + idx < (int) p2[1] && idx < (int) p1[4]; + idx++) + if ((p2[2 + idx] & p1[5 + idx]) != 0) + break; + + if (idx == p2[1] || idx == p1[4]) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } + } + } + } + p -= 2; /* Point at relative address again. */ + if ((re_opcode_t) p[-1] != pop_failure_jump) + { + p[-1] = (unsigned char) jump; + DEBUG_PRINT1 (" Match => jump.\n"); + goto unconditional_jump; + } + /* Note fall through. */ + + + /* The end of a simple repeat has a pop_failure_jump back to + its matching on_failure_jump, where the latter will push a + failure point. The pop_failure_jump takes off failure + points put on by this pop_failure_jump's matching + on_failure_jump; we got through the pattern to here from the + matching on_failure_jump, so didn't fail. */ + case pop_failure_jump: + { + /* We need to pass separate storage for the lowest and + highest registers, even though we don't care about the + actual values. Otherwise, we will restore only one + register from the stack, since lowest will == highest in + `pop_failure_point'. */ + active_reg_t dummy_low_reg, dummy_high_reg; + unsigned char *pdummy; + const char *sdummy; + + DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n"); + POP_FAILURE_POINT (sdummy, pdummy, + dummy_low_reg, dummy_high_reg, + reg_dummy, reg_dummy, reg_info_dummy); + } + /* Note fall through. */ + + unconditional_jump: +#ifdef _LIBC + DEBUG_PRINT2 ("\n%p: ", p); +#else + DEBUG_PRINT2 ("\n0x%x: ", p); +#endif + /* Note fall through. */ + + /* Unconditionally jump (without popping any failure points). */ + case jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */ + DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt); + p += mcnt; /* Do the jump. */ +#ifdef _LIBC + DEBUG_PRINT2 ("(to %p).\n", p); +#else + DEBUG_PRINT2 ("(to 0x%x).\n", p); +#endif + break; + + + /* We need this opcode so we can detect where alternatives end + in `group_match_null_string_p' et al. */ + case jump_past_alt: + DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n"); + goto unconditional_jump; + + + /* Normally, the on_failure_jump pushes a failure point, which + then gets popped at pop_failure_jump. We will end up at + pop_failure_jump, also, and with a pattern of, say, `a+', we + are skipping over the on_failure_jump, so we have to push + something meaningless for pop_failure_jump to pop. */ + case dummy_failure_jump: + DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n"); + /* It doesn't matter what we push for the string here. What + the code at `fail' tests is the value for the pattern. */ + PUSH_FAILURE_POINT (NULL, NULL, -2); + goto unconditional_jump; + + + /* At the end of an alternative, we need to push a dummy failure + point in case we are followed by a `pop_failure_jump', because + we don't want the failure point for the alternative to be + popped. For example, matching `(a|ab)*' against `aab' + requires that we match the `ab' alternative. */ + case push_dummy_failure: + DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n"); + /* See comments just above at `dummy_failure_jump' about the + two zeroes. */ + PUSH_FAILURE_POINT (NULL, NULL, -2); + break; + + /* Have to succeed matching what follows at least n times. + After that, handle like `on_failure_jump'. */ + case succeed_n: + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt); + + assert (mcnt >= 0); + /* Originally, this is how many times we HAVE to succeed. */ + if (mcnt > 0) + { + mcnt--; + p += 2; + STORE_NUMBER_AND_INCR (p, mcnt); +#ifdef _LIBC + DEBUG_PRINT3 (" Setting %p to %d.\n", p - 2, mcnt); +#else + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p - 2, mcnt); +#endif + } + else if (mcnt == 0) + { +#ifdef _LIBC + DEBUG_PRINT2 (" Setting two bytes from %p to no_op.\n", p+2); +#else + DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2); +#endif + p[2] = (unsigned char) no_op; + p[3] = (unsigned char) no_op; + goto on_failure; + } + break; + + case jump_n: + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt); + + /* Originally, this is how many times we CAN jump. */ + if (mcnt) + { + mcnt--; + STORE_NUMBER (p + 2, mcnt); +#ifdef _LIBC + DEBUG_PRINT3 (" Setting %p to %d.\n", p + 2, mcnt); +#else + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p + 2, mcnt); +#endif + goto unconditional_jump; + } + /* If don't have to jump any more, skip over the rest of command. */ + else + p += 4; + break; + + case set_number_at: + { + DEBUG_PRINT1 ("EXECUTING set_number_at.\n"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + p1 = p + mcnt; + EXTRACT_NUMBER_AND_INCR (mcnt, p); +#ifdef _LIBC + DEBUG_PRINT3 (" Setting %p to %d.\n", p1, mcnt); +#else + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt); +#endif + STORE_NUMBER (p1, mcnt); + break; + } + +#if 0 + /* The DEC Alpha C compiler 3.x generates incorrect code for the + test WORDCHAR_P (d - 1) != WORDCHAR_P (d) in the expansion of + AT_WORD_BOUNDARY, so this code is disabled. Expanding the + macro and introducing temporary variables works around the bug. */ + + case wordbound: + DEBUG_PRINT1 ("EXECUTING wordbound.\n"); + if (AT_WORD_BOUNDARY (d)) + break; + goto fail; + + case notwordbound: + DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); + if (AT_WORD_BOUNDARY (d)) + goto fail; + break; +#else + case wordbound: + { + boolean prevchar, thischar; + + DEBUG_PRINT1 ("EXECUTING wordbound.\n"); + if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)) + break; + + prevchar = WORDCHAR_P (d - 1); + thischar = WORDCHAR_P (d); + if (prevchar != thischar) + break; + goto fail; + } + + case notwordbound: + { + boolean prevchar, thischar; + + DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); + if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)) + goto fail; + + prevchar = WORDCHAR_P (d - 1); + thischar = WORDCHAR_P (d); + if (prevchar != thischar) + goto fail; + break; + } +#endif + + case wordbeg: + DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); + if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1))) + break; + goto fail; + + case wordend: + DEBUG_PRINT1 ("EXECUTING wordend.\n"); + if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1) + && (!WORDCHAR_P (d) || AT_STRINGS_END (d))) + break; + goto fail; + +#ifdef emacs + case before_dot: + DEBUG_PRINT1 ("EXECUTING before_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) >= point) + goto fail; + break; + + case at_dot: + DEBUG_PRINT1 ("EXECUTING at_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) != point) + goto fail; + break; + + case after_dot: + DEBUG_PRINT1 ("EXECUTING after_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) <= point) + goto fail; + break; + + case syntaxspec: + DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt); + mcnt = *p++; + goto matchsyntax; + + case wordchar: + DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n"); + mcnt = (int) Sword; + matchsyntax: + PREFETCH (); + /* Can't use *d++ here; SYNTAX may be an unsafe macro. */ + d++; + if (SYNTAX (d[-1]) != (enum syntaxcode) mcnt) + goto fail; + SET_REGS_MATCHED (); + break; + + case notsyntaxspec: + DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt); + mcnt = *p++; + goto matchnotsyntax; + + case notwordchar: + DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n"); + mcnt = (int) Sword; + matchnotsyntax: + PREFETCH (); + /* Can't use *d++ here; SYNTAX may be an unsafe macro. */ + d++; + if (SYNTAX (d[-1]) == (enum syntaxcode) mcnt) + goto fail; + SET_REGS_MATCHED (); + break; + +#else /* not emacs */ + case wordchar: + DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n"); + PREFETCH (); + if (!WORDCHAR_P (d)) + goto fail; + SET_REGS_MATCHED (); + d++; + break; + + case notwordchar: + DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n"); + PREFETCH (); + if (WORDCHAR_P (d)) + goto fail; + SET_REGS_MATCHED (); + d++; + break; +#endif /* not emacs */ + + default: + abort (); + } + continue; /* Successfully executed one pattern command; keep going. */ + + + /* We goto here if a matching operation fails. */ + fail: + if (!FAIL_STACK_EMPTY ()) + { /* A restart point is known. Restore to that state. */ + DEBUG_PRINT1 ("\nFAIL:\n"); + POP_FAILURE_POINT (d, p, + lowest_active_reg, highest_active_reg, + regstart, regend, reg_info); + + /* If this failure point is a dummy, try the next one. */ + if (!p) + goto fail; + + /* If we failed to the end of the pattern, don't examine *p. */ + assert (p <= pend); + if (p < pend) + { + boolean is_a_jump_n = false; + + /* If failed to a backwards jump that's part of a repetition + loop, need to pop this failure point and use the next one. */ + switch ((re_opcode_t) *p) + { + case jump_n: + is_a_jump_n = true; + case maybe_pop_jump: + case pop_failure_jump: + case jump: + p1 = p + 1; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + + if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n) + || (!is_a_jump_n + && (re_opcode_t) *p1 == on_failure_jump)) + goto fail; + break; + default: + /* do nothing */ ; + } + } + + if (d >= string1 && d <= end1) + dend = end_match_1; + } + else + break; /* Matching at this starting point really fails. */ + } /* for (;;) */ + + if (best_regs_set) + goto restore_best_regs; + + FREE_VARIABLES (); + + return -1; /* Failure to match. */ +} /* re_match_2 */ + +/* Subroutine definitions for re_match_2. */ + + +/* We are passed P pointing to a register number after a start_memory. + + Return true if the pattern up to the corresponding stop_memory can + match the empty string, and false otherwise. + + If we find the matching stop_memory, sets P to point to one past its number. + Otherwise, sets P to an undefined byte less than or equal to END. + + We don't handle duplicates properly (yet). */ + +static boolean +group_match_null_string_p (p, end, reg_info) + unsigned char **p, *end; + register_info_type *reg_info; +{ + int mcnt; + /* Point to after the args to the start_memory. */ + unsigned char *p1 = *p + 2; + + while (p1 < end) + { + /* Skip over opcodes that can match nothing, and return true or + false, as appropriate, when we get to one that can't, or to the + matching stop_memory. */ + + switch ((re_opcode_t) *p1) + { + /* Could be either a loop or a series of alternatives. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + /* If the next operation is not a jump backwards in the + pattern. */ + + if (mcnt >= 0) + { + /* Go through the on_failure_jumps of the alternatives, + seeing if any of the alternatives cannot match nothing. + The last alternative starts with only a jump, + whereas the rest start with on_failure_jump and end + with a jump, e.g., here is the pattern for `a|b|c': + + /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6 + /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3 + /exactn/1/c + + So, we have to first go through the first (n-1) + alternatives and then deal with the last one separately. */ + + + /* Deal with the first (n-1) alternatives, which start + with an on_failure_jump (see above) that jumps to right + past a jump_past_alt. */ + + while ((re_opcode_t) p1[mcnt-3] == jump_past_alt) + { + /* `mcnt' holds how many bytes long the alternative + is, including the ending `jump_past_alt' and + its number. */ + + if (!alt_match_null_string_p (p1, p1 + mcnt - 3, + reg_info)) + return false; + + /* Move to right after this alternative, including the + jump_past_alt. */ + p1 += mcnt; + + /* Break if it's the beginning of an n-th alternative + that doesn't begin with an on_failure_jump. */ + if ((re_opcode_t) *p1 != on_failure_jump) + break; + + /* Still have to check that it's not an n-th + alternative that starts with an on_failure_jump. */ + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if ((re_opcode_t) p1[mcnt-3] != jump_past_alt) + { + /* Get to the beginning of the n-th alternative. */ + p1 -= 3; + break; + } + } + + /* Deal with the last alternative: go back and get number + of the `jump_past_alt' just before it. `mcnt' contains + the length of the alternative. */ + EXTRACT_NUMBER (mcnt, p1 - 2); + + if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info)) + return false; + + p1 += mcnt; /* Get past the n-th alternative. */ + } /* if mcnt > 0 */ + break; + + + case stop_memory: + assert (p1[1] == **p); + *p = p1 + 2; + return true; + + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return false; + } + } /* while p1 < end */ + + return false; +} /* group_match_null_string_p */ + + +/* Similar to group_match_null_string_p, but doesn't deal with alternatives: + It expects P to be the first byte of a single alternative and END one + byte past the last. The alternative can contain groups. */ + +static boolean +alt_match_null_string_p (p, end, reg_info) + unsigned char *p, *end; + register_info_type *reg_info; +{ + int mcnt; + unsigned char *p1 = p; + + while (p1 < end) + { + /* Skip over opcodes that can match nothing, and break when we get + to one that can't. */ + + switch ((re_opcode_t) *p1) + { + /* It's a loop. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + break; + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return false; + } + } /* while p1 < end */ + + return true; +} /* alt_match_null_string_p */ + + +/* Deals with the ops common to group_match_null_string_p and + alt_match_null_string_p. + + Sets P to one after the op and its arguments, if any. */ + +static boolean +common_op_match_null_string_p (p, end, reg_info) + unsigned char **p, *end; + register_info_type *reg_info; +{ + int mcnt; + boolean ret; + int reg_no; + unsigned char *p1 = *p; + + switch ((re_opcode_t) *p1++) + { + case no_op: + case begline: + case endline: + case begbuf: + case endbuf: + case wordbeg: + case wordend: + case wordbound: + case notwordbound: +#ifdef emacs + case before_dot: + case at_dot: + case after_dot: +#endif + break; + + case start_memory: + reg_no = *p1; + assert (reg_no > 0 && reg_no <= MAX_REGNUM); + ret = group_match_null_string_p (&p1, end, reg_info); + + /* Have to set this here in case we're checking a group which + contains a group and a back reference to it. */ + + if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret; + + if (!ret) + return false; + break; + + /* If this is an optimized succeed_n for zero times, make the jump. */ + case jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if (mcnt >= 0) + p1 += mcnt; + else + return false; + break; + + case succeed_n: + /* Get to the number of times to succeed. */ + p1 += 2; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + if (mcnt == 0) + { + p1 -= 4; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + } + else + return false; + break; + + case duplicate: + if (!REG_MATCH_NULL_STRING_P (reg_info[*p1])) + return false; + break; + + case set_number_at: + p1 += 4; + + default: + /* All other opcodes mean we cannot match the empty string. */ + return false; + } + + *p = p1; + return true; +} /* common_op_match_null_string_p */ + + +/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN + bytes; nonzero otherwise. */ + +static int +bcmp_translate (s1, s2, len, translate) + const char *s1, *s2; + register int len; + RE_TRANSLATE_TYPE translate; +{ + register const unsigned char *p1 = (const unsigned char *) s1; + register const unsigned char *p2 = (const unsigned char *) s2; + while (len) + { + if (translate[*p1++] != translate[*p2++]) return 1; + len--; + } + return 0; +} + +/* Entry points for GNU code. */ + +/* re_compile_pattern is the GNU regular expression compiler: it + compiles PATTERN (of length SIZE) and puts the result in BUFP. + Returns 0 if the pattern was valid, otherwise an error string. + + Assumes the `allocated' (and perhaps `buffer') and `translate' fields + are set in BUFP on entry. + + We call regex_compile to do the actual compilation. */ + +const char * +re_compile_pattern (pattern, length, bufp) + const char *pattern; + size_t length; + struct re_pattern_buffer *bufp; +{ + reg_errcode_t ret; + + /* GNU code is written to assume at least RE_NREGS registers will be set + (and at least one extra will be -1). */ + bufp->regs_allocated = REGS_UNALLOCATED; + + /* And GNU code determines whether or not to get register information + by passing null for the REGS argument to re_match, etc., not by + setting no_sub. */ + bufp->no_sub = 0; + + /* Match anchors at newline. */ + bufp->newline_anchor = 1; + + ret = regex_compile (pattern, length, re_syntax_options, bufp); + + if (!ret) + return NULL; + return gettext (re_error_msgid + re_error_msgid_idx[(int) ret]); +} +#ifdef _LIBC +weak_alias (__re_compile_pattern, re_compile_pattern) +#endif + +/* Entry points compatible with 4.2 BSD regex library. We don't define + them unless specifically requested. */ + +#if defined _REGEX_RE_COMP || defined _LIBC + +/* BSD has one and only one pattern buffer. */ +static struct re_pattern_buffer re_comp_buf; + +char * +#ifdef _LIBC +/* Make these definitions weak in libc, so POSIX programs can redefine + these names if they don't use our functions, and still use + regcomp/regexec below without link errors. */ +weak_function +#endif +re_comp (s) + const char *s; +{ + reg_errcode_t ret; + + if (!s) + { + if (!re_comp_buf.buffer) + return gettext ("No previous regular expression"); + return 0; + } + + if (!re_comp_buf.buffer) + { + re_comp_buf.buffer = (unsigned char *) malloc (200); + if (re_comp_buf.buffer == NULL) + return (char *) gettext (re_error_msgid + + re_error_msgid_idx[(int) REG_ESPACE]); + re_comp_buf.allocated = 200; + + re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH); + if (re_comp_buf.fastmap == NULL) + return (char *) gettext (re_error_msgid + + re_error_msgid_idx[(int) REG_ESPACE]); + } + + /* Since `re_exec' always passes NULL for the `regs' argument, we + don't need to initialize the pattern buffer fields which affect it. */ + + /* Match anchors at newlines. */ + re_comp_buf.newline_anchor = 1; + + ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); + + if (!ret) + return NULL; + + /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ + return (char *) gettext (re_error_msgid + re_error_msgid_idx[(int) ret]); +} + + +int +#ifdef _LIBC +weak_function +#endif +re_exec (s) + const char *s; +{ + const int len = strlen (s); + return + 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0); +} + +#endif /* _REGEX_RE_COMP */ + +/* POSIX.2 functions. Don't define these for Emacs. */ + +#ifndef emacs + +/* regcomp takes a regular expression as a string and compiles it. + + PREG is a regex_t *. We do not expect any fields to be initialized, + since POSIX says we shouldn't. Thus, we set + + `buffer' to the compiled pattern; + `used' to the length of the compiled pattern; + `syntax' to RE_SYNTAX_POSIX_EXTENDED if the + REG_EXTENDED bit in CFLAGS is set; otherwise, to + RE_SYNTAX_POSIX_BASIC; + `newline_anchor' to REG_NEWLINE being set in CFLAGS; + `fastmap' to an allocated space for the fastmap; + `fastmap_accurate' to zero; + `re_nsub' to the number of subexpressions in PATTERN. + + PATTERN is the address of the pattern string. + + CFLAGS is a series of bits which affect compilation. + + If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we + use POSIX basic syntax. + + If REG_NEWLINE is set, then . and [^...] don't match newline. + Also, regexec will try a match beginning after every newline. + + If REG_ICASE is set, then we considers upper- and lowercase + versions of letters to be equivalent when matching. + + If REG_NOSUB is set, then when PREG is passed to regexec, that + routine will report only success or failure, and nothing about the + registers. + + It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for + the return codes and their meanings.) */ + +int +regcomp (preg, pattern, cflags) + regex_t *preg; + const char *pattern; + int cflags; +{ + reg_errcode_t ret; + reg_syntax_t syntax + = (cflags & REG_EXTENDED) ? + RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC; + + /* regex_compile will allocate the space for the compiled pattern. */ + preg->buffer = 0; + preg->allocated = 0; + preg->used = 0; + + /* Try to allocate space for the fastmap. */ + preg->fastmap = (char *) malloc (1 << BYTEWIDTH); + + if (cflags & REG_ICASE) + { + unsigned i; + + preg->translate + = (RE_TRANSLATE_TYPE) malloc (CHAR_SET_SIZE + * sizeof (*(RE_TRANSLATE_TYPE)0)); + if (preg->translate == NULL) + return (int) REG_ESPACE; + + /* Map uppercase characters to corresponding lowercase ones. */ + for (i = 0; i < CHAR_SET_SIZE; i++) + preg->translate[i] = ISUPPER (i) ? TOLOWER (i) : i; + } + else + preg->translate = NULL; + + /* If REG_NEWLINE is set, newlines are treated differently. */ + if (cflags & REG_NEWLINE) + { /* REG_NEWLINE implies neither . nor [^...] match newline. */ + syntax &= ~RE_DOT_NEWLINE; + syntax |= RE_HAT_LISTS_NOT_NEWLINE; + /* It also changes the matching behavior. */ + preg->newline_anchor = 1; + } + else + preg->newline_anchor = 0; + + preg->no_sub = !!(cflags & REG_NOSUB); + + /* POSIX says a null character in the pattern terminates it, so we + can use strlen here in compiling the pattern. */ + ret = regex_compile (pattern, strlen (pattern), syntax, preg); + + /* POSIX doesn't distinguish between an unmatched open-group and an + unmatched close-group: both are REG_EPAREN. */ + if (ret == REG_ERPAREN) ret = REG_EPAREN; + + if (ret == REG_NOERROR && preg->fastmap) + { + /* Compute the fastmap now, since regexec cannot modify the pattern + buffer. */ + if (re_compile_fastmap (preg) == -2) + { + /* Some error occured while computing the fastmap, just forget + about it. */ + free (preg->fastmap); + preg->fastmap = NULL; + } + } + + return (int) ret; +} +#ifdef _LIBC +weak_alias (__regcomp, regcomp) +#endif + + +/* regexec searches for a given pattern, specified by PREG, in the + string STRING. + + If NMATCH is zero or REG_NOSUB was set in the cflags argument to + `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at + least NMATCH elements, and we set them to the offsets of the + corresponding matched substrings. + + EFLAGS specifies `execution flags' which affect matching: if + REG_NOTBOL is set, then ^ does not match at the beginning of the + string; if REG_NOTEOL is set, then $ does not match at the end. + + We return 0 if we find a match and REG_NOMATCH if not. */ + +int +regexec (preg, string, nmatch, pmatch, eflags) + const regex_t *preg; + const char *string; + size_t nmatch; + regmatch_t pmatch[]; + int eflags; +{ + int ret; + struct re_registers regs; + regex_t private_preg; + int len = strlen (string); + boolean want_reg_info = !preg->no_sub && nmatch > 0; + + private_preg = *preg; + + private_preg.not_bol = !!(eflags & REG_NOTBOL); + private_preg.not_eol = !!(eflags & REG_NOTEOL); + + /* The user has told us exactly how many registers to return + information about, via `nmatch'. We have to pass that on to the + matching routines. */ + private_preg.regs_allocated = REGS_FIXED; + + if (want_reg_info) + { + regs.num_regs = nmatch; + regs.start = TALLOC (nmatch * 2, regoff_t); + if (regs.start == NULL) + return (int) REG_NOMATCH; + regs.end = regs.start + nmatch; + } + + /* Perform the searching operation. */ + ret = re_search (&private_preg, string, len, + /* start: */ 0, /* range: */ len, + want_reg_info ? ®s : (struct re_registers *) 0); + + /* Copy the register information to the POSIX structure. */ + if (want_reg_info) + { + if (ret >= 0) + { + unsigned r; + + for (r = 0; r < nmatch; r++) + { + pmatch[r].rm_so = regs.start[r]; + pmatch[r].rm_eo = regs.end[r]; + } + } + + /* If we needed the temporary register info, free the space now. */ + free (regs.start); + } + + /* We want zero return to mean success, unlike `re_search'. */ + return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH; +} +#ifdef _LIBC +weak_alias (__regexec, regexec) +#endif + + +/* Returns a message corresponding to an error code, ERRCODE, returned + from either regcomp or regexec. We don't use PREG here. */ + +size_t +regerror (errcode, preg, errbuf, errbuf_size) + int errcode; + const regex_t *preg; + char *errbuf; + size_t errbuf_size; +{ + const char *msg; + size_t msg_size; + + if (errcode < 0 + || errcode >= (int) (sizeof (re_error_msgid_idx) + / sizeof (re_error_msgid_idx[0]))) + /* Only error codes returned by the rest of the code should be passed + to this routine. If we are given anything else, or if other regex + code generates an invalid error code, then the program has a bug. + Dump core so we can fix it. */ + abort (); + + msg = gettext (re_error_msgid + re_error_msgid_idx[errcode]); + + msg_size = strlen (msg) + 1; /* Includes the null. */ + + if (errbuf_size != 0) + { + if (msg_size > errbuf_size) + { +#if defined HAVE_MEMPCPY || defined _LIBC + *((char *) __mempcpy (errbuf, msg, errbuf_size - 1)) = '\0'; +#else + memcpy (errbuf, msg, errbuf_size - 1); + errbuf[errbuf_size - 1] = 0; +#endif + } + else + memcpy (errbuf, msg, msg_size); + } + + return msg_size; +} +#ifdef _LIBC +weak_alias (__regerror, regerror) +#endif + + +/* Free dynamically allocated space used by PREG. */ + +void +regfree (preg) + regex_t *preg; +{ + if (preg->buffer != NULL) + free (preg->buffer); + preg->buffer = NULL; + + preg->allocated = 0; + preg->used = 0; + + if (preg->fastmap != NULL) + free (preg->fastmap); + preg->fastmap = NULL; + preg->fastmap_accurate = 0; + + if (preg->translate != NULL) + free (preg->translate); + preg->translate = NULL; +} +#ifdef _LIBC +weak_alias (__regfree, regfree) +#endif + +#endif /* not emacs */ diff --git a/lib/routemap.c b/lib/routemap.c new file mode 100644 index 00000000..b000f2fc --- /dev/null +++ b/lib/routemap.c @@ -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 + +#include "linklist.h" +#include "memory.h" +#include "vector.h" +#include "prefix.h" +#include "routemap.h" +#include "command.h" + +/* Vector for route match rules. */ +static vector route_match_vec; + +/* Vector for route set rules. */ +static vector route_set_vec; + +/* Route map rule. This rule has both `match' rule and `set' rule. */ +struct route_map_rule +{ + /* Rule type. */ + struct route_map_rule_cmd *cmd; + + /* For pretty printing. */ + char *rule_str; + + /* Pre-compiled match rule. */ + void *value; + + /* Linked list. */ + struct route_map_rule *next; + struct route_map_rule *prev; +}; + +/* Making route map list. */ +struct route_map_list +{ + struct route_map *head; + struct route_map *tail; + + void (*add_hook) (char *); + void (*delete_hook) (char *); + void (*event_hook) (route_map_event_t, char *); +}; + +/* Master list of route map. */ +static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL }; + +static void +route_map_rule_delete (struct route_map_rule_list *, + struct route_map_rule *); + +static void +route_map_index_delete (struct route_map_index *, int); + +/* New route map allocation. Please note route map's name must be + specified. */ +static struct route_map * +route_map_new (char *name) +{ + struct route_map *new; + + new = XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map)); + new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name); + return new; +} + +/* Add new name to route_map. */ +static struct route_map * +route_map_add (char *name) +{ + struct route_map *map; + struct route_map_list *list; + + map = route_map_new (name); + list = &route_map_master; + + map->next = NULL; + map->prev = list->tail; + if (list->tail) + list->tail->next = map; + else + list->head = map; + list->tail = map; + + /* Execute hook. */ + if (route_map_master.add_hook) + (*route_map_master.add_hook) (name); + + return map; +} + +/* Route map delete from list. */ +static void +route_map_delete (struct route_map *map) +{ + struct route_map_list *list; + struct route_map_index *index; + char *name; + + while ((index = map->head) != NULL) + route_map_index_delete (index, 0); + + name = map->name; + + list = &route_map_master; + + if (map->next) + map->next->prev = map->prev; + else + list->tail = map->prev; + + if (map->prev) + map->prev->next = map->next; + else + list->head = map->next; + + XFREE (MTYPE_ROUTE_MAP, map); + + /* Execute deletion hook. */ + if (route_map_master.delete_hook) + (*route_map_master.delete_hook) (name); + + if (name) + XFREE (MTYPE_ROUTE_MAP_NAME, name); + +} + +/* Lookup route map by route map name string. */ +struct route_map * +route_map_lookup_by_name (char *name) +{ + struct route_map *map; + + for (map = route_map_master.head; map; map = map->next) + if (strcmp (map->name, name) == 0) + return map; + return NULL; +} + +/* Lookup route map. If there isn't route map create one and return + it. */ +struct route_map * +route_map_get (char *name) +{ + struct route_map *map; + + map = route_map_lookup_by_name (name); + if (map == NULL) + map = route_map_add (name); + return map; +} + +/* Return route map's type string. */ +static char * +route_map_type_str (enum route_map_type type) +{ + switch (type) + { + case RMAP_PERMIT: + return "permit"; + break; + case RMAP_DENY: + return "deny"; + break; + default: + return ""; + break; + } +} + +int +route_map_empty (struct route_map *map) +{ + if (map->head == NULL && map->tail == NULL) + return 1; + else + return 0; +} + +/* 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; +} + +/* 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); +} + +/* 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 index 00000000..e37f1e7b --- /dev/null +++ b/lib/routemap.h @@ -0,0 +1,194 @@ +/* Route map function. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_ROUTEMAP_H +#define _ZEBRA_ROUTEMAP_H + +/* Route map's type. */ +enum route_map_type +{ + RMAP_PERMIT, + RMAP_DENY, + RMAP_ANY +}; + +typedef enum +{ + RMAP_MATCH, + RMAP_DENYMATCH, + RMAP_NOMATCH, + RMAP_ERROR, + RMAP_OKAY +} route_map_result_t; + +typedef enum +{ + RMAP_RIP, + RMAP_RIPNG, + RMAP_OSPF, + RMAP_OSPF6, + RMAP_BGP +} route_map_object_t; + +typedef enum +{ + RMAP_EXIT, + RMAP_GOTO, + RMAP_NEXT +} route_map_end_t; + +typedef enum +{ + RMAP_EVENT_SET_ADDED, + RMAP_EVENT_SET_DELETED, + RMAP_EVENT_SET_REPLACED, + RMAP_EVENT_MATCH_ADDED, + RMAP_EVENT_MATCH_DELETED, + RMAP_EVENT_MATCH_REPLACED, + RMAP_EVENT_INDEX_ADDED, + RMAP_EVENT_INDEX_DELETED +} route_map_event_t; + +/* Route map rule structure for matching and setting. */ +struct route_map_rule_cmd +{ + /* Route map rule name (e.g. as-path, metric) */ + char *str; + + /* Function for value set or match. */ + route_map_result_t (*func_apply)(void *, struct prefix *, + route_map_object_t, void *); + + /* Compile argument and return result as void *. */ + void *(*func_compile)(char *); + + /* Free allocated value by func_compile (). */ + void (*func_free)(void *); +}; + +/* Route map apply error. */ +enum +{ + /* Route map rule is missing. */ + RMAP_RULE_MISSING = 1, + + /* Route map rule can't compile */ + RMAP_COMPILE_ERROR +}; + +/* Route map rule list. */ +struct route_map_rule_list +{ + struct route_map_rule *head; + struct route_map_rule *tail; +}; + +/* Route map index structure. */ +struct route_map_index +{ + struct route_map *map; + + /* Preference of this route map rule. */ + int pref; + + /* Route map type permit or deny. */ + enum route_map_type type; + + /* Do we follow old rules, or hop forward? */ + route_map_end_t exitpolicy; + + /* If we're using "GOTO", to where do we go? */ + int nextpref; + + /* Matching rule list. */ + struct route_map_rule_list match_list; + struct route_map_rule_list set_list; + + /* Make linked list. */ + struct route_map_index *next; + struct route_map_index *prev; +}; + +/* Route map list structure. */ +struct route_map +{ + /* Name of route map. */ + char *name; + + /* Route map's rule. */ + struct route_map_index *head; + struct route_map_index *tail; + + /* Make linked list. */ + struct route_map *next; + struct route_map *prev; +}; + +/* Prototypes. */ +void route_map_init (); +void route_map_init_vty (); + +/* Add match statement to route map. */ +int +route_map_add_match (struct route_map_index *index, + char *match_name, + char *match_arg); + +/* Delete specified route match rule. */ +int +route_map_delete_match (struct route_map_index *index, + char *match_name, + char *match_arg); + +/* Add route-map set statement to the route map. */ +int +route_map_add_set (struct route_map_index *index, + char *set_name, + char *set_arg); + +/* Delete route map set rule. */ +int +route_map_delete_set (struct route_map_index *index, char *set_name, + char *set_arg); + +/* Install rule command to the match list. */ +void +route_map_install_match (struct route_map_rule_cmd *cmd); + +/* Install rule command to the set list. */ +void +route_map_install_set (struct route_map_rule_cmd *cmd); + +/* Lookup route map by name. */ +struct route_map * +route_map_lookup_by_name (char *name); + +/* Apply route map to the object. */ +route_map_result_t +route_map_apply (struct route_map *map, struct prefix *, + route_map_object_t object_type, void *object); + +void route_map_add_hook (void (*func) (char *)); +void route_map_delete_hook (void (*func) (char *)); +void route_map_event_hook (void (*func) (route_map_event_t, char *)); + + +#endif /* _ZEBRA_ROUTEMAP_H */ diff --git a/lib/smux.c b/lib/smux.c new file mode 100644 index 00000000..32f8c8ff --- /dev/null +++ b/lib/smux.c @@ -0,0 +1,1501 @@ +/* SNMP support + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#ifdef HAVE_SNMP + +#include +#include +#include + +#include "smux.h" +#include "log.h" +#include "thread.h" +#include "linklist.h" +#include "command.h" +#include "version.h" +#include "memory.h" +#include "sockunion.h" + +#define min(A,B) ((A) < (B) ? (A) : (B)) + +enum smux_event {SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ}; + +void smux_event (enum smux_event, int); + + +/* SMUX socket. */ +int smux_sock = -1; + +/* SMUX subtree list. */ +struct list *treelist; + +/* SMUX oid. */ +oid *smux_oid; +size_t smux_oid_len; + +/* SMUX default oid. */ +oid *smux_default_oid; +size_t smux_default_oid_len; + +/* SMUX password. */ +char *smux_passwd; +char *smux_default_passwd = ""; + +/* SMUX read threads. */ +struct thread *smux_read_thread; + +/* SMUX connect thrads. */ +struct thread *smux_connect_thread; + +/* SMUX debug flag. */ +int debug_smux = 0; + +/* SMUX failure count. */ +int fail = 0; + +/* SMUX node. */ +struct cmd_node smux_node = +{ + SMUX_NODE, + "" /* SMUX has no interface. */ +}; + +void * +oid_copy (void *dest, void *src, size_t size) +{ + return memcpy (dest, src, size * sizeof (oid)); +} + +void +oid2in_addr (oid oid[], int len, struct in_addr *addr) +{ + int i; + u_char *pnt; + + if (len == 0) + return; + + pnt = (u_char *) addr; + + for (i = 0; i < len; i++) + *pnt++ = oid[i]; +} + +void +oid_copy_addr (oid oid[], struct in_addr *addr, int len) +{ + int i; + u_char *pnt; + + if (len == 0) + return; + + pnt = (u_char *) addr; + + for (i = 0; i < len; i++) + oid[i] = *pnt++; +} + +int +oid_compare (oid *o1, int o1_len, oid *o2, int o2_len) +{ + int i; + + for (i = 0; i < min (o1_len, o2_len); i++) + { + if (o1[i] < o2[i]) + return -1; + else if (o1[i] > o2[i]) + return 1; + } + if (o1_len < o2_len) + return -1; + if (o1_len > o2_len) + return 1; + + return 0; +} + +int +oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len) +{ + int i; + + for (i = 0; i < min (o1_len, o2_len); i++) + { + if (o1[i] < o2[i]) + return -1; + else if (o1[i] > o2[i]) + return 1; + } + if (o1_len < o2_len) + return -1; + + return 0; +} + +void +smux_oid_dump (char *prefix, oid *oid, size_t oid_len) +{ + int i; + int first = 1; + char buf[MAX_OID_LEN * 3]; + + buf[0] = '\0'; + + for (i = 0; i < oid_len; i++) + { + sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) oid[i]); + first = 0; + } + zlog_info ("%s: %s", prefix, buf); +} + +int +smux_socket () +{ + int ret; +#ifdef HAVE_IPV6 + struct addrinfo hints, *res0, *res; + int gai; +#else + struct sockaddr_in serv; + struct servent *sp; +#endif + int sock = 0; + +#ifdef HAVE_IPV6 + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + gai = getaddrinfo(NULL, "smux", &hints, &res0); + if (gai == EAI_SERVICE) + { + char servbuf[NI_MAXSERV]; + sprintf(servbuf,"%d",SMUX_PORT_DEFAULT); + servbuf[sizeof (servbuf) - 1] = '\0'; + gai = getaddrinfo(NULL, servbuf, &hints, &res0); + } + if (gai) + { + zlog_warn("Cannot locate loopback service smux"); + return -1; + } + for(res=res0; res; res=res->ai_next) + { + if (res->ai_family != AF_INET +#ifdef HAVE_IPV6 + && res->ai_family != AF_INET6 +#endif /* HAVE_IPV6 */ + ) + continue; + + sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sock < 0) + continue; + sockopt_reuseaddr (sock); + sockopt_reuseport (sock); + ret = connect (sock, res->ai_addr, res->ai_addrlen); + if (ret < 0) + { + close(sock); + sock = -1; + continue; + } + break; + } + freeaddrinfo(res0); + if (sock < 0) + zlog_warn ("Can't connect to SNMP agent with SMUX"); +#else + sock = socket (AF_INET, SOCK_STREAM, 0); + if (sock < 0) + { + zlog_warn ("Can't make socket for SNMP"); + return -1; + } + + memset (&serv, 0, sizeof (struct sockaddr_in)); + serv.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + serv.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + + sp = getservbyname ("smux", "tcp"); + if (sp != NULL) + serv.sin_port = sp->s_port; + else + serv.sin_port = htons (SMUX_PORT_DEFAULT); + + serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + sockopt_reuseaddr (sock); + sockopt_reuseport (sock); + + ret = connect (sock, (struct sockaddr *) &serv, sizeof (struct sockaddr_in)); + if (ret < 0) + { + close (sock); + smux_sock = -1; + zlog_warn ("Can't connect to SNMP agent with SMUX"); + return -1; + } +#endif + return sock; +} + +void +smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat, + long errindex, u_char val_type, void *arg, size_t arg_len) +{ + int ret; + u_char buf[BUFSIZ]; + u_char *ptr, *h1, *h1e, *h2, *h2e; + int len, length; + + ptr = buf; + len = BUFSIZ; + length = len; + + if (debug_smux) + { + zlog_info ("SMUX GETRSP send"); + zlog_info ("SMUX GETRSP reqid: %ld", reqid); + } + + h1 = ptr; + /* Place holder h1 for complete sequence */ + ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0); + h1e = ptr; + + ptr = asn_build_int (ptr, &len, + (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), + &reqid, sizeof (reqid)); + + if (debug_smux) + zlog_info ("SMUX GETRSP errstat: %ld", errstat); + + ptr = asn_build_int (ptr, &len, + (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), + &errstat, sizeof (errstat)); + if (debug_smux) + zlog_info ("SMUX GETRSP errindex: %ld", errindex); + + ptr = asn_build_int (ptr, &len, + (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), + &errindex, sizeof (errindex)); + + h2 = ptr; + /* Place holder h2 for one variable */ + ptr = asn_build_sequence (ptr, &len, + (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), + 0); + h2e = ptr; + + ptr = snmp_build_var_op (ptr, objid, &objid_len, + val_type, arg_len, arg, &len); + + /* Now variable size is known, fill in size */ + asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e); + + /* Fill in size of whole sequence */ + asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e); + + if (debug_smux) + zlog_info ("SMUX getresp send: %d", ptr - buf); + + ret = send (smux_sock, buf, (ptr - buf), 0); +} + +char * +smux_var (char *ptr, int len, oid objid[], size_t *objid_len, + size_t *var_val_len, + u_char *var_val_type, + void **var_value) +{ + u_char type; + u_char val_type; + size_t val_len; + u_char *val; + + if (debug_smux) + zlog_info ("SMUX var parse: len %d", len); + + /* Parse header. */ + ptr = asn_parse_header (ptr, &len, &type); + + if (debug_smux) + { + zlog_info ("SMUX var parse: type %d len %d", type, len); + zlog_info ("SMUX var parse: type must be %d", + (ASN_SEQUENCE | ASN_CONSTRUCTOR)); + } + + /* Parse var option. */ + *objid_len = MAX_OID_LEN; + ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type, + &val_len, &val, &len); + + if (var_val_len) + *var_val_len = val_len; + + if (var_value) + *var_value = (void*) val; + + if (var_val_type) + *var_val_type = val_type; + + /* Requested object id length is objid_len. */ + if (debug_smux) + smux_oid_dump ("Request OID", objid, *objid_len); + + if (debug_smux) + zlog_info ("SMUX val_type: %d", val_type); + + /* Check request value type. */ + if (debug_smux) + switch (val_type) + { + case ASN_NULL: + /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to + ASN_NULL. */ + zlog_info ("ASN_NULL"); + break; + + case ASN_INTEGER: + zlog_info ("ASN_INTEGER"); + break; + case ASN_COUNTER: + case ASN_GAUGE: + case ASN_TIMETICKS: + case ASN_UINTEGER: + zlog_info ("ASN_COUNTER"); + break; + case ASN_COUNTER64: + zlog_info ("ASN_COUNTER64"); + break; + case ASN_IPADDRESS: + zlog_info ("ASN_IPADDRESS"); + break; + case ASN_OCTET_STR: + zlog_info ("ASN_OCTET_STR"); + break; + case ASN_OPAQUE: + case ASN_NSAP: + case ASN_OBJECT_ID: + zlog_info ("ASN_OPAQUE"); + break; + case SNMP_NOSUCHOBJECT: + zlog_info ("SNMP_NOSUCHOBJECT"); + break; + case SNMP_NOSUCHINSTANCE: + zlog_info ("SNMP_NOSUCHINSTANCE"); + break; + case SNMP_ENDOFMIBVIEW: + zlog_info ("SNMP_ENDOFMIBVIEW"); + break; + case ASN_BIT_STR: + zlog_info ("ASN_BIT_STR"); + break; + default: + zlog_info ("Unknown type"); + break; + } + return ptr; +} + +/* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on + ucd-snmp smux and as such suppose, that the peer receives in the message + only one variable. Fortunately, IBM seems to do the same in AIX. */ + +int +smux_set (oid *reqid, size_t *reqid_len, + u_char val_type, void *val, size_t val_len, int action) +{ + int j; + struct subtree *subtree; + struct variable *v; + int subresult; + oid *suffix; + int suffix_len; + int result; + u_char *statP = NULL; + WriteMethod *write_method = NULL; + struct listnode *node; + + /* Check */ + for (node = treelist->head; node; node = node->next) + { + subtree = node->data; + subresult = oid_compare_part (reqid, *reqid_len, + subtree->name, subtree->name_len); + + /* Subtree matched. */ + if (subresult == 0) + { + /* Prepare suffix. */ + suffix = reqid + subtree->name_len; + suffix_len = *reqid_len - subtree->name_len; + result = subresult; + + /* Check variables. */ + for (j = 0; j < subtree->variables_num; j++) + { + v = &subtree->variables[j]; + + /* Always check suffix */ + result = oid_compare_part (suffix, suffix_len, + v->name, v->namelen); + + /* This is exact match so result must be zero. */ + if (result == 0) + { + if (debug_smux) + zlog_info ("SMUX function call index is %d", v->magic); + + statP = (*v->findVar) (v, suffix, &suffix_len, 1, + &val_len, &write_method); + + if (write_method) + { + return (*write_method)(action, val, val_type, val_len, + statP, suffix, suffix_len, v); + } + else + { + return SNMP_ERR_READONLY; + } + } + + /* If above execution is failed or oid is small (so + there is no further match). */ + if (result < 0) + return SNMP_ERR_NOSUCHNAME; + } + } + } + return SNMP_ERR_NOSUCHNAME; +} + +int +smux_get (oid *reqid, size_t *reqid_len, int exact, + u_char *val_type,void **val, size_t *val_len) +{ + int j; + struct subtree *subtree; + struct variable *v; + int subresult; + oid *suffix; + int suffix_len; + int result; + WriteMethod *write_method=NULL; + struct listnode *node; + + /* Check */ + for (node = treelist->head; node; node = node->next) + { + subtree = node->data; + subresult = oid_compare_part (reqid, *reqid_len, + subtree->name, subtree->name_len); + + /* Subtree matched. */ + if (subresult == 0) + { + /* Prepare suffix. */ + suffix = reqid + subtree->name_len; + suffix_len = *reqid_len - subtree->name_len; + result = subresult; + + /* Check variables. */ + for (j = 0; j < subtree->variables_num; j++) + { + v = &subtree->variables[j]; + + /* Always check suffix */ + result = oid_compare_part (suffix, suffix_len, + v->name, v->namelen); + + /* This is exact match so result must be zero. */ + if (result == 0) + { + if (debug_smux) + zlog_info ("SMUX function call index is %d", v->magic); + + *val = (*v->findVar) (v, suffix, &suffix_len, exact, + val_len, &write_method); + + /* There is no instance. */ + if (*val == NULL) + return SNMP_NOSUCHINSTANCE; + + /* Call is suceed. */ + *val_type = v->type; + + return 0; + } + + /* If above execution is failed or oid is small (so + there is no further match). */ + if (result < 0) + return SNMP_ERR_NOSUCHNAME; + } + } + } + return SNMP_ERR_NOSUCHNAME; +} + +int +smux_getnext (oid *reqid, size_t *reqid_len, int exact, + u_char *val_type,void **val, size_t *val_len) +{ + int j; + oid save[MAX_OID_LEN]; + int savelen = 0; + struct subtree *subtree; + struct variable *v; + int subresult; + oid *suffix; + int suffix_len; + int result; + WriteMethod *write_method=NULL; + struct listnode *node; + + + /* Save incoming request. */ + oid_copy (save, reqid, *reqid_len); + savelen = *reqid_len; + + /* Check */ + for (node = treelist->head; node; node = node->next) + { + subtree = node->data; + subresult = oid_compare_part (reqid, *reqid_len, + subtree->name, subtree->name_len); + + /* If request is in the tree. The agent has to make sure we + only receive requests we have registered for. */ + /* Unfortunately, that's not true. In fact, a SMUX subagent has to + behave as if it manages the whole SNMP MIB tree itself. It's the + duty of the master agent to collect the best answer and return it + to the manager. See RFC 1227 chapter 3.1.6 for the glory details + :-). ucd-snmp really behaves bad here as it actually might ask + multiple times for the same GETNEXT request as it throws away the + answer when it expects it in a different subtree and might come + back later with the very same request. --jochen */ + + if (subresult <= 0) + { + /* Prepare suffix. */ + suffix = reqid + subtree->name_len; + suffix_len = *reqid_len - subtree->name_len; + if (subresult < 0) + { + oid_copy(reqid, subtree->name, subtree->name_len); + *reqid_len = subtree->name_len; + } + for (j = 0; j < subtree->variables_num; j++) + { + result = subresult; + v = &subtree->variables[j]; + + /* Next then check result >= 0. */ + if (result == 0) + result = oid_compare_part (suffix, suffix_len, + v->name, v->namelen); + + if (result <= 0) + { + if (debug_smux) + zlog_info ("SMUX function call index is %d", v->magic); + if(result<0) + { + oid_copy(suffix, v->name, v->namelen); + suffix_len = v->namelen; + } + *val = (*v->findVar) (v, suffix, &suffix_len, exact, + val_len, &write_method); + *reqid_len = suffix_len + subtree->name_len; + if (*val) + { + *val_type = v->type; + return 0; + } + } + } + } + } + memcpy (reqid, save, savelen * sizeof(oid)); + *reqid_len = savelen; + + return SNMP_ERR_NOSUCHNAME; +} + +/* GET message header. */ +char * +smux_parse_get_header (char *ptr, size_t *len, long *reqid) +{ + u_char type; + long errstat; + long errindex; + + /* Request ID. */ + ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid)); + + if (debug_smux) + zlog_info ("SMUX GET reqid: %d len: %d", (int) *reqid, (int) *len); + + /* Error status. */ + ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat)); + + if (debug_smux) + zlog_info ("SMUX GET errstat %ld len: %d", errstat, *len); + + /* Error index. */ + ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex)); + + if (debug_smux) + zlog_info ("SMUX GET errindex %ld len: %d", errindex, *len); + + return ptr; +} + +void +smux_parse_set (char *ptr, size_t len, int action) +{ + long reqid; + oid oid[MAX_OID_LEN]; + size_t oid_len; + u_char val_type; + void *val; + size_t val_len; + int ret; + + if (debug_smux) + zlog_info ("SMUX SET(%s) message parse: len %d", + (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"), + len); + + /* Parse SET message header. */ + ptr = smux_parse_get_header (ptr, &len, &reqid); + + /* Parse SET message object ID. */ + ptr = smux_var (ptr, len, oid, &oid_len, &val_len, &val_type, &val); + + ret = smux_set (oid, &oid_len, val_type, val, val_len, action); + if (debug_smux) + zlog_info ("SMUX SET ret %d", ret); + + /* Return result. */ + if (RESERVE1 == action) + smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0); +} + +void +smux_parse_get (char *ptr, size_t len, int exact) +{ + long reqid; + oid oid[MAX_OID_LEN]; + size_t oid_len; + u_char val_type; + void *val; + size_t val_len; + int ret; + + if (debug_smux) + zlog_info ("SMUX GET message parse: len %d", len); + + /* Parse GET message header. */ + ptr = smux_parse_get_header (ptr, &len, &reqid); + + /* Parse GET message object ID. We needn't the value come */ + ptr = smux_var (ptr, len, oid, &oid_len, NULL, NULL, NULL); + + /* Traditional getstatptr. */ + if (exact) + ret = smux_get (oid, &oid_len, exact, &val_type, &val, &val_len); + else + ret = smux_getnext (oid, &oid_len, exact, &val_type, &val, &val_len); + + /* Return result. */ + if (ret == 0) + smux_getresp_send (oid, oid_len, reqid, 0, 0, val_type, val, val_len); + else + smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0); +} + +/* Parse SMUX_CLOSE message. */ +void +smux_parse_close (char *ptr, int len) +{ + long reason = 0; + + while (len--) + { + reason = (reason << 8) | (long) *ptr; + ptr++; + } + zlog_info ("SMUX_CLOSE with reason: %ld", reason); +} + +/* SMUX_RRSP message. */ +void +smux_parse_rrsp (char *ptr, int len) +{ + char val; + long errstat; + + ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat)); + + if (debug_smux) + zlog_info ("SMUX_RRSP value: %d errstat: %ld", val, errstat); +} + +/* Parse SMUX message. */ +int +smux_parse (char *ptr, int len) +{ + /* This buffer we'll use for SOUT message. We could allocate it with + malloc and save only static pointer/lenght, but IMHO static + buffer is a faster solusion. */ + static u_char sout_save_buff[SMUXMAXPKTSIZE]; + static int sout_save_len = 0; + + int len_income = len; /* see note below: YYY */ + u_char type; + u_char rollback; + + rollback = ptr[2]; /* important only for SMUX_SOUT */ + +process_rest: /* see note below: YYY */ + + /* Parse SMUX message type and subsequent length. */ + ptr = asn_parse_header (ptr, &len, &type); + + if (debug_smux) + zlog_info ("SMUX message received type: %d rest len: %d", type, len); + + switch (type) + { + case SMUX_OPEN: + /* Open must be not send from SNMP agent. */ + zlog_warn ("SMUX_OPEN received: resetting connection."); + return -1; + break; + case SMUX_RREQ: + /* SMUX_RREQ message is invalid for us. */ + zlog_warn ("SMUX_RREQ received: resetting connection."); + return -1; + break; + case SMUX_SOUT: + /* SMUX_SOUT message is now valied for us. */ + if (debug_smux) + zlog_info ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit"); + + if (sout_save_len > 0) + { + smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT); + sout_save_len = 0; + } + else + zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len); + + if (len_income > 3) + { + /* YYY: this strange code has to solve the "slow peer" + problem: When agent sends SMUX_SOUT message it doesn't + wait any responce and may send some next message to + subagent. Then the peer in 'smux_read()' will recieve + from socket the 'concatenated' buffer, contaning both + SMUX_SOUT message and the next one + (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if + the buffer is longer than 3 ( length of SMUX_SOUT ), we + must process the rest of it. This effect may be observed + if 'debug_smux' is set to '1' */ + ptr++; + len = len_income - 3; + goto process_rest; + } + break; + case SMUX_GETRSP: + /* SMUX_GETRSP message is invalid for us. */ + zlog_warn ("SMUX_GETRSP received: resetting connection."); + return -1; + break; + case SMUX_CLOSE: + /* Close SMUX connection. */ + if (debug_smux) + zlog_info ("SMUX_CLOSE"); + smux_parse_close (ptr, len); + return -1; + break; + case SMUX_RRSP: + /* This is response for register message. */ + if (debug_smux) + zlog_info ("SMUX_RRSP"); + smux_parse_rrsp (ptr, len); + break; + case SMUX_GET: + /* Exact request for object id. */ + if (debug_smux) + zlog_info ("SMUX_GET"); + smux_parse_get (ptr, len, 1); + break; + case SMUX_GETNEXT: + /* Next request for object id. */ + if (debug_smux) + zlog_info ("SMUX_GETNEXT"); + smux_parse_get (ptr, len, 0); + break; + case SMUX_SET: + /* SMUX_SET is supported with some limitations. */ + if (debug_smux) + zlog_info ("SMUX_SET"); + + /* save the data for future SMUX_SOUT */ + memcpy (sout_save_buff, ptr, len); + sout_save_len = len; + smux_parse_set (ptr, len, RESERVE1); + break; + default: + zlog_info ("Unknown type: %d", type); + break; + } + return 0; +} + +/* SMUX message read function. */ +int +smux_read (struct thread *t) +{ + int sock; + int len; + u_char buf[SMUXMAXPKTSIZE]; + int ret; + + /* Clear thread. */ + sock = THREAD_FD (t); + smux_read_thread = NULL; + + if (debug_smux) + zlog_info ("SMUX read start"); + + /* Read message from SMUX socket. */ + len = recv (sock, buf, SMUXMAXPKTSIZE, 0); + + if (len < 0) + { + zlog_warn ("Can't read all SMUX packet: %s", strerror (errno)); + close (sock); + smux_sock = -1; + smux_event (SMUX_CONNECT, 0); + return -1; + } + + if (len == 0) + { + zlog_warn ("SMUX connection closed: %d", sock); + close (sock); + smux_sock = -1; + smux_event (SMUX_CONNECT, 0); + return -1; + } + + if (debug_smux) + zlog_info ("SMUX read len: %d", len); + + /* Parse the message. */ + ret = smux_parse (buf, len); + + if (ret < 0) + { + close (sock); + smux_sock = -1; + smux_event (SMUX_CONNECT, 0); + return -1; + } + + /* Regiser read thread. */ + smux_event (SMUX_READ, sock); + + return 0; +} + +int +smux_open (int sock) +{ + u_char buf[BUFSIZ]; + u_char *ptr; + int len; + u_long version; + u_char progname[] = "zebra-" ZEBRA_VERSION; + + if (debug_smux) + { + smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len); + zlog_info ("SMUX open progname: %s", progname); + zlog_info ("SMUX open password: %s", smux_passwd); + } + + ptr = buf; + len = BUFSIZ; + + /* SMUX Header. As placeholder. */ + ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0); + + /* SMUX Open. */ + version = 0; + ptr = asn_build_int (ptr, &len, + (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), + &version, sizeof (u_long)); + + /* SMUX connection oid. */ + ptr = asn_build_objid (ptr, &len, + (u_char) + (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID), + smux_oid, smux_oid_len); + + /* SMUX connection description. */ + ptr = asn_build_string (ptr, &len, + (u_char) + (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), + progname, strlen (progname)); + + /* SMUX connection password. */ + ptr = asn_build_string (ptr, &len, + (u_char) + (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), + smux_passwd, strlen (smux_passwd)); + + /* Fill in real SMUX header. We exclude ASN header size (2). */ + len = BUFSIZ; + asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2); + + return send (sock, buf, (ptr - buf), 0); +} + +int +smux_trap (oid *name, size_t namelen, + oid *iname, size_t inamelen, + struct trap_object *trapobj, size_t trapobjlen, + unsigned int tick) +{ + 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; + } +} + +extern struct thread_master *master; + +void +smux_event (enum smux_event event, int sock) +{ + switch (event) + { + case SMUX_SCHEDULE: + smux_connect_thread = thread_add_event (master, smux_connect, NULL, 0); + break; + case SMUX_CONNECT: + smux_connect_thread = thread_add_timer (master, smux_connect, NULL, 10); + break; + case SMUX_READ: + smux_read_thread = thread_add_read (master, smux_read, NULL, sock); + break; + default: + break; + } +} + +int +smux_str2oid (char *str, oid *oid, size_t *oid_len) +{ + int len; + int val; + + len = 0; + val = 0; + *oid_len = 0; + + if (*str == '.') + str++; + if (*str == '\0') + return 0; + + while (1) + { + if (! isdigit (*str)) + return -1; + + while (isdigit (*str)) + { + val *= 10; + val += (*str - '0'); + str++; + } + + if (*str == '\0') + break; + if (*str != '.') + return -1; + + oid[len++] = val; + val = 0; + str++; + } + + oid[len++] = val; + *oid_len = len; + + return 0; +} + +oid * +smux_oid_dup (oid *objid, size_t objid_len) +{ + oid *new; + + new = XMALLOC (MTYPE_TMP, sizeof (oid) * objid_len); + oid_copy (new, objid, objid_len); + + return new; +} + +int +smux_peer_oid (struct vty *vty, char *oid_str, char *passwd_str) +{ + int ret; + oid oid[MAX_OID_LEN]; + size_t oid_len; + + ret = smux_str2oid (oid_str, oid, &oid_len); + if (ret != 0) + { + vty_out (vty, "object ID malformed%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (smux_oid && smux_oid != smux_default_oid) + free (smux_oid); + + if (smux_passwd && smux_passwd != smux_default_passwd) + { + free (smux_passwd); + smux_passwd = NULL; + } + + smux_oid = smux_oid_dup (oid, oid_len); + smux_oid_len = oid_len; + + if (passwd_str) + smux_passwd = strdup (passwd_str); + + return CMD_SUCCESS; +} + +int +smux_header_generic (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + oid fulloid[MAX_OID_LEN]; + int ret; + + oid_copy (fulloid, v->name, v->namelen); + fulloid[v->namelen] = 0; + /* Check against full instance. */ + ret = oid_compare (name, *length, fulloid, v->namelen + 1); + + /* Check single instance. */ + if ((exact && (ret != 0)) || (!exact && (ret >= 0))) + return MATCH_FAILED; + + /* In case of getnext, fill in full instance. */ + memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid)); + *length = v->namelen + 1; + + *write_method = 0; + *var_len = sizeof(long); /* default to 'long' results */ + + return MATCH_SUCCEEDED; +} + +int +smux_peer_default () +{ + if (smux_oid != smux_default_oid) + { + free (smux_oid); + smux_oid = smux_default_oid; + smux_oid_len = smux_default_oid_len; + } + if (smux_passwd != smux_default_passwd) + { + free (smux_passwd); + smux_passwd = smux_default_passwd; + } + return CMD_SUCCESS; +} + +DEFUN (smux_peer, + smux_peer_cmd, + "smux peer OID", + "SNMP MUX protocol settings\n" + "SNMP MUX peer settings\n" + "Object ID used in SMUX peering\n") +{ + return smux_peer_oid (vty, argv[0], NULL); +} + +DEFUN (smux_peer_password, + smux_peer_password_cmd, + "smux peer OID PASSWORD", + "SNMP MUX protocol settings\n" + "SNMP MUX peer settings\n" + "SMUX peering object ID\n" + "SMUX peering password\n") +{ + return smux_peer_oid (vty, argv[0], argv[1]); +} + +DEFUN (no_smux_peer, + no_smux_peer_cmd, + "no smux peer OID", + NO_STR + "SNMP MUX protocol settings\n" + "SNMP MUX peer settings\n" + "Object ID used in SMUX peering\n") +{ + return smux_peer_default (); +} + +DEFUN (no_smux_peer_password, + no_smux_peer_password_cmd, + "no smux peer OID PASSWORD", + NO_STR + "SNMP MUX protocol settings\n" + "SNMP MUX peer settings\n" + "SMUX peering object ID\n" + "SMUX peering password\n") +{ + return smux_peer_default (); +} + +int +config_write_smux (struct vty *vty) +{ + int first = 1; + int i; + + if (smux_oid != smux_default_oid || smux_passwd != smux_default_passwd) + { + vty_out (vty, "smux peer "); + for (i = 0; i < smux_oid_len; i++) + { + vty_out (vty, "%s%d", first ? "" : ".", (int) smux_oid[i]); + first = 0; + } + vty_out (vty, " %s%s", smux_passwd, VTY_NEWLINE); + } + return 0; +} + +/* Register subtree to smux master tree. */ +void +smux_register_mib (char *descr, struct variable *var, size_t width, int num, + oid name[], size_t namelen) +{ + struct subtree *tree; + + tree = (struct subtree *)malloc(sizeof(struct subtree)); + oid_copy (tree->name, name, namelen); + tree->name_len = namelen; + tree->variables = var; + tree->variables_num = num; + tree->variables_width = width; + tree->registered = 0; + listnode_add_sort(treelist, tree); +} + +void +smux_reset () +{ + /* Setting configuration to default. */ + smux_peer_default (); +} + +/* Compare function to keep treelist sorted */ +static int +smux_tree_cmp(struct subtree *tree1, struct subtree *tree2) +{ + return oid_compare(tree1->name, tree1->name_len, + tree2->name, tree2->name_len); +} + +/* Initialize some values then schedule first SMUX connection. */ +void +smux_init (oid defoid[], size_t defoid_len) +{ + /* Set default SMUX oid. */ + smux_default_oid = defoid; + smux_default_oid_len = defoid_len; + + smux_oid = smux_default_oid; + smux_oid_len = smux_default_oid_len; + smux_passwd = smux_default_passwd; + + /* Make MIB tree. */ + treelist = list_new(); + treelist->cmp = (int (*)(void *, void *))smux_tree_cmp; + + /* Install commands. */ + install_node (&smux_node, config_write_smux); + + install_element (CONFIG_NODE, &smux_peer_cmd); + install_element (CONFIG_NODE, &smux_peer_password_cmd); + install_element (CONFIG_NODE, &no_smux_peer_cmd); + install_element (CONFIG_NODE, &no_smux_peer_password_cmd); +} + +void +smux_start(void) +{ + /* Schedule first connection. */ + smux_event (SMUX_SCHEDULE, 0); +} +#endif /* HAVE_SNMP */ diff --git a/lib/smux.h b/lib/smux.h new file mode 100644 index 00000000..91c3d46f --- /dev/null +++ b/lib/smux.h @@ -0,0 +1,159 @@ +/* SNMP support + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_SNMP_H +#define _ZEBRA_SNMP_H + +#define SMUX_PORT_DEFAULT 199 + +#define SMUXMAXPKTSIZE 1500 +#define SMUXMAXSTRLEN 256 + +#define SMUX_OPEN (ASN_APPLICATION | ASN_CONSTRUCTOR | 0) +#define SMUX_CLOSE (ASN_APPLICATION | ASN_PRIMITIVE | 1) +#define SMUX_RREQ (ASN_APPLICATION | ASN_CONSTRUCTOR | 2) +#define SMUX_RRSP (ASN_APPLICATION | ASN_PRIMITIVE | 3) +#define SMUX_SOUT (ASN_APPLICATION | ASN_PRIMITIVE | 4) + +#define SMUX_GET (ASN_CONTEXT | ASN_CONSTRUCTOR | 0) +#define SMUX_GETNEXT (ASN_CONTEXT | ASN_CONSTRUCTOR | 1) +#define SMUX_GETRSP (ASN_CONTEXT | ASN_CONSTRUCTOR | 2) +#define SMUX_SET (ASN_CONTEXT | ASN_CONSTRUCTOR | 3) +#define SMUX_TRAP (ASN_CONTEXT | ASN_CONSTRUCTOR | 4) + +#define SMUX_MAX_FAILURE 3 + +/* Structures here are mostly compatible with UCD SNMP 4.1.1 */ +#define MATCH_FAILED (-1) +#define MATCH_SUCCEEDED 0 + +/* SYNTAX TruthValue from SNMPv2-TC. */ +#define SNMP_TRUE 1 +#define SNMP_FALSE 2 + +/* SYNTAX RowStatus from SNMPv2-TC. */ +#define SNMP_VALID 1 +#define SNMP_INVALID 2 + +#define IN_ADDR_SIZE sizeof(struct in_addr) + +struct variable; + +#define REGISTER_MIB(descr, var, vartype, theoid) \ + smux_register_mib(descr, (struct variable *)var, sizeof(struct vartype), \ + sizeof(var)/sizeof(struct vartype), \ + theoid, sizeof(theoid)/sizeof(oid)) + +typedef int (WriteMethod)(int action, + u_char *var_val, + u_char var_val_type, + size_t var_val_len, + u_char *statP, + oid *name, + size_t length, + struct variable *v); + +typedef u_char *(FindVarMethod)(struct variable *v, + oid *name, + size_t *length, + int exact, + size_t *var_len, + WriteMethod **write_method); + +/* SNMP variable */ +struct variable +{ + /* Index of the MIB.*/ + u_char magic; + + /* Type of variable. */ + char type; + + /* Access control list. */ + u_short acl; + + /* Callback function. */ + FindVarMethod *findVar; + + /* Suffix of the MIB. */ + u_char namelen; + oid name[MAX_OID_LEN]; +}; + +/* SNMP tree. */ +struct subtree +{ + /* Tree's oid. */ + oid name[MAX_OID_LEN]; + u_char name_len; + + /* List of the variables. */ + struct variable *variables; + + /* Length of the variables list. */ + int variables_num; + + /* Width of the variables list. */ + int variables_width; + + /* Registered flag. */ + int registered; +}; + +struct trap_object +{ + FindVarMethod *findVar; + u_char namelen; + oid name[MAX_OID_LEN]; +}; + +/* Declare SMUX return value. */ +#define SNMP_LOCAL_VARIABLES \ + static int32_t snmp_int_val; \ + static struct in_addr snmp_in_addr_val; + +#define SNMP_INTEGER(V) \ + ( \ + *var_len = sizeof (int32_t), \ + snmp_int_val = V, \ + (u_char *) &snmp_int_val \ + ) + +#define SNMP_IPADDRESS(V) \ + ( \ + *var_len = sizeof (struct in_addr), \ + snmp_in_addr_val = V, \ + (u_char *) &snmp_in_addr_val \ + ) + +void smux_init (oid [], size_t); +void smux_start (void); +void smux_register_mib(char *, struct variable *, size_t, int, oid [], size_t); +int smux_header_generic (struct variable *, oid [], size_t *, int, size_t *, + WriteMethod **); +int smux_trap (oid *, size_t, oid *, size_t, struct trap_object *, size_t, unsigned int); + +int oid_compare (oid *, int, oid *, int); +void oid2in_addr (oid [], int, struct in_addr *); +void *oid_copy (void *, void *, size_t); +void oid_copy_addr (oid [], struct in_addr *, int); + +#endif /* _ZEBRA_SNMP_H */ diff --git a/lib/sockopt.c b/lib/sockopt.c new file mode 100644 index 00000000..e2beca9f --- /dev/null +++ b/lib/sockopt.c @@ -0,0 +1,199 @@ +/* setsockopt functions + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include +#include "log.h" + +#ifdef HAVE_IPV6 +/* Set IPv6 packet info to the socket. */ +int +setsockopt_ipv6_pktinfo (int sock, int val) +{ + int ret; + +#ifdef IPV6_RECVPKTINFO /*2292bis-01*/ + ret = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_RECVPKTINFO : %s", strerror (errno)); +#else /*RFC2292*/ + ret = setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &val, sizeof(val)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_PKTINFO : %s", strerror (errno)); +#endif /* INIA_IPV6 */ + return ret; +} + +/* Set multicast hops val to the socket. */ +int +setsockopt_ipv6_checksum (int sock, int val) +{ + int ret; + +#ifdef GNU_LINUX + ret = setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val)); +#else + ret = setsockopt(sock, IPPROTO_IPV6, IPV6_CHECKSUM, &val, sizeof(val)); +#endif /* GNU_LINUX */ + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_CHECKSUM"); + return ret; +} + +/* Set multicast hops val to the socket. */ +int +setsockopt_ipv6_multicast_hops (int sock, int val) +{ + int ret; + + ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_MULTICAST_HOPS"); + return ret; +} + +/* Set multicast hops val to the socket. */ +int +setsockopt_ipv6_unicast_hops (int sock, int val) +{ + int ret; + + ret = setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_UNICAST_HOPS"); + return ret; +} + +int +setsockopt_ipv6_hoplimit (int sock, int val) +{ + int ret; + +#ifdef IPV6_RECVHOPLIMIT /*2292bis-01*/ + ret = setsockopt (sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_RECVHOPLIMIT"); +#else /*RFC2292*/ + ret = setsockopt (sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &val, sizeof(val)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_HOPLIMIT"); +#endif + return ret; +} + +/* Set multicast loop zero to the socket. */ +int +setsockopt_ipv6_multicast_loop (int sock, int val) +{ + int ret; + + ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, + sizeof (val)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_MULTICAST_LOOP"); + return ret; +} + +#endif /* HAVE_IPV6 */ + + +/* Set up a multicast socket options for IPv4 + This is here so that people only have to do their OS multicast mess + in one place rather than all through zebra, ospfd, and ripd + NB: This is a hookpoint for specific OS functionality */ +int +setsockopt_multicast_ipv4(int sock, + int optname, + struct in_addr if_addr, + unsigned int mcast_addr, + unsigned int ifindex) +{ + + /* Linux 2.2.0 and up */ +#if defined(GNU_LINUX) && LINUX_VERSION_CODE > 131584 + /* This is better because it uses ifindex directly */ + struct ip_mreqn mreqn; + + switch (optname) + { + case IP_MULTICAST_IF: + case IP_ADD_MEMBERSHIP: + case IP_DROP_MEMBERSHIP: + memset (&mreqn, 0, sizeof(mreqn)); + + if (mcast_addr) + mreqn.imr_multiaddr.s_addr = mcast_addr; + + if (ifindex) + mreqn.imr_ifindex = ifindex; + else + mreqn.imr_address = if_addr; + + return setsockopt(sock, IPPROTO_IP, optname, (void *)&mreqn, sizeof(mreqn)); + break; + + default: + /* Can out and give an understandable error */ + errno = EINVAL; + return -1; + break; + } + + /* Example defines for another OS, boilerplate off other code in this + function, AND handle optname as per other sections for consistency !! */ + /* #elif defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */ + /* Add your favourite OS here! */ + +#else /* #if OS_TYPE */ + /* default OS support */ + + struct in_addr m; + struct ip_mreq mreq; + + switch (optname) + { + case IP_MULTICAST_IF: + m = if_addr; + + return setsockopt (sock, IPPROTO_IP, optname, (void *)&m, sizeof(m)); + break; + + case IP_ADD_MEMBERSHIP: + case IP_DROP_MEMBERSHIP: + memset (&mreq, 0, sizeof(mreq)); + mreq.imr_multiaddr.s_addr = mcast_addr; + mreq.imr_interface = if_addr; + + return setsockopt (sock, + IPPROTO_IP, + optname, + (void *)&mreq, + sizeof(mreq)); + break; + + default: + /* Can out and give an understandable error */ + errno = EINVAL; + return -1; + break; + } +#endif /* #if OS_TYPE */ + +} diff --git a/lib/sockopt.h b/lib/sockopt.h new file mode 100644 index 00000000..7fb31c18 --- /dev/null +++ b/lib/sockopt.h @@ -0,0 +1,41 @@ +/* Router advertisement + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_SOCKOPT_H +#define _ZEBRA_SOCKOPT_H + +#ifdef HAVE_IPV6 +int setsockopt_ipv6_pktinfo (int, int); +int setsockopt_ipv6_checksum (int, int); +int setsockopt_ipv6_multicast_hops (int, int); +int setsockopt_ipv6_unicast_hops (int, int); +int setsockopt_ipv6_hoplimit (int, int); +int setsockopt_ipv6_multicast_loop (int, int); +#endif /* HAVE_IPV6 */ + +int setsockopt_multicast_ipv4(int sock, + int optname, + struct in_addr if_addr, + unsigned int mcast_addr, + unsigned int ifindex); + + +#endif /*_ZEBRA_SOCKOPT_H */ diff --git a/lib/sockunion.c b/lib/sockunion.c new file mode 100644 index 00000000..21371624 --- /dev/null +++ b/lib/sockunion.c @@ -0,0 +1,756 @@ +/* Socket union related function. + * Copyright (c) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "vty.h" +#include "sockunion.h" +#include "memory.h" +#include "str.h" +#include "log.h" + +#ifndef HAVE_INET_ATON +int +inet_aton (const char *cp, struct in_addr *inaddr) +{ + int dots = 0; + register u_long addr = 0; + register u_long val = 0, base = 10; + + do + { + register char c = *cp; + + switch (c) + { + case '0': case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + val = (val * base) + (c - '0'); + break; + case '.': + if (++dots > 3) + return 0; + case '\0': + if (val > 255) + return 0; + addr = addr << 8 | val; + val = 0; + break; + default: + return 0; + } + } while (*cp++) ; + + if (dots < 3) + addr <<= 8 * (3 - dots); + if (inaddr) + inaddr->s_addr = htonl (addr); + return 1; +} +#endif /* ! HAVE_INET_ATON */ + + +#ifndef HAVE_INET_PTON +int +inet_pton (int family, const char *strptr, void *addrptr) +{ + if (family == AF_INET) + { + struct in_addr in_val; + + if (inet_aton (strptr, &in_val)) + { + memcpy (addrptr, &in_val, sizeof (struct in_addr)); + return 1; + } + return 0; + } + errno = EAFNOSUPPORT; + return -1; +} +#endif /* ! HAVE_INET_PTON */ + +#ifndef HAVE_INET_NTOP +const char * +inet_ntop (int family, const void *addrptr, char *strptr, size_t len) +{ + unsigned char *p = (unsigned char *) addrptr; + + if (family == AF_INET) + { + char temp[INET_ADDRSTRLEN]; + + snprintf(temp, sizeof(temp), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); + + if (strlen(temp) >= len) + { + errno = ENOSPC; + return NULL; + } + strcpy(strptr, temp); + return strptr; + } + + errno = EAFNOSUPPORT; + return NULL; +} +#endif /* ! HAVE_INET_NTOP */ + +const char * +inet_sutop (union sockunion *su, char *str) +{ + switch (su->sa.sa_family) + { + case AF_INET: + inet_ntop (AF_INET, &su->sin.sin_addr, str, INET_ADDRSTRLEN); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, INET6_ADDRSTRLEN); + break; +#endif /* HAVE_IPV6 */ + } + return str; +} + +int +str2sockunion (char *str, union sockunion *su) +{ + int ret; + + memset (su, 0, sizeof (union sockunion)); + + ret = inet_pton (AF_INET, str, &su->sin.sin_addr); + if (ret > 0) /* Valid IPv4 address format. */ + { + su->sin.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + su->sin.sin_len = sizeof(struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + return 0; + } +#ifdef HAVE_IPV6 + ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr); + if (ret > 0) /* Valid IPv6 address format. */ + { + su->sin6.sin6_family = AF_INET6; +#ifdef SIN6_LEN + su->sin6.sin6_len = sizeof(struct sockaddr_in6); +#endif /* SIN6_LEN */ + return 0; + } +#endif /* HAVE_IPV6 */ + return -1; +} + +const char * +sockunion2str (union sockunion *su, char *buf, size_t len) +{ + if (su->sa.sa_family == AF_INET) + return inet_ntop (AF_INET, &su->sin.sin_addr, buf, len); +#ifdef HAVE_IPV6 + else if (su->sa.sa_family == AF_INET6) + return inet_ntop (AF_INET6, &su->sin6.sin6_addr, buf, len); +#endif /* HAVE_IPV6 */ + return NULL; +} + +union sockunion * +sockunion_str2su (char *str) +{ + int ret; + union sockunion *su; + + su = XMALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); + memset (su, 0, sizeof (union sockunion)); + + ret = inet_pton (AF_INET, str, &su->sin.sin_addr); + if (ret > 0) /* Valid IPv4 address format. */ + { + su->sin.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + su->sin.sin_len = sizeof(struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + return su; + } +#ifdef HAVE_IPV6 + ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr); + if (ret > 0) /* Valid IPv6 address format. */ + { + su->sin6.sin6_family = AF_INET6; +#ifdef SIN6_LEN + su->sin6.sin6_len = sizeof(struct sockaddr_in6); +#endif /* SIN6_LEN */ + return su; + } +#endif /* HAVE_IPV6 */ + + XFREE (MTYPE_SOCKUNION, su); + return NULL; +} + +char * +sockunion_su2str (union sockunion *su) +{ + char str[INET6_ADDRSTRLEN]; + + switch (su->sa.sa_family) + { + case AF_INET: + inet_ntop (AF_INET, &su->sin.sin_addr, str, sizeof (str)); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, sizeof (str)); + break; +#endif /* HAVE_IPV6 */ + } + return strdup (str); +} + +/* Return socket of sockunion. */ +int +sockunion_socket (union sockunion *su) +{ + int sock; + + sock = socket (su->sa.sa_family, SOCK_STREAM, 0); + if (sock < 0) + { + zlog (NULL, LOG_WARNING, "Can't make socket : %s", strerror (errno)); + return -1; + } + + return sock; +} + +/* Return accepted new socket file descriptor. */ +int +sockunion_accept (int sock, union sockunion *su) +{ + socklen_t len; + int client_sock; + + len = sizeof (union sockunion); + client_sock = accept (sock, (struct sockaddr *) su, &len); + + /* Convert IPv4 compatible IPv6 address to IPv4 address. */ +#ifdef HAVE_IPV6 + if (su->sa.sa_family == AF_INET6) + { + if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr)) + { + struct sockaddr_in sin; + + memset (&sin, 0, sizeof (struct sockaddr_in)); + sin.sin_family = AF_INET; + memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4); + memcpy (su, &sin, sizeof (struct sockaddr_in)); + } + } +#endif /* HAVE_IPV6 */ + + return client_sock; +} + +/* Return sizeof union sockunion. */ +int +sockunion_sizeof (union sockunion *su) +{ + int ret; + + ret = 0; + switch (su->sa.sa_family) + { + case AF_INET: + ret = sizeof (struct sockaddr_in); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + ret = sizeof (struct sockaddr_in6); + break; +#endif /* AF_INET6 */ + } + return ret; +} + +/* return sockunion structure : this function should be revised. */ +char * +sockunion_log (union sockunion *su) +{ + static char buf[SU_ADDRSTRLEN]; + + switch (su->sa.sa_family) + { + case AF_INET: + snprintf (buf, BUFSIZ, "%s", inet_ntoa (su->sin.sin_addr)); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + snprintf (buf, BUFSIZ, "%s", + inet_ntop (AF_INET6, &(su->sin6.sin6_addr), buf, BUFSIZ)); + break; +#endif /* HAVE_IPV6 */ + default: + snprintf (buf, BUFSIZ, "af_unknown %d ", su->sa.sa_family); + break; + } + return buf; +} + +/* sockunion_connect returns + -1 : error occured + 0 : connect success + 1 : connect is in progress */ +enum connect_result +sockunion_connect (int fd, union sockunion *peersu, unsigned short port, + unsigned int ifindex) +{ + int ret; + int val; + union sockunion su; + + memcpy (&su, peersu, sizeof (union sockunion)); + + switch (su.sa.sa_family) + { + case AF_INET: + su.sin.sin_port = port; + break; +#ifdef HAVE_IPV6 + case AF_INET6: + su.sin6.sin6_port = port; +#ifdef KAME + if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex) + { +#ifdef HAVE_SIN6_SCOPE_ID + /* su.sin6.sin6_scope_id = ifindex; */ +#endif /* HAVE_SIN6_SCOPE_ID */ + SET_IN6_LINKLOCAL_IFINDEX (su.sin6.sin6_addr, ifindex); + } +#endif /* KAME */ + break; +#endif /* HAVE_IPV6 */ + } + + /* Make socket non-block. */ + val = fcntl (fd, F_GETFL, 0); + fcntl (fd, F_SETFL, val|O_NONBLOCK); + + /* Call connect function. */ + ret = connect (fd, (struct sockaddr *) &su, sockunion_sizeof (&su)); + + /* Immediate success */ + if (ret == 0) + { + fcntl (fd, F_SETFL, val); + return connect_success; + } + + /* If connect is in progress then return 1 else it's real error. */ + if (ret < 0) + { + if (errno != EINPROGRESS) + { + zlog_info ("can't connect to %s fd %d : %s", + sockunion_log (&su), fd, strerror (errno)); + return connect_error; + } + } + + fcntl (fd, F_SETFL, val); + + return connect_in_progress; +} + +/* Make socket from sockunion union. */ +int +sockunion_stream_socket (union sockunion *su) +{ + int sock; + + if (su->sa.sa_family == 0) + su->sa.sa_family = AF_INET_UNION; + + sock = socket (su->sa.sa_family, SOCK_STREAM, 0); + + if (sock < 0) + zlog (NULL, LOG_WARNING, "can't make socket sockunion_stream_socket"); + + return sock; +} + +/* Bind socket to specified address. */ +int +sockunion_bind (int sock, union sockunion *su, unsigned short port, + union sockunion *su_addr) +{ + int size = 0; + int ret; + + if (su->sa.sa_family == AF_INET) + { + size = sizeof (struct sockaddr_in); + su->sin.sin_port = htons (port); +#ifdef HAVE_SIN_LEN + su->sin.sin_len = size; +#endif /* HAVE_SIN_LEN */ + if (su_addr == NULL) + su->sin.sin_addr.s_addr = htonl (INADDR_ANY); + } +#ifdef HAVE_IPV6 + else if (su->sa.sa_family == AF_INET6) + { + size = sizeof (struct sockaddr_in6); + su->sin6.sin6_port = htons (port); +#ifdef SIN6_LEN + su->sin6.sin6_len = size; +#endif /* SIN6_LEN */ + if (su_addr == NULL) + { +#if defined(LINUX_IPV6) || defined(NRL) + memset (&su->sin6.sin6_addr, 0, sizeof (struct in6_addr)); +#else + su->sin6.sin6_addr = in6addr_any; +#endif /* LINUX_IPV6 */ + } + } +#endif /* HAVE_IPV6 */ + + + ret = bind (sock, (struct sockaddr *)su, size); + if (ret < 0) + zlog (NULL, LOG_WARNING, "can't bind socket : %s", strerror (errno)); + + return ret; +} + +int +sockopt_reuseaddr (int sock) +{ + int ret; + int on = 1; + + ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, + (void *) &on, sizeof (on)); + if (ret < 0) + { + zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEADDR to socket %d", sock); + return -1; + } + return 0; +} + +#ifdef SO_REUSEPORT +int +sockopt_reuseport (int sock) +{ + int ret; + int on = 1; + + ret = setsockopt (sock, SOL_SOCKET, SO_REUSEPORT, + (void *) &on, sizeof (on)); + if (ret < 0) + { + zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEADDR to socket %d", sock); + return -1; + } + return 0; +} +#else +int +sockopt_reuseport (int sock) +{ + return 0; +} +#endif /* 0 */ + +int +sockopt_ttl (int family, int sock, int ttl) +{ + int ret; + +#ifdef IP_TTL + if (family == AF_INET) + { + ret = setsockopt (sock, IPPROTO_IP, IP_TTL, + (void *) &ttl, sizeof (int)); + if (ret < 0) + { + zlog (NULL, LOG_WARNING, "can't set sockopt IP_TTL %d to socket %d", ttl, sock); + return -1; + } + return 0; + } +#endif /* IP_TTL */ +#ifdef HAVE_IPV6 + if (family == AF_INET6) + { + ret = setsockopt (sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, + (void *) &ttl, sizeof (int)); + if (ret < 0) + { + zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_UNICAST_HOPS %d to socket %d", + ttl, sock); + return -1; + } + return 0; + } +#endif /* HAVE_IPV6 */ + return 0; +} + +/* If same family and same prefix return 1. */ +int +sockunion_same (union sockunion *su1, union sockunion *su2) +{ + int ret = 0; + + if (su1->sa.sa_family != su2->sa.sa_family) + return 0; + + switch (su1->sa.sa_family) + { + case AF_INET: + ret = memcmp (&su1->sin.sin_addr, &su2->sin.sin_addr, + sizeof (struct in_addr)); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + ret = memcmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr, + sizeof (struct in6_addr)); + break; +#endif /* HAVE_IPV6 */ + } + if (ret == 0) + return 1; + else + return 0; +} + +/* After TCP connection is established. Get local address and port. */ +union sockunion * +sockunion_getsockname (int fd) +{ + int ret; + int len; + union + { + struct sockaddr sa; + struct sockaddr_in sin; +#ifdef HAVE_IPV6 + struct sockaddr_in6 sin6; +#endif /* HAVE_IPV6 */ + char tmp_buffer[128]; + } name; + union sockunion *su; + + memset (&name, 0, sizeof name); + len = sizeof name; + + ret = getsockname (fd, (struct sockaddr *)&name, &len); + if (ret < 0) + { + zlog_warn ("Can't get local address and port by getsockname: %s", + strerror (errno)); + return NULL; + } + + if (name.sa.sa_family == AF_INET) + { + su = XCALLOC (MTYPE_TMP, sizeof (union sockunion)); + memcpy (su, &name, sizeof (struct sockaddr_in)); + return su; + } +#ifdef HAVE_IPV6 + if (name.sa.sa_family == AF_INET6) + { + su = XCALLOC (MTYPE_TMP, sizeof (union sockunion)); + memcpy (su, &name, sizeof (struct sockaddr_in6)); + + if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr)) + { + struct sockaddr_in sin; + + sin.sin_family = AF_INET; + memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4); + sin.sin_port = su->sin6.sin6_port; + memcpy (su, &sin, sizeof (struct sockaddr_in)); + } + return su; + } +#endif /* HAVE_IPV6 */ + return NULL; +} + +/* After TCP connection is established. Get remote address and port. */ +union sockunion * +sockunion_getpeername (int fd) +{ + int ret; + int len; + union + { + struct sockaddr sa; + struct sockaddr_in sin; +#ifdef HAVE_IPV6 + struct sockaddr_in6 sin6; +#endif /* HAVE_IPV6 */ + char tmp_buffer[128]; + } name; + union sockunion *su; + + memset (&name, 0, sizeof name); + len = sizeof name; + ret = getpeername (fd, (struct sockaddr *)&name, &len); + if (ret < 0) + { + zlog (NULL, LOG_WARNING, "Can't get remote address and port: %s", + strerror (errno)); + return NULL; + } + + if (name.sa.sa_family == AF_INET) + { + su = XCALLOC (MTYPE_TMP, sizeof (union sockunion)); + memcpy (su, &name, sizeof (struct sockaddr_in)); + return su; + } +#ifdef HAVE_IPV6 + if (name.sa.sa_family == AF_INET6) + { + su = XCALLOC (MTYPE_TMP, sizeof (union sockunion)); + memcpy (su, &name, sizeof (struct sockaddr_in6)); + + if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr)) + { + struct sockaddr_in sin; + + sin.sin_family = AF_INET; + memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4); + sin.sin_port = su->sin6.sin6_port; + memcpy (su, &sin, sizeof (struct sockaddr_in)); + } + return su; + } +#endif /* HAVE_IPV6 */ + return NULL; +} + +/* Print sockunion structure */ +void +sockunion_print (union sockunion *su) +{ + if (su == NULL) + return; + + switch (su->sa.sa_family) + { + case AF_INET: + printf ("%s\n", inet_ntoa (su->sin.sin_addr)); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + { + char buf [64]; + + printf ("%s\n", inet_ntop (AF_INET6, &(su->sin6.sin6_addr), + buf, sizeof (buf))); + } + break; +#endif /* HAVE_IPV6 */ + +#ifdef AF_LINK + case AF_LINK: + { + struct sockaddr_dl *sdl; + + sdl = (struct sockaddr_dl *)&(su->sa); + printf ("link#%d\n", sdl->sdl_index); + } + break; +#endif /* AF_LINK */ + default: + printf ("af_unknown %d\n", su->sa.sa_family); + break; + } +} + +#ifdef HAVE_IPV6 +int +in6addr_cmp (struct in6_addr *addr1, struct in6_addr *addr2) +{ + int i; + u_char *p1, *p2; + + p1 = (u_char *)addr1; + p2 = (u_char *)addr2; + + for (i = 0; i < sizeof (struct in6_addr); i++) + { + if (p1[i] > p2[i]) + return 1; + else if (p1[i] < p2[i]) + return -1; + } + return 0; +} +#endif /* HAVE_IPV6 */ + +int +sockunion_cmp (union sockunion *su1, union sockunion *su2) +{ + if (su1->sa.sa_family > su2->sa.sa_family) + return 1; + if (su1->sa.sa_family < su2->sa.sa_family) + return -1; + + if (su1->sa.sa_family == AF_INET) + { + if (ntohl (su1->sin.sin_addr.s_addr) == ntohl (su2->sin.sin_addr.s_addr)) + return 0; + if (ntohl (su1->sin.sin_addr.s_addr) > ntohl (su2->sin.sin_addr.s_addr)) + return 1; + else + return -1; + } +#ifdef HAVE_IPV6 + if (su1->sa.sa_family == AF_INET6) + return in6addr_cmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr); +#endif /* HAVE_IPV6 */ + return 0; +} + +/* Duplicate sockunion. */ +union sockunion * +sockunion_dup (union sockunion *su) +{ + union sockunion *dup = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); + memcpy (dup, su, sizeof (union sockunion)); + return dup; +} + +void +sockunion_free (union sockunion *su) +{ + XFREE (MTYPE_SOCKUNION, su); +} diff --git a/lib/sockunion.h b/lib/sockunion.h new file mode 100644 index 00000000..99bdf6a3 --- /dev/null +++ b/lib/sockunion.h @@ -0,0 +1,128 @@ +/* + * Socket union header. + * Copyright (c) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_SOCKUNION_H +#define _ZEBRA_SOCKUNION_H + +#if 0 +union sockunion { + struct sockinet { + u_char si_len; + u_char si_family; + u_short si_port; + } su_si; + struct sockaddr_in su_sin; + struct sockaddr_in6 su_sin6; +}; +#define su_len su_si.si_len +#define su_family su_si.si_family +#define su_port su_si.si_port +#endif /* 0 */ + +union sockunion +{ + struct sockaddr sa; + struct sockaddr_in sin; +#ifdef HAVE_IPV6 + struct sockaddr_in6 sin6; +#endif /* HAVE_IPV6 */ +}; + +enum connect_result +{ + connect_error, + connect_success, + connect_in_progress +}; + +/* Default address family. */ +#ifdef HAVE_IPV6 +#define AF_INET_UNION AF_INET6 +#else +#define AF_INET_UNION AF_INET +#endif + +/* Sockunion address string length. Same as INET6_ADDRSTRLEN. */ +#define SU_ADDRSTRLEN 46 + +/* Macro to set link local index to the IPv6 address. For KAME IPv6 + stack. */ +#ifdef KAME +#define IN6_LINKLOCAL_IFINDEX(a) ((a).s6_addr[2] << 8 | (a).s6_addr[3]) +#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \ + do { \ + (a).s6_addr[2] = ((i) >> 8) & 0xff; \ + (a).s6_addr[3] = (i) & 0xff; \ + } while (0) +#else +#define IN6_LINKLOCAL_IFINDEX(a) +#define SET_IN6_LINKLOCAL_IFINDEX(a, i) +#endif /* KAME */ + +/* shortcut macro to specify address field of struct sockaddr */ +#define sock2ip(X) (((struct sockaddr_in *)(X))->sin_addr.s_addr) +#ifdef HAVE_IPV6 +#define sock2ip6(X) (((struct sockaddr_in6 *)(X))->sin6_addr.s6_addr) +#endif /* HAVE_IPV6 */ + +#define sockunion_family(X) (X)->sa.sa_family + +/* Prototypes. */ +int str2sockunion (char *, union sockunion *); +const char *sockunion2str (union sockunion *, char *, size_t); +int sockunion_cmp (union sockunion *, union sockunion *); +int sockunion_same (union sockunion *, union sockunion *); + +char *sockunion_su2str (union sockunion *su); +union sockunion *sockunion_str2su (char *str); +struct in_addr sockunion_get_in_addr (union sockunion *su); +int sockunion_accept (int sock, union sockunion *); +int sockunion_stream_socket (union sockunion *); +int sockopt_reuseaddr (int); +int sockopt_reuseport (int); +int sockunion_bind (int sock, union sockunion *, unsigned short, union sockunion *); +int sockopt_ttl (int family, int sock, int ttl); +int sockunion_socket (union sockunion *su); +const char *inet_sutop (union sockunion *su, char *str); +enum connect_result +sockunion_connect (int fd, union sockunion *su, unsigned short port, unsigned int); +union sockunion *sockunion_getsockname (int); +union sockunion *sockunion_getpeername (int); +union sockunion *sockunion_dup (union sockunion *); +void sockunion_free (union sockunion *); + +#ifndef HAVE_INET_NTOP +const char * +inet_ntop (int family, const void *addrptr, char *strptr, size_t len); +#endif /* HAVE_INET_NTOP */ + +#ifndef HAVE_INET_PTON +int +inet_pton (int family, const char *strptr, void *addrptr); +#endif /* HAVE_INET_PTON */ + +#ifndef HAVE_INET_ATON +int +inet_aton (const char *cp, struct in_addr *inaddr); +#endif + +#endif /* _ZEBRA_SOCKUNION_H */ diff --git a/lib/str.c b/lib/str.c new file mode 100644 index 00000000..797e9b87 --- /dev/null +++ b/lib/str.c @@ -0,0 +1,62 @@ +/* + * zebra string function + * + * these functions are just very basic wrappers around exiting ones and + * do not offer the protection that might be expected against buffer + * overruns etc + */ + +#include + +#include "str.h" + +#ifndef HAVE_SNPRINTF +/* + * snprint() is a real basic wrapper around the standard sprintf() + * without any bounds checking + */ +int +snprintf(char *str, size_t size, const char *format, ...) +{ + va_list args; + + va_start (args, format); + + return vsprintf (str, format, args); +} +#endif + +#ifndef HAVE_STRLCPY +/* + * strlcpy is a safer version of strncpy(), checking the total + * size of the buffer + */ +size_t +strlcpy(char *dst, const char *src, size_t size) +{ + strncpy(dst, src, size); + + return (strlen(dst)); +} +#endif + +#ifndef HAVE_STRLCAT +/* + * strlcat is a safer version of strncat(), checking the total + * size of the buffer + */ +size_t +strlcat(char *dst, const char *src, size_t size) +{ + /* strncpy(dst, src, size - strlen(dst)); */ + + /* I've just added below code only for workable under Linux. So + need rewrite -- Kunihiro. */ + if (strlen (dst) + strlen (src) >= size) + return -1; + + strcat (dst, src); + + return (strlen(dst)); +} +#endif diff --git a/lib/str.h b/lib/str.h new file mode 100644 index 00000000..4098896a --- /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 index 00000000..2d4de760 --- /dev/null +++ b/lib/stream.c @@ -0,0 +1,479 @@ +/* + * Packet interface + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "stream.h" +#include "memory.h" +#include "network.h" +#include "prefix.h" + + +/*A macro to check pointers in order to not + go behind the allocated mem block + S -- stream reference + Z -- size of data to be written +*/ + +#define CHECK_SIZE(S, Z) \ + if (((S)->putp + (Z)) > (S)->size) \ + (Z) = (S)->size - (S)->putp; + +/* Stream is fixed length buffer for network output/input. */ + +/* Make stream buffer. */ +struct stream * +stream_new (size_t size) +{ + struct stream *s; + + s = XCALLOC (MTYPE_STREAM, sizeof (struct stream)); + + s->data = XCALLOC (MTYPE_STREAM_DATA, size); + s->size = size; + return s; +} + +/* Free it now. */ +void +stream_free (struct stream *s) +{ + XFREE (MTYPE_STREAM_DATA, s->data); + XFREE (MTYPE_STREAM, s); +} + +unsigned long +stream_get_getp (struct stream *s) +{ + return s->getp; +} + +unsigned long +stream_get_putp (struct stream *s) +{ + return s->putp; +} + +unsigned long +stream_get_endp (struct stream *s) +{ + return s->endp; +} + +unsigned long +stream_get_size (struct stream *s) +{ + return s->size; +} + +/* Stream structre' stream pointer related functions. */ +void +stream_set_getp (struct stream *s, unsigned long pos) +{ + s->getp = pos; +} + +void +stream_set_putp (struct stream *s, unsigned long pos) +{ + s->putp = pos; +} + +/* Forward pointer. */ +void +stream_forward (struct stream *s, int size) +{ + s->getp += size; +} + +/* Copy from stream to destination. */ +void +stream_get (void *dst, struct stream *s, size_t size) +{ + memcpy (dst, s->data + s->getp, size); + s->getp += size; +} + +/* Get next character from the stream. */ +u_char +stream_getc (struct stream *s) +{ + u_char c; + + c = s->data[s->getp]; + s->getp++; + return c; +} + +/* Get next character from the stream. */ +u_char +stream_getc_from (struct stream *s, unsigned long from) +{ + u_char c; + + c = s->data[from]; + return c; +} + +/* Get next word from the stream. */ +u_int16_t +stream_getw (struct stream *s) +{ + u_int16_t w; + + w = s->data[s->getp++] << 8; + w |= s->data[s->getp++]; + return w; +} + +/* Get next word from the stream. */ +u_int16_t +stream_getw_from (struct stream *s, unsigned long from) +{ + u_int16_t w; + + w = s->data[from++] << 8; + w |= s->data[from]; + return w; +} + +/* Get next long word from the stream. */ +u_int32_t +stream_getl (struct stream *s) +{ + u_int32_t l; + + l = s->data[s->getp++] << 24; + l |= s->data[s->getp++] << 16; + l |= s->data[s->getp++] << 8; + l |= s->data[s->getp++]; + return l; +} + +/* Get next long word from the stream. */ +u_int32_t +stream_get_ipv4 (struct stream *s) +{ + u_int32_t l; + + memcpy (&l, s->data + s->getp, 4); + s->getp += 4; + + return l; +} + +/* Copy to source to stream. */ +void +stream_put (struct stream *s, void *src, size_t size) +{ + + CHECK_SIZE(s, size); + + if (src) + memcpy (s->data + s->putp, src, size); + else + memset (s->data + s->putp, 0, size); + + s->putp += size; + if (s->putp > s->endp) + s->endp = s->putp; +} + +/* Put character to the stream. */ +int +stream_putc (struct stream *s, u_char c) +{ + if (s->putp >= s->size) return 0; + + s->data[s->putp] = c; + s->putp++; + if (s->putp > s->endp) + s->endp = s->putp; + return 1; +} + +/* Put word to the stream. */ +int +stream_putw (struct stream *s, u_int16_t w) +{ + if ((s->size - s->putp) < 2) return 0; + + s->data[s->putp++] = (u_char)(w >> 8); + s->data[s->putp++] = (u_char) w; + + if (s->putp > s->endp) + s->endp = s->putp; + return 2; +} + +/* Put long word to the stream. */ +int +stream_putl (struct stream *s, u_int32_t l) +{ + if ((s->size - s->putp) < 4) return 0; + + s->data[s->putp++] = (u_char)(l >> 24); + s->data[s->putp++] = (u_char)(l >> 16); + s->data[s->putp++] = (u_char)(l >> 8); + s->data[s->putp++] = (u_char)l; + + if (s->putp > s->endp) + s->endp = s->putp; + return 4; +} + +int +stream_putc_at (struct stream *s, unsigned long putp, u_char c) +{ + s->data[putp] = c; + return 1; +} + +int +stream_putw_at (struct stream *s, unsigned long putp, u_int16_t w) +{ + s->data[putp] = (u_char)(w >> 8); + s->data[putp + 1] = (u_char) w; + return 2; +} + +int +stream_putl_at (struct stream *s, unsigned long putp, u_int32_t l) +{ + s->data[putp] = (u_char)(l >> 24); + s->data[putp + 1] = (u_char)(l >> 16); + s->data[putp + 2] = (u_char)(l >> 8); + s->data[putp + 3] = (u_char)l; + return 4; +} + +/* Put long word to the stream. */ +int +stream_put_ipv4 (struct stream *s, u_int32_t l) +{ + if ((s->size - s->putp) < 4) + return 0; + + memcpy (s->data + s->putp, &l, 4); + s->putp += 4; + + if (s->putp > s->endp) + s->endp = s->putp; + return 4; +} + +/* Put long word to the stream. */ +int +stream_put_in_addr (struct stream *s, struct in_addr *addr) +{ + if ((s->size - s->putp) < 4) + return 0; + + memcpy (s->data + s->putp, addr, 4); + s->putp += 4; + + if (s->putp > s->endp) + s->endp = s->putp; + return 4; +} + +/* Put prefix by nlri type format. */ +int +stream_put_prefix (struct stream *s, struct prefix *p) +{ + u_char psize; + + psize = PSIZE (p->prefixlen); + + if ((s->size - s->putp) < psize) return 0; + + stream_putc (s, p->prefixlen); + memcpy (s->data + s->putp, &p->u.prefix, psize); + s->putp += psize; + + if (s->putp > s->endp) + s->endp = s->putp; + + return psize; +} + +/* Read size from fd. */ +int +stream_read (struct stream *s, int fd, size_t size) +{ + int nbytes; + + nbytes = readn (fd, s->data + s->putp, size); + + if (nbytes > 0) + { + s->putp += nbytes; + s->endp += nbytes; + } + return nbytes; +} + +/* Read size from fd. */ +int +stream_read_unblock (struct stream *s, int fd, size_t size) +{ + int nbytes; + int val; + + val = fcntl (fd, F_GETFL, 0); + fcntl (fd, F_SETFL, val|O_NONBLOCK); + nbytes = read (fd, s->data + s->putp, size); + fcntl (fd, F_SETFL, val); + + if (nbytes > 0) + { + s->putp += nbytes; + s->endp += nbytes; + } + return nbytes; +} + +/* Write data to buffer. */ +int +stream_write (struct stream *s, u_char *ptr, size_t size) +{ + + CHECK_SIZE(s, size); + + memcpy (s->data + s->putp, ptr, size); + s->putp += size; + if (s->putp > s->endp) + s->endp = s->putp; + return size; +} + +/* Return current read pointer. */ +u_char * +stream_pnt (struct stream *s) +{ + return s->data + s->getp; +} + +/* Check does this stream empty? */ +int +stream_empty (struct stream *s) +{ + if (s->putp == 0 && s->endp == 0 && s->getp == 0) + return 1; + else + return 0; +} + +/* Reset stream. */ +void +stream_reset (struct stream *s) +{ + s->putp = 0; + s->endp = 0; + s->getp = 0; +} + +/* Write stream contens to the file discriptor. */ +int +stream_flush (struct stream *s, int fd) +{ + int nbytes; + + nbytes = write (fd, s->data + s->getp, s->endp - s->getp); + + return nbytes; +} + +/* Stream first in first out queue. */ + +struct stream_fifo * +stream_fifo_new () +{ + struct stream_fifo *new; + + new = XCALLOC (MTYPE_STREAM_FIFO, sizeof (struct stream_fifo)); + return new; +} + +/* Add new stream to fifo. */ +void +stream_fifo_push (struct stream_fifo *fifo, struct stream *s) +{ + if (fifo->tail) + fifo->tail->next = s; + else + fifo->head = s; + + fifo->tail = s; + + fifo->count++; +} + +/* Delete first stream from fifo. */ +struct stream * +stream_fifo_pop (struct stream_fifo *fifo) +{ + struct stream *s; + + s = fifo->head; + + if (s) + { + fifo->head = s->next; + + if (fifo->head == NULL) + fifo->tail = NULL; + } + + fifo->count--; + + return s; +} + +/* Return first fifo entry. */ +struct stream * +stream_fifo_head (struct stream_fifo *fifo) +{ + return fifo->head; +} + +void +stream_fifo_clean (struct stream_fifo *fifo) +{ + struct stream *s; + struct stream *next; + + for (s = fifo->head; s; s = next) + { + next = s->next; + stream_free (s); + } + fifo->head = fifo->tail = NULL; + fifo->count = 0; +} + +void +stream_fifo_free (struct stream_fifo *fifo) +{ + stream_fifo_clean (fifo); + XFREE (MTYPE_STREAM_FIFO, fifo); +} diff --git a/lib/stream.h b/lib/stream.h new file mode 100644 index 00000000..c6ef3c81 --- /dev/null +++ b/lib/stream.h @@ -0,0 +1,113 @@ +/* + * Packet interface + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_STREAM_H +#define _ZEBRA_STREAM_H + +/* Stream buffer. */ +struct stream +{ + struct stream *next; + + unsigned char *data; + + /* Put pointer. */ + unsigned long putp; + + /* Get pointer. */ + unsigned long getp; + + /* End of pointer. */ + unsigned long endp; + + /* Data size. */ + unsigned long size; +}; + +/* First in first out queue structure. */ +struct stream_fifo +{ + unsigned long count; + + struct stream *head; + struct stream *tail; +}; + +/* Utility macros. */ +#define STREAM_PNT(S) ((S)->data + (S)->getp) +#define STREAM_SIZE(S) ((S)->size) +#define STREAM_REMAIN(S) ((S)->size - (S)->putp) +#define STREAM_DATA(S) ((S)->data) + +/* Stream prototypes. */ +struct stream *stream_new (size_t); +void stream_free (struct stream *); + +unsigned long stream_get_getp (struct stream *); +unsigned long stream_get_putp (struct stream *); +unsigned long stream_get_endp (struct stream *); +unsigned long stream_get_size (struct stream *); +u_char *stream_get_data (struct stream *); + +void stream_set_getp (struct stream *, unsigned long); +void stream_set_putp (struct stream *, unsigned long); + +void stream_forward (struct stream *, int); + +void stream_put (struct stream *, void *, size_t); +int stream_putc (struct stream *, u_char); +int stream_putc_at (struct stream *, unsigned long, u_char); +int stream_putw (struct stream *, u_int16_t); +int stream_putw_at (struct stream *, unsigned long, u_int16_t); +int stream_putl (struct stream *, u_int32_t); +int stream_putl_at (struct stream *, unsigned long, u_int32_t); +int stream_put_ipv4 (struct stream *, u_int32_t); +int stream_put_in_addr (struct stream *, struct in_addr *); + +void stream_get (void *, struct stream *, size_t); +u_char stream_getc (struct stream *); +u_char stream_getc_from (struct stream *, unsigned long); +u_int16_t stream_getw (struct stream *); +u_int16_t stream_getw_from (struct stream *, unsigned long); +u_int32_t stream_getl (struct stream *); +u_int32_t stream_get_ipv4 (struct stream *); + +#undef stream_read +#undef stream_write +int stream_read (struct stream *, int, size_t); +int stream_read_unblock (struct stream *, int, size_t); +int stream_write (struct stream *, u_char *, size_t); + +u_char *stream_pnt (struct stream *); +void stream_reset (struct stream *); +int stream_flush (struct stream *, int); +int stream_empty (struct stream *); + +/* Stream fifo. */ +struct stream_fifo *stream_fifo_new (); +void stream_fifo_push (struct stream_fifo *fifo, struct stream *s); +struct stream *stream_fifo_pop (struct stream_fifo *fifo); +struct stream *stream_fifo_head (struct stream_fifo *fifo); +void stream_fifo_clean (struct stream_fifo *fifo); +void stream_fifo_free (struct stream_fifo *fifo); + +#endif /* _ZEBRA_STREAM_H */ diff --git a/lib/table.c b/lib/table.c new file mode 100644 index 00000000..00ba58d9 --- /dev/null +++ b/lib/table.c @@ -0,0 +1,503 @@ +/* + * Routing Table functions. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "table.h" +#include "memory.h" +#include "sockunion.h" + +void route_node_delete (struct route_node *); +void route_table_free (struct route_table *); + +struct route_table * +route_table_init (void) +{ + struct route_table *rt; + + rt = XCALLOC (MTYPE_ROUTE_TABLE, sizeof (struct route_table)); + return rt; +} + +void +route_table_finish (struct route_table *rt) +{ + route_table_free (rt); +} + +/* Allocate new route node. */ +struct route_node * +route_node_new () +{ + struct route_node *node; + node = XCALLOC (MTYPE_ROUTE_NODE, sizeof (struct route_node)); + return node; +} + +/* Allocate new route node with prefix set. */ +struct route_node * +route_node_set (struct route_table *table, struct prefix *prefix) +{ + struct route_node *node; + + node = route_node_new (); + + prefix_copy (&node->p, prefix); + node->table = table; + + return node; +} + +/* Free route node. */ +void +route_node_free (struct route_node *node) +{ + XFREE (MTYPE_ROUTE_NODE, node); +} + +/* Free route table. */ +void +route_table_free (struct route_table *rt) +{ + struct route_node *tmp_node; + struct route_node *node; + + if (rt == NULL) + return; + + node = rt->top; + + while (node) + { + if (node->l_left) + { + node = node->l_left; + continue; + } + + if (node->l_right) + { + node = node->l_right; + continue; + } + + tmp_node = node; + node = node->parent; + + if (node != NULL) + { + if (node->l_left == tmp_node) + node->l_left = NULL; + else + node->l_right = NULL; + + route_node_free (tmp_node); + } + else + { + route_node_free (tmp_node); + break; + } + } + + XFREE (MTYPE_ROUTE_TABLE, rt); + return; +} + +/* Utility mask array. */ +static u_char maskbit[] = +{ + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff +}; + +/* Common prefix route genaration. */ +static void +route_common (struct prefix *n, struct prefix *p, struct prefix *new) +{ + int i; + u_char diff; + u_char mask; + + u_char *np = (u_char *)&n->u.prefix; + u_char *pp = (u_char *)&p->u.prefix; + u_char *newp = (u_char *)&new->u.prefix; + + for (i = 0; i < p->prefixlen / 8; i++) + { + if (np[i] == pp[i]) + newp[i] = np[i]; + else + break; + } + + new->prefixlen = i * 8; + + if (new->prefixlen != p->prefixlen) + { + diff = np[i] ^ pp[i]; + mask = 0x80; + while (new->prefixlen < p->prefixlen && !(mask & diff)) + { + mask >>= 1; + new->prefixlen++; + } + newp[i] = np[i] & maskbit[new->prefixlen % 8]; + } +} + +/* Macro version of check_bit (). */ +#define CHECK_BIT(X,P) ((((u_char *)(X))[(P) / 8]) >> (7 - ((P) % 8)) & 1) + +/* Check bit of the prefix. */ +static int +check_bit (u_char *prefix, u_char prefixlen) +{ + int offset; + int shift; + u_char *p = (u_char *)prefix; + + assert (prefixlen <= 128); + + offset = prefixlen / 8; + shift = 7 - (prefixlen % 8); + + return (p[offset] >> shift & 1); +} + +/* Macro version of set_link (). */ +#define SET_LINK(X,Y) (X)->link[CHECK_BIT(&(Y)->prefix,(X)->prefixlen)] = (Y);\ + (Y)->parent = (X) + +static void +set_link (struct route_node *node, struct route_node *new) +{ + int bit; + + bit = check_bit (&new->p.u.prefix, node->p.prefixlen); + + assert (bit == 0 || bit == 1); + + node->link[bit] = new; + new->parent = node; +} + +/* Lock node. */ +struct route_node * +route_lock_node (struct route_node *node) +{ + node->lock++; + return node; +} + +/* Unlock node. */ +void +route_unlock_node (struct route_node *node) +{ + node->lock--; + + if (node->lock == 0) + route_node_delete (node); +} + +/* Dump routing table. */ +void +route_dump_node (struct route_table *t) +{ + struct route_node *node; + char buf[46]; + + for (node = route_top (t); node != NULL; node = route_next (node)) + { + printf ("[%d] %p %s/%d\n", + node->lock, + node->info, + inet_ntop (node->p.family, &node->p.u.prefix, buf, 46), + node->p.prefixlen); + } +} + +/* Find matched prefix. */ +struct route_node * +route_node_match (struct route_table *table, struct prefix *p) +{ + struct route_node *node; + struct route_node *matched; + + matched = NULL; + node = table->top; + + /* Walk down tree. If there is matched route then store it to + matched. */ + while (node && node->p.prefixlen <= p->prefixlen && + prefix_match (&node->p, p)) + { + if (node->info) + matched = node; + node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)]; + } + + /* If matched route found, return it. */ + if (matched) + return route_lock_node (matched); + + return NULL; +} + +struct route_node * +route_node_match_ipv4 (struct route_table *table, struct in_addr *addr) +{ + struct prefix_ipv4 p; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = *addr; + + return route_node_match (table, (struct prefix *) &p); +} + +#ifdef HAVE_IPV6 +struct route_node * +route_node_match_ipv6 (struct route_table *table, struct in6_addr *addr) +{ + struct prefix_ipv6 p; + + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_PREFIXLEN; + p.prefix = *addr; + + return route_node_match (table, (struct prefix *) &p); +} +#endif /* HAVE_IPV6 */ + +/* Lookup same prefix node. Return NULL when we can't find route. */ +struct route_node * +route_node_lookup (struct route_table *table, struct prefix *p) +{ + struct route_node *node; + + node = table->top; + + while (node && node->p.prefixlen <= p->prefixlen && + prefix_match (&node->p, p)) + { + if (node->p.prefixlen == p->prefixlen && node->info) + return route_lock_node (node); + + node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)]; + } + + return NULL; +} + +/* Add node to routing table. */ +struct route_node * +route_node_get (struct route_table *table, struct prefix *p) +{ + struct route_node *new; + struct route_node *node; + struct route_node *match; + + match = NULL; + node = table->top; + while (node && node->p.prefixlen <= p->prefixlen && + prefix_match (&node->p, p)) + { + if (node->p.prefixlen == p->prefixlen) + { + route_lock_node (node); + return node; + } + match = node; + node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)]; + } + + if (node == NULL) + { + new = route_node_set (table, p); + if (match) + set_link (match, new); + else + table->top = new; + } + else + { + new = route_node_new (); + route_common (&node->p, p, &new->p); + new->p.family = p->family; + new->table = table; + set_link (new, node); + + if (match) + set_link (match, new); + else + table->top = new; + + if (new->p.prefixlen != p->prefixlen) + { + match = new; + new = route_node_set (table, p); + set_link (match, new); + } + } + route_lock_node (new); + + return new; +} + +/* Delete node from the routing table. */ +void +route_node_delete (struct route_node *node) +{ + struct route_node *child; + struct route_node *parent; + + assert (node->lock == 0); + assert (node->info == NULL); + + if (node->l_left && node->l_right) + return; + + if (node->l_left) + child = node->l_left; + else + child = node->l_right; + + parent = node->parent; + + if (child) + child->parent = parent; + + if (parent) + { + if (parent->l_left == node) + parent->l_left = child; + else + parent->l_right = child; + } + else + node->table->top = child; + + route_node_free (node); + + /* If parent node is stub then delete it also. */ + if (parent && parent->lock == 0) + route_node_delete (parent); +} + +/* Get fist node and lock it. This function is useful when one want + to lookup all the node exist in the routing table. */ +struct route_node * +route_top (struct route_table *table) +{ + /* If there is no node in the routing table return NULL. */ + if (table->top == NULL) + return NULL; + + /* Lock the top node and return it. */ + route_lock_node (table->top); + return table->top; +} + +/* Unlock current node and lock next node then return it. */ +struct route_node * +route_next (struct route_node *node) +{ + struct route_node *next; + struct route_node *start; + + /* Node may be deleted from route_unlock_node so we have to preserve + next node's pointer. */ + + if (node->l_left) + { + next = node->l_left; + route_lock_node (next); + route_unlock_node (node); + return next; + } + if (node->l_right) + { + next = node->l_right; + route_lock_node (next); + route_unlock_node (node); + return next; + } + + start = node; + while (node->parent) + { + if (node->parent->l_left == node && node->parent->l_right) + { + next = node->parent->l_right; + route_lock_node (next); + route_unlock_node (start); + return next; + } + node = node->parent; + } + route_unlock_node (start); + return NULL; +} + +/* Unlock current node and lock next node until limit. */ +struct route_node * +route_next_until (struct route_node *node, struct route_node *limit) +{ + struct route_node *next; + struct route_node *start; + + /* Node may be deleted from route_unlock_node so we have to preserve + next node's pointer. */ + + if (node->l_left) + { + next = node->l_left; + route_lock_node (next); + route_unlock_node (node); + return next; + } + if (node->l_right) + { + next = node->l_right; + route_lock_node (next); + route_unlock_node (node); + return next; + } + + start = node; + while (node->parent && node != limit) + { + if (node->parent->l_left == node && node->parent->l_right) + { + next = node->parent->l_right; + route_lock_node (next); + route_unlock_node (start); + return next; + } + node = node->parent; + } + route_unlock_node (start); + return NULL; +} diff --git a/lib/table.h b/lib/table.h new file mode 100644 index 00000000..6f090995 --- /dev/null +++ b/lib/table.h @@ -0,0 +1,74 @@ +/* + * Routing Table + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_TABLE_H +#define _ZEBRA_TABLE_H + +/* Routing table top structure. */ +struct route_table +{ + struct route_node *top; +}; + +/* Each routing entry. */ +struct route_node +{ + /* Actual prefix of this radix. */ + struct prefix p; + + /* Tree link. */ + struct route_table *table; + struct route_node *parent; + struct route_node *link[2]; +#define l_left link[0] +#define l_right link[1] + + /* Lock of this radix */ + unsigned int lock; + + /* Each node of route. */ + void *info; + + /* Aggregation. */ + void *aggregate; +}; + +/* Prototypes. */ +struct route_table *route_table_init (void); +void route_table_finish (struct route_table *); +void route_unlock_node (struct route_node *node); +void route_node_delete (struct route_node *node); +struct route_node *route_top (struct route_table *); +struct route_node *route_next (struct route_node *); +struct route_node *route_next_until (struct route_node *, struct route_node *); +struct route_node *route_node_get (struct route_table *, struct prefix *); +struct route_node *route_node_lookup (struct route_table *, struct prefix *); +struct route_node *route_lock_node (struct route_node *node); +struct route_node *route_node_match (struct route_table *, struct prefix *); +struct route_node *route_node_match_ipv4 (struct route_table *, + struct in_addr *); +#ifdef HAVE_IPV6 +struct route_node *route_node_match_ipv6 (struct route_table *, + struct in6_addr *); +#endif /* HAVE_IPV6 */ + +#endif /* _ZEBRA_TABLE_H */ diff --git a/lib/tcpfilter.c b/lib/tcpfilter.c new file mode 100644 index 00000000..4895ab5b --- /dev/null +++ b/lib/tcpfilter.c @@ -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 + +#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 index 00000000..c3d30081 --- /dev/null +++ b/lib/tcpfilter.h @@ -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 index 00000000..31bbcd77 --- /dev/null +++ b/lib/thread.c @@ -0,0 +1,668 @@ +/* Thread management routine + * Copyright (C) 1998, 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* #define DEBUG */ + +#include + +#include "thread.h" +#include "memory.h" +#include "log.h" + +/* Struct timeval's tv_usec one second value. */ +#define TIMER_SECOND_MICRO 1000000L + +struct timeval +timeval_adjust (struct timeval a) +{ + while (a.tv_usec >= TIMER_SECOND_MICRO) + { + a.tv_usec -= TIMER_SECOND_MICRO; + a.tv_sec++; + } + + while (a.tv_usec < 0) + { + a.tv_usec += TIMER_SECOND_MICRO; + a.tv_sec--; + } + + if (a.tv_sec < 0) + { + a.tv_sec = 0; + a.tv_usec = 10; + } + + if (a.tv_sec > TIMER_SECOND_MICRO) + a.tv_sec = TIMER_SECOND_MICRO; + + return a; +} + +static struct timeval +timeval_subtract (struct timeval a, struct timeval b) +{ + struct timeval ret; + + ret.tv_usec = a.tv_usec - b.tv_usec; + ret.tv_sec = a.tv_sec - b.tv_sec; + + return timeval_adjust (ret); +} + +static int +timeval_cmp (struct timeval a, struct timeval b) +{ + return (a.tv_sec == b.tv_sec + ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec); +} + +static unsigned long +timeval_elapsed (struct timeval a, struct timeval b) +{ + return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO) + + (a.tv_usec - b.tv_usec)); +} + +/* List allocation and head/tail print out. */ +static void +thread_list_debug (struct thread_list *list) +{ + printf ("count [%d] head [%p] tail [%p]\n", + list->count, list->head, list->tail); +} + +/* Debug print for thread_master. */ +void +thread_master_debug (struct thread_master *m) +{ + printf ("-----------\n"); + printf ("readlist : "); + thread_list_debug (&m->read); + printf ("writelist : "); + thread_list_debug (&m->write); + printf ("timerlist : "); + thread_list_debug (&m->timer); + printf ("eventlist : "); + thread_list_debug (&m->event); + printf ("unuselist : "); + thread_list_debug (&m->unuse); + printf ("total alloc: [%ld]\n", m->alloc); + printf ("-----------\n"); +} + +/* Allocate new thread master. */ +struct thread_master * +thread_master_create () +{ + return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER, + sizeof (struct thread_master)); +} + +/* Add a new thread to the list. */ +static void +thread_list_add (struct thread_list *list, struct thread *thread) +{ + thread->next = NULL; + thread->prev = list->tail; + if (list->tail) + list->tail->next = thread; + else + list->head = thread; + list->tail = thread; + list->count++; +} + +/* Add a new thread just before the point. */ +static void +thread_list_add_before (struct thread_list *list, + struct thread *point, + struct thread *thread) +{ + thread->next = point; + thread->prev = point->prev; + if (point->prev) + point->prev->next = thread; + else + list->head = thread; + point->prev = thread; + list->count++; +} + +/* Delete a thread from the list. */ +static struct thread * +thread_list_delete (struct thread_list *list, struct thread *thread) +{ + if (thread->next) + thread->next->prev = thread->prev; + else + list->tail = thread->prev; + if (thread->prev) + thread->prev->next = thread->next; + else + list->head = thread->next; + thread->next = thread->prev = NULL; + list->count--; + return thread; +} + +/* Move thread to unuse list. */ +static void +thread_add_unuse (struct thread_master *m, struct thread *thread) +{ + assert (m != NULL); + assert (thread->next == NULL); + assert (thread->prev == NULL); + assert (thread->type == THREAD_UNUSED); + thread_list_add (&m->unuse, thread); +} + +/* Free all unused thread. */ +static void +thread_list_free (struct thread_master *m, struct thread_list *list) +{ + struct thread *t; + struct thread *next; + + for (t = list->head; t; t = next) + { + next = t->next; + XFREE (MTYPE_THREAD, t); + list->count--; + m->alloc--; + } +} + +/* Stop thread scheduler. */ +void +thread_master_free (struct thread_master *m) +{ + thread_list_free (m, &m->read); + thread_list_free (m, &m->write); + thread_list_free (m, &m->timer); + thread_list_free (m, &m->event); + thread_list_free (m, &m->ready); + thread_list_free (m, &m->unuse); + + XFREE (MTYPE_THREAD_MASTER, m); +} + +/* Delete top of the list and return it. */ +static struct thread * +thread_trim_head (struct thread_list *list) +{ + if (list->head) + return thread_list_delete (list, list->head); + return NULL; +} + +/* Thread list is empty or not. */ +int +thread_empty (struct thread_list *list) +{ + return list->head ? 0 : 1; +} + +/* Return remain time 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 index 00000000..9de62cdd --- /dev/null +++ b/lib/thread.h @@ -0,0 +1,139 @@ +/* Thread management routine header. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_THREAD_H +#define _ZEBRA_THREAD_H + +#ifdef HAVE_RUSAGE +#define RUSAGE_T struct rusage +#define GETRUSAGE(X) getrusage (RUSAGE_SELF, X); +#else +#define RUSAGE_T struct timeval +#define GETRUSAGE(X) gettimeofday (X, NULL); +#endif /* HAVE_RUSAGE */ + +/* Linked list of thread. */ +struct thread_list +{ + struct thread *head; + struct thread *tail; + int count; +}; + +/* Master of the theads. */ +struct thread_master +{ + struct thread_list read; + struct thread_list write; + struct thread_list timer; + struct thread_list event; + struct thread_list ready; + struct thread_list unuse; + fd_set readfd; + fd_set writefd; + fd_set exceptfd; + unsigned long alloc; +}; + +/* Thread itself. */ +struct thread +{ + unsigned char type; /* thread type */ + struct thread *next; /* next pointer of the thread */ + struct thread *prev; /* previous pointer of the thread */ + struct thread_master *master; /* pointer to the struct thread_master. */ + int (*func) (struct thread *); /* event function */ + void *arg; /* event argument */ + union { + int val; /* second argument of the event. */ + int fd; /* file descriptor in case of read/write. */ + struct timeval sands; /* rest of time sands value. */ + } u; + RUSAGE_T ru; /* Indepth usage info. */ +}; + +/* Thread types. */ +#define THREAD_READ 0 +#define THREAD_WRITE 1 +#define THREAD_TIMER 2 +#define THREAD_EVENT 3 +#define THREAD_READY 4 +#define THREAD_UNUSED 5 + +/* Thread yield time. */ +#define THREAD_YIELD_TIME_SLOT 100 * 1000L /* 100ms */ + +/* Macros. */ +#define THREAD_ARG(X) ((X)->arg) +#define THREAD_FD(X) ((X)->u.fd) +#define THREAD_VAL(X) ((X)->u.val) + +#define THREAD_READ_ON(master,thread,func,arg,sock) \ + do { \ + if (! thread) \ + thread = thread_add_read (master, func, arg, sock); \ + } while (0) + +#define THREAD_WRITE_ON(master,thread,func,arg,sock) \ + do { \ + if (! thread) \ + thread = thread_add_write (master, func, arg, sock); \ + } while (0) + +#define THREAD_TIMER_ON(master,thread,func,arg,time) \ + do { \ + if (! thread) \ + thread = thread_add_timer (master, func, arg, time); \ + } while (0) + +#define THREAD_OFF(thread) \ + do { \ + if (thread) \ + { \ + thread_cancel (thread); \ + thread = NULL; \ + } \ + } while (0) + +#define THREAD_READ_OFF(thread) THREAD_OFF(thread) +#define THREAD_WRITE_OFF(thread) THREAD_OFF(thread) +#define THREAD_TIMER_OFF(thread) THREAD_OFF(thread) + +/* Prototypes. */ +struct thread_master *thread_master_create (); +struct thread *thread_add_read (struct thread_master *, + int (*)(struct thread *), void *, int); +struct thread *thread_add_write (struct thread_master *, + int (*)(struct thread *), void *, int); +struct thread *thread_add_timer (struct thread_master *, + int (*)(struct thread *), void *, long); +struct thread *thread_add_event (struct thread_master *, + int (*)(struct thread *), void *, int ); +void thread_cancel (struct thread *); +void thread_cancel_event (struct thread_master *, void *); + +struct thread *thread_fetch (struct thread_master *, struct thread *); +struct thread *thread_execute (struct thread_master *, + int (*)(struct thread *), void *, int); +void thread_call (struct thread *); +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 index 00000000..31cdc77d --- /dev/null +++ b/lib/vector.c @@ -0,0 +1,189 @@ +/* Generic vector interface routine + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "vector.h" +#include "memory.h" + +/* Initialize vector : allocate memory and return vector. */ +vector +vector_init (unsigned int size) +{ + vector v = XCALLOC (MTYPE_VECTOR, sizeof (struct _vector)); + + /* allocate at least one slot */ + if (size == 0) + size = 1; + + v->alloced = size; + v->max = 0; + v->index = XCALLOC (MTYPE_VECTOR_INDEX, sizeof (void *) * size); + return v; +} + +void +vector_only_wrapper_free (vector v) +{ + XFREE (MTYPE_VECTOR, v); +} + +void +vector_only_index_free (void *index) +{ + XFREE (MTYPE_VECTOR_INDEX, index); +} + +void +vector_free (vector v) +{ + XFREE (MTYPE_VECTOR_INDEX, v->index); + XFREE (MTYPE_VECTOR, v); +} + +vector +vector_copy (vector v) +{ + unsigned int size; + vector new = XCALLOC (MTYPE_VECTOR, sizeof (struct _vector)); + + new->max = v->max; + new->alloced = v->alloced; + + size = sizeof (void *) * (v->alloced); + new->index = XCALLOC (MTYPE_VECTOR_INDEX, size); + memcpy (new->index, v->index, size); + + return new; +} + +/* Check assigned index, and if it runs short double index pointer */ +void +vector_ensure (vector v, unsigned int num) +{ + if (v->alloced > num) + return; + + v->index = XREALLOC (MTYPE_VECTOR_INDEX, + v->index, sizeof (void *) * (v->alloced * 2)); + memset (&v->index[v->alloced], 0, sizeof (void *) * v->alloced); + v->alloced *= 2; + + if (v->alloced <= num) + vector_ensure (v, num); +} + +/* This function only returns next empty slot index. It dose not mean + the slot's index memory is assigned, please call vector_ensure() + after calling this function. */ +int +vector_empty_slot (vector v) +{ + unsigned int i; + + if (v->max == 0) + return 0; + + for (i = 0; i < v->max; i++) + if (v->index[i] == 0) + return i; + + return i; +} + +/* Set value to the smallest empty slot. */ +int +vector_set (vector v, void *val) +{ + unsigned int i; + + i = vector_empty_slot (v); + vector_ensure (v, i); + + v->index[i] = val; + + if (v->max <= i) + v->max = i + 1; + + return i; +} + +/* Set value to specified index slot. */ +int +vector_set_index (vector v, unsigned int i, void *val) +{ + vector_ensure (v, i); + + v->index[i] = val; + + if (v->max <= i) + v->max = i + 1; + + return i; +} + +/* Look up vector. */ +void * +vector_lookup (vector v, unsigned int i) +{ + if (i >= v->max) + return NULL; + return v->index[i]; +} + +/* Lookup vector, ensure it. */ +void * +vector_lookup_ensure (vector v, unsigned int i) +{ + vector_ensure (v, i); + return v->index[i]; +} + +/* Unset value at specified index slot. */ +void +vector_unset (vector v, unsigned int i) +{ + if (i >= v->alloced) + return; + + v->index[i] = NULL; + + if (i + 1 == v->max) + { + v->max--; + while (i && v->index[--i] == NULL && v->max--) + ; /* Is this ugly ? */ + } +} + +/* Count the number of not emplty slot. */ +unsigned int +vector_count (vector v) +{ + unsigned int i; + unsigned count = 0; + + for (i = 0; i < v->max; i++) + if (v->index[i] != NULL) + count++; + + return count; +} diff --git a/lib/vector.h b/lib/vector.h new file mode 100644 index 00000000..7e00c397 --- /dev/null +++ b/lib/vector.h @@ -0,0 +1,58 @@ +/* + * Generic vector interface header. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_VECTOR_H +#define _ZEBRA_VECTOR_H + +/* struct for vector */ +struct _vector +{ + unsigned int max; /* max number of used slot */ + unsigned int alloced; /* number of allocated slot */ + void **index; /* index to data */ +}; +typedef struct _vector *vector; + +#define VECTOR_MIN_SIZE 1 + +/* (Sometimes) usefull macros. This macro convert index expression to + array expression. */ +#define vector_slot(V,I) ((V)->index[(I)]) +#define vector_max(V) ((V)->max) + +/* Prototypes. */ +vector vector_init (unsigned int size); +void vector_ensure (vector v, unsigned int num); +int vector_empty_slot (vector v); +int vector_set (vector v, void *val); +int vector_set_index (vector v, unsigned int i, void *val); +void vector_unset (vector v, unsigned int i); +unsigned int vector_count (vector v); +void vector_only_wrapper_free (vector v); +void vector_only_index_free (void *index); +void vector_free (vector v); +vector vector_copy (vector v); + +void *vector_lookup (vector, unsigned int); +void *vector_lookup_ensure (vector, unsigned int); + +#endif /* _ZEBRA_VECTOR_H */ diff --git a/lib/version.h b/lib/version.h new file mode 100644 index 00000000..9a90bf4e --- /dev/null +++ b/lib/version.h @@ -0,0 +1,39 @@ +/* Zebra version + * Copyright (C) 1997, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_VERSION_H +#define _ZEBRA_VERSION_H + +#define ZEBRA_VERSION "0.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 index 00000000..d31521cc --- /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 + +#include "linklist.h" +#include "buffer.h" +#include "version.h" +#include "command.h" +#include "sockunion.h" +#include "thread.h" +#include "memory.h" +#include "str.h" +#include "log.h" +#include "prefix.h" +#include "filter.h" + +/* Vty events */ +enum event +{ + VTY_SERV, + VTY_READ, + VTY_WRITE, + VTY_TIMEOUT_RESET, +#ifdef VTYSH + VTYSH_SERV, + VTYSH_READ +#endif /* VTYSH */ +}; + +static void vty_event (enum event, int, struct vty *); + +/* Extern host structure from command.c */ +extern struct host host; + +/* Vector which store each vty structure. */ +static vector vtyvec; + +/* Vty timeout value. */ +static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT; + +/* Vty access-class command */ +static char *vty_accesslist_name = NULL; + +/* Vty access-calss for IPv6. */ +static char *vty_ipv6_accesslist_name = NULL; + +/* VTY server thread. */ +vector Vvty_serv_thread; + +/* Current directory. */ +char *vty_cwd = NULL; + +/* Configure lock. */ +static int vty_config; + +/* Login password check. */ +static int no_password_check = 0; + +/* Integrated configuration file path */ +char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG; + + +/* VTY standard output function. */ +int +vty_out (struct vty *vty, const char *format, ...) +{ + va_list args; + int len = 0; + int size = 1024; + char buf[1024]; + char *p = NULL; + + va_start (args, format); + + if (vty_shell (vty)) + vprintf (format, args); + else + { + /* Try to write to initial buffer. */ + len = vsnprintf (buf, sizeof buf, format, args); + + /* Initial buffer is not enough. */ + if (len < 0 || len >= size) + { + while (1) + { + if (len > -1) + size = len + 1; + else + size = size * 2; + + p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size); + if (! p) + return -1; + + len = vsnprintf (p, size, format, args); + + if (len > -1 && len < size) + break; + } + } + + /* When initial buffer is enough to store all output. */ + if (! p) + p = buf; + + /* Pointer p must point out buffer. */ + if (vty_shell_serv (vty)) + write (vty->fd, (u_char *) p, len); + else + buffer_write (vty->obuf, (u_char *) p, len); + + /* If p is not different with buf, it is allocated buffer. */ + if (p != buf) + XFREE (MTYPE_VTY_OUT_BUF, p); + } + + va_end (args); + + return len; +} + +int +vty_log_out (struct vty *vty, const char *proto_str, const char *format, + va_list va) +{ + int len; + char buf[1024]; + + snprintf (buf, sizeof buf, "%s: ", proto_str); + write (vty->fd, buf, strlen (proto_str) + 2); + + len = vsnprintf (buf, sizeof buf, format, va); + if (len < 0) + return -1; + write (vty->fd, (u_char *)buf, len); + + snprintf (buf, sizeof buf, "\r\n"); + write (vty->fd, buf, 2); + + return len; +} + +/* Output current time to the vty. */ +void +vty_time_print (struct vty *vty, int cr) +{ + time_t clock; + struct tm *tm; +#define TIME_BUF 25 + char buf [TIME_BUF]; + int ret; + + time (&clock); + tm = localtime (&clock); + + ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm); + if (ret == 0) + { + zlog (NULL, LOG_INFO, "strftime error"); + return; + } + if (cr) + vty_out (vty, "%s\n", buf); + else + vty_out (vty, "%s ", buf); + + return; +} + +/* Say hello to vty interface. */ +void +vty_hello (struct vty *vty) +{ + if (host.motd) + vty_out (vty, host.motd); +} + +/* Put out prompt and wait input from user. */ +static void +vty_prompt (struct vty *vty) +{ + struct utsname names; + const char*hostname; + + if (vty->type == VTY_TERM) + { + hostname = host.name; + if (!hostname) + { + uname (&names); + hostname = names.nodename; + } + vty_out (vty, cmd_prompt (vty->node), hostname); + } +} + +/* Send WILL TELOPT_ECHO to remote server. */ +void +vty_will_echo (struct vty *vty) +{ + char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' }; + vty_out (vty, "%s", cmd); +} + +/* Make suppress Go-Ahead telnet option. */ +static void +vty_will_suppress_go_ahead (struct vty *vty) +{ + char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' }; + vty_out (vty, "%s", cmd); +} + +/* Make don't use linemode over telnet. */ +static void +vty_dont_linemode (struct vty *vty) +{ + char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' }; + vty_out (vty, "%s", cmd); +} + +/* Use window size. */ +static void +vty_do_window_size (struct vty *vty) +{ + char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' }; + vty_out (vty, "%s", cmd); +} + +#if 0 /* Currently not used. */ +/* Make don't use lflow vty interface. */ +static void +vty_dont_lflow_ahead (struct vty *vty) +{ + char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' }; + vty_out (vty, "%s", cmd); +} +#endif /* 0 */ + +/* Allocate new vty struct. */ +struct vty * +vty_new () +{ + struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty)); + + new->obuf = (struct buffer *) buffer_new (100); + new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ); + new->max = VTY_BUFSIZ; + new->sb_buffer = NULL; + + return new; +} + +/* Authentication of vty */ +static void +vty_auth (struct vty *vty, char *buf) +{ + char *passwd = NULL; + enum node_type next_node = 0; + int fail; + char *crypt (const char *, const char *); + + switch (vty->node) + { + case AUTH_NODE: + if (host.encrypt) + passwd = host.password_encrypt; + else + passwd = host.password; + if (host.advanced) + next_node = host.enable ? VIEW_NODE : ENABLE_NODE; + else + next_node = VIEW_NODE; + break; + case AUTH_ENABLE_NODE: + if (host.encrypt) + passwd = host.enable_encrypt; + else + passwd = host.enable; + next_node = ENABLE_NODE; + break; + } + + if (passwd) + { + if (host.encrypt) + fail = strcmp (crypt(buf, passwd), passwd); + else + fail = strcmp (buf, passwd); + } + else + fail = 1; + + if (! fail) + { + vty->fail = 0; + vty->node = next_node; /* Success ! */ + } + else + { + vty->fail++; + if (vty->fail >= 3) + { + if (vty->node == AUTH_NODE) + { + vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE); + vty->status = VTY_CLOSE; + } + else + { + /* AUTH_ENABLE_NODE */ + vty->fail = 0; + vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE); + vty->node = VIEW_NODE; + } + } + } +} + +/* Command execution over the vty interface. */ +int +vty_command (struct vty *vty, char *buf) +{ + int ret; + vector vline; + + /* Split readline string up into the vector */ + vline = cmd_make_strvec (buf); + + if (vline == NULL) + return CMD_SUCCESS; + + ret = cmd_execute_command (vline, vty, NULL); + + if (ret != CMD_SUCCESS) + switch (ret) + { + case CMD_WARNING: + if (vty->type == VTY_FILE) + vty_out (vty, "Warning...%s", VTY_NEWLINE); + break; + case CMD_ERR_AMBIGUOUS: + vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); + break; + case CMD_ERR_NO_MATCH: + vty_out (vty, "%% Unknown command.%s", VTY_NEWLINE); + break; + case CMD_ERR_INCOMPLETE: + vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE); + break; + } + cmd_free_strvec (vline); + + return ret; +} + +char telnet_backward_char = 0x08; +char telnet_space_char = ' '; + +/* Basic function to write buffer to vty. */ +static void +vty_write (struct vty *vty, char *buf, size_t nbytes) +{ + if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE)) + return; + + /* Should we do buffering here ? And make vty_flush (vty) ? */ + buffer_write (vty->obuf, (u_char *)buf, nbytes); +} + +/* Ensure length of input buffer. Is buffer is short, double it. */ +static void +vty_ensure (struct vty *vty, int length) +{ + if (vty->max <= length) + { + vty->max *= 2; + vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max); + } +} + +/* Basic function to insert character into vty. */ +static void +vty_self_insert (struct vty *vty, char c) +{ + int i; + int length; + + vty_ensure (vty, vty->length + 1); + length = vty->length - vty->cp; + memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length); + vty->buf[vty->cp] = c; + + vty_write (vty, &vty->buf[vty->cp], length + 1); + for (i = 0; i < length; i++) + vty_write (vty, &telnet_backward_char, 1); + + vty->cp++; + vty->length++; +} + +/* Self insert character 'c' in overwrite mode. */ +static void +vty_self_insert_overwrite (struct vty *vty, char c) +{ + vty_ensure (vty, vty->length + 1); + vty->buf[vty->cp++] = c; + + if (vty->cp > vty->length) + vty->length++; + + if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE)) + return; + + vty_write (vty, &c, 1); +} + +/* Insert a word into vty interface with overwrite mode. */ +static void +vty_insert_word_overwrite (struct vty *vty, char *str) +{ + int len = strlen (str); + vty_write (vty, str, len); + strcpy (&vty->buf[vty->cp], str); + vty->cp += len; + vty->length = vty->cp; +} + +/* Forward character. */ +static void +vty_forward_char (struct vty *vty) +{ + if (vty->cp < vty->length) + { + vty_write (vty, &vty->buf[vty->cp], 1); + vty->cp++; + } +} + +/* Backward character. */ +static void +vty_backward_char (struct vty *vty) +{ + if (vty->cp > 0) + { + vty->cp--; + vty_write (vty, &telnet_backward_char, 1); + } +} + +/* Move to the beginning of the line. */ +static void +vty_beginning_of_line (struct vty *vty) +{ + while (vty->cp) + vty_backward_char (vty); +} + +/* Move to the end of the line. */ +static void +vty_end_of_line (struct vty *vty) +{ + while (vty->cp < vty->length) + vty_forward_char (vty); +} + +static void vty_kill_line_from_beginning (struct vty *); +static void vty_redraw_line (struct vty *); + +/* Print command line history. This function is called from + vty_next_line and vty_previous_line. */ +static void +vty_history_print (struct vty *vty) +{ + int length; + + vty_kill_line_from_beginning (vty); + + /* Get previous line from history buffer */ + length = strlen (vty->hist[vty->hp]); + memcpy (vty->buf, vty->hist[vty->hp], length); + vty->cp = vty->length = length; + + /* Redraw current line */ + vty_redraw_line (vty); +} + +/* Show next command line history. */ +void +vty_next_line (struct vty *vty) +{ + int try_index; + + if (vty->hp == vty->hindex) + return; + + /* Try is there history exist or not. */ + try_index = vty->hp; + if (try_index == (VTY_MAXHIST - 1)) + try_index = 0; + else + try_index++; + + /* If there is not history return. */ + if (vty->hist[try_index] == NULL) + return; + else + vty->hp = try_index; + + vty_history_print (vty); +} + +/* Show previous command line history. */ +void +vty_previous_line (struct vty *vty) +{ + int try_index; + + try_index = vty->hp; + if (try_index == 0) + try_index = VTY_MAXHIST - 1; + else + try_index--; + + if (vty->hist[try_index] == NULL) + return; + else + vty->hp = try_index; + + vty_history_print (vty); +} + +/* This function redraw all of the command line character. */ +static void +vty_redraw_line (struct vty *vty) +{ + vty_write (vty, vty->buf, vty->length); + vty->cp = vty->length; +} + +/* Forward word. */ +static void +vty_forward_word (struct vty *vty) +{ + while (vty->cp != vty->length && vty->buf[vty->cp] != ' ') + vty_forward_char (vty); + + while (vty->cp != vty->length && vty->buf[vty->cp] == ' ') + vty_forward_char (vty); +} + +/* Backward word without skipping training space. */ +static void +vty_backward_pure_word (struct vty *vty) +{ + while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') + vty_backward_char (vty); +} + +/* Backward word. */ +static void +vty_backward_word (struct vty *vty) +{ + while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ') + vty_backward_char (vty); + + while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') + vty_backward_char (vty); +} + +/* When '^D' is typed at the beginning of the line we move to the down + level. */ +static void +vty_down_level (struct vty *vty) +{ + vty_out (vty, "%s", VTY_NEWLINE); + config_exit (NULL, vty, 0, NULL); + vty_prompt (vty); + vty->cp = 0; +} + +/* When '^Z' is received from vty, move down to the enable mode. */ +void +vty_end_config (struct vty *vty) +{ + vty_out (vty, "%s", VTY_NEWLINE); + + switch (vty->node) + { + case VIEW_NODE: + case ENABLE_NODE: + /* Nothing to do. */ + break; + case CONFIG_NODE: + case INTERFACE_NODE: + case ZEBRA_NODE: + case RIP_NODE: + case RIPNG_NODE: + case BGP_NODE: + case BGP_VPNV4_NODE: + case BGP_IPV4_NODE: + case BGP_IPV4M_NODE: + case BGP_IPV6_NODE: + case RMAP_NODE: + case OSPF_NODE: + case OSPF6_NODE: + case KEYCHAIN_NODE: + case KEYCHAIN_KEY_NODE: + case MASC_NODE: + case VTY_NODE: + vty_config_unlock (vty); + vty->node = ENABLE_NODE; + break; + default: + /* Unknown node, we have to ignore it. */ + break; + } + + vty_prompt (vty); + vty->cp = 0; +} + +/* Delete a charcter at the current point. */ +static void +vty_delete_char (struct vty *vty) +{ + int i; + int size; + + if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) + return; + + if (vty->length == 0) + { + vty_down_level (vty); + return; + } + + if (vty->cp == vty->length) + return; /* completion need here? */ + + size = vty->length - vty->cp; + + vty->length--; + memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1); + vty->buf[vty->length] = '\0'; + + vty_write (vty, &vty->buf[vty->cp], size - 1); + vty_write (vty, &telnet_space_char, 1); + + for (i = 0; i < size; i++) + vty_write (vty, &telnet_backward_char, 1); +} + +/* Delete a character before the point. */ +static void +vty_delete_backward_char (struct vty *vty) +{ + if (vty->cp == 0) + return; + + vty_backward_char (vty); + vty_delete_char (vty); +} + +/* Kill rest of line from current point. */ +static void +vty_kill_line (struct vty *vty) +{ + int i; + int size; + + size = vty->length - vty->cp; + + if (size == 0) + return; + + for (i = 0; i < size; i++) + vty_write (vty, &telnet_space_char, 1); + for (i = 0; i < size; i++) + vty_write (vty, &telnet_backward_char, 1); + + memset (&vty->buf[vty->cp], 0, size); + vty->length = vty->cp; +} + +/* Kill line from the beginning. */ +static void +vty_kill_line_from_beginning (struct vty *vty) +{ + vty_beginning_of_line (vty); + vty_kill_line (vty); +} + +/* Delete a word before the point. */ +static void +vty_forward_kill_word (struct vty *vty) +{ + while (vty->cp != vty->length && vty->buf[vty->cp] == ' ') + vty_delete_char (vty); + while (vty->cp != vty->length && vty->buf[vty->cp] != ' ') + vty_delete_char (vty); +} + +/* Delete a word before the point. */ +static void +vty_backward_kill_word (struct vty *vty) +{ + while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ') + vty_delete_backward_char (vty); + while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') + vty_delete_backward_char (vty); +} + +/* Transpose chars before or at the point. */ +static void +vty_transpose_chars (struct vty *vty) +{ + char c1, c2; + + /* If length is short or point is near by the beginning of line then + return. */ + if (vty->length < 2 || vty->cp < 1) + return; + + /* In case of point is located at the end of the line. */ + if (vty->cp == vty->length) + { + c1 = vty->buf[vty->cp - 1]; + c2 = vty->buf[vty->cp - 2]; + + vty_backward_char (vty); + vty_backward_char (vty); + vty_self_insert_overwrite (vty, c1); + vty_self_insert_overwrite (vty, c2); + } + else + { + c1 = vty->buf[vty->cp]; + c2 = vty->buf[vty->cp - 1]; + + vty_backward_char (vty); + vty_self_insert_overwrite (vty, c1); + vty_self_insert_overwrite (vty, c2); + } +} + +/* Do completion at vty interface. */ +static void +vty_complete_command (struct vty *vty) +{ + int i; + int ret; + char **matched = NULL; + vector vline; + + if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) + return; + + vline = cmd_make_strvec (vty->buf); + if (vline == NULL) + return; + + /* In case of 'help \t'. */ + if (isspace ((int) vty->buf[vty->length - 1])) + vector_set (vline, '\0'); + + matched = cmd_complete_command (vline, vty, &ret); + + cmd_free_strvec (vline); + + vty_out (vty, "%s", VTY_NEWLINE); + switch (ret) + { + case CMD_ERR_AMBIGUOUS: + vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); + vty_prompt (vty); + vty_redraw_line (vty); + break; + case CMD_ERR_NO_MATCH: + /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */ + vty_prompt (vty); + vty_redraw_line (vty); + break; + case CMD_COMPLETE_FULL_MATCH: + vty_prompt (vty); + vty_redraw_line (vty); + vty_backward_pure_word (vty); + vty_insert_word_overwrite (vty, matched[0]); + vty_self_insert (vty, ' '); + XFREE (MTYPE_TMP, matched[0]); + break; + case CMD_COMPLETE_MATCH: + vty_prompt (vty); + vty_redraw_line (vty); + vty_backward_pure_word (vty); + vty_insert_word_overwrite (vty, matched[0]); + XFREE (MTYPE_TMP, matched[0]); + vector_only_index_free (matched); + return; + break; + case CMD_COMPLETE_LIST_MATCH: + for (i = 0; matched[i] != NULL; i++) + { + if (i != 0 && ((i % 6) == 0)) + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "%-10s ", matched[i]); + XFREE (MTYPE_TMP, matched[i]); + } + vty_out (vty, "%s", VTY_NEWLINE); + + vty_prompt (vty); + vty_redraw_line (vty); + break; + case CMD_ERR_NOTHING_TODO: + vty_prompt (vty); + vty_redraw_line (vty); + break; + default: + break; + } + if (matched) + vector_only_index_free (matched); +} + +void +vty_describe_fold (struct vty *vty, int cmd_width, + int desc_width, struct desc *desc) +{ + char *buf, *cmd, *p; + int pos; + + cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd; + + if (desc_width <= 0) + { + vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE); + return; + } + + buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1); + + for (p = desc->str; strlen (p) > desc_width; p += pos + 1) + { + for (pos = desc_width; pos > 0; pos--) + if (*(p + pos) == ' ') + break; + + if (pos == 0) + break; + + strncpy (buf, p, pos); + buf[pos] = '\0'; + vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE); + + cmd = ""; + } + + vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE); + + XFREE (MTYPE_TMP, buf); +} + +/* Describe matched command function. */ +static void +vty_describe_command (struct vty *vty) +{ + int ret; + vector vline; + vector describe; + int i, width, desc_width; + struct desc *desc, *desc_cr = NULL; + + vline = cmd_make_strvec (vty->buf); + + /* In case of '> ?'. */ + if (vline == NULL) + { + vline = vector_init (1); + vector_set (vline, '\0'); + } + else + if (isspace ((int) vty->buf[vty->length - 1])) + vector_set (vline, '\0'); + + describe = cmd_describe_command (vline, vty, &ret); + + vty_out (vty, "%s", VTY_NEWLINE); + + /* Ambiguous error. */ + switch (ret) + { + case CMD_ERR_AMBIGUOUS: + cmd_free_strvec (vline); + vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); + vty_prompt (vty); + vty_redraw_line (vty); + return; + break; + case CMD_ERR_NO_MATCH: + cmd_free_strvec (vline); + vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); + vty_prompt (vty); + vty_redraw_line (vty); + return; + break; + } + + /* Get width of command string. */ + width = 0; + for (i = 0; i < vector_max (describe); i++) + if ((desc = vector_slot (describe, i)) != NULL) + { + int len; + + if (desc->cmd[0] == '\0') + continue; + + len = strlen (desc->cmd); + if (desc->cmd[0] == '.') + len--; + + if (width < len) + width = len; + } + + /* Get width of description string. */ + desc_width = vty->width - (width + 6); + + /* Print out description. */ + for (i = 0; i < vector_max (describe); i++) + if ((desc = vector_slot (describe, i)) != NULL) + { + if (desc->cmd[0] == '\0') + continue; + + if (strcmp (desc->cmd, "") == 0) + { + desc_cr = desc; + continue; + } + + if (!desc->str) + vty_out (vty, " %-s%s", + desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, + VTY_NEWLINE); + else if (desc_width >= strlen (desc->str)) + vty_out (vty, " %-*s %s%s", width, + desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, + desc->str, VTY_NEWLINE); + else + vty_describe_fold (vty, width, desc_width, desc); + +#if 0 + vty_out (vty, " %-*s %s%s", width + desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, + desc->str ? desc->str : "", VTY_NEWLINE); +#endif /* 0 */ + } + + if ((desc = desc_cr)) + { + if (!desc->str) + vty_out (vty, " %-s%s", + desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, + VTY_NEWLINE); + else if (desc_width >= strlen (desc->str)) + vty_out (vty, " %-*s %s%s", width, + desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, + desc->str, VTY_NEWLINE); + else + vty_describe_fold (vty, width, desc_width, desc); + } + + cmd_free_strvec (vline); + vector_free (describe); + + vty_prompt (vty); + vty_redraw_line (vty); +} + +void +vty_clear_buf (struct vty *vty) +{ + memset (vty->buf, 0, vty->max); +} + +/* ^C stop current input and do not add command line to the history. */ +static void +vty_stop_input (struct vty *vty) +{ + vty->cp = vty->length = 0; + vty_clear_buf (vty); + vty_out (vty, "%s", VTY_NEWLINE); + + switch (vty->node) + { + case VIEW_NODE: + case ENABLE_NODE: + /* Nothing to do. */ + break; + case CONFIG_NODE: + case INTERFACE_NODE: + case ZEBRA_NODE: + case RIP_NODE: + case RIPNG_NODE: + case BGP_NODE: + case RMAP_NODE: + case OSPF_NODE: + case OSPF6_NODE: + case KEYCHAIN_NODE: + case KEYCHAIN_KEY_NODE: + case MASC_NODE: + case VTY_NODE: + vty_config_unlock (vty); + vty->node = ENABLE_NODE; + break; + default: + /* Unknown node, we have to ignore it. */ + break; + } + vty_prompt (vty); + + /* Set history pointer to the latest one. */ + vty->hp = vty->hindex; +} + +/* Add current command line to the history buffer. */ +static void +vty_hist_add (struct vty *vty) +{ + int index; + + if (vty->length == 0) + return; + + index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1; + + /* Ignore the same string as previous one. */ + if (vty->hist[index]) + if (strcmp (vty->buf, vty->hist[index]) == 0) + { + vty->hp = vty->hindex; + return; + } + + /* Insert history entry. */ + if (vty->hist[vty->hindex]) + XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]); + vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf); + + /* History index rotation. */ + vty->hindex++; + if (vty->hindex == VTY_MAXHIST) + vty->hindex = 0; + + vty->hp = vty->hindex; +} + +/* #define TELNET_OPTION_DEBUG */ + +/* Get telnet window size. */ +static int +vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes) +{ +#ifdef TELNET_OPTION_DEBUG + int i; + + for (i = 0; i < nbytes; i++) + { + switch (buf[i]) + { + case IAC: + vty_out (vty, "IAC "); + break; + case WILL: + vty_out (vty, "WILL "); + break; + case WONT: + vty_out (vty, "WONT "); + break; + case DO: + vty_out (vty, "DO "); + break; + case DONT: + vty_out (vty, "DONT "); + break; + case SB: + vty_out (vty, "SB "); + break; + case SE: + vty_out (vty, "SE "); + break; + case TELOPT_ECHO: + vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE); + break; + case TELOPT_SGA: + vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE); + break; + case TELOPT_NAWS: + vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE); + break; + default: + vty_out (vty, "%x ", buf[i]); + break; + } + } + vty_out (vty, "%s", VTY_NEWLINE); + +#endif /* TELNET_OPTION_DEBUG */ + + switch (buf[0]) + { + case SB: + buffer_reset(vty->sb_buffer); + vty->iac_sb_in_progress = 1; + return 0; + break; + case SE: + { + char *buffer = (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 + +/* VTY shell UNIX domain socket. */ +void +vty_serv_un (char *path) +{ + int ret; + int sock, len; + struct sockaddr_un serv; + mode_t old_mask; + + /* First of all, unlink existing socket */ + unlink (path); + + /* Set umask */ + old_mask = umask (0077); + + /* Make UNIX domain socket. */ + sock = socket (AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + { + perror ("sock"); + return; + } + + /* Make server socket. */ + memset (&serv, 0, sizeof (struct sockaddr_un)); + serv.sun_family = AF_UNIX; + strncpy (serv.sun_path, path, strlen (path)); +#ifdef HAVE_SUN_LEN + len = serv.sun_len = SUN_LEN(&serv); +#else + len = sizeof (serv.sun_family) + strlen (serv.sun_path); +#endif /* HAVE_SUN_LEN */ + + ret = bind (sock, (struct sockaddr *) &serv, len); + if (ret < 0) + { + perror ("bind"); + close (sock); /* Avoid sd leak. */ + return; + } + + ret = listen (sock, 5); + if (ret < 0) + { + perror ("listen"); + close (sock); /* Avoid sd leak. */ + return; + } + + umask (old_mask); + + vty_event (VTYSH_SERV, sock, NULL); +} + +/* #define VTYSH_DEBUG 1 */ + +static int +vtysh_accept (struct thread *thread) +{ + int accept_sock; + int sock; + int client_len; + struct sockaddr_un client; + struct vty *vty; + + accept_sock = THREAD_FD (thread); + + vty_event (VTYSH_SERV, accept_sock, NULL); + + memset (&client, 0, sizeof (struct sockaddr_un)); + client_len = sizeof (struct sockaddr_un); + + sock = accept (accept_sock, (struct sockaddr *) &client, &client_len); + + if (sock < 0) + { + zlog_warn ("can't accept vty socket : %s", strerror (errno)); + return -1; + } + +#ifdef VTYSH_DEBUG + printf ("VTY shell accept\n"); +#endif /* VTYSH_DEBUG */ + + vty = vty_new (); + vty->fd = sock; + vty->type = VTY_SHELL_SERV; + vty->node = VIEW_NODE; + + vty_event (VTYSH_READ, sock, vty); + + return 0; +} + +static int +vtysh_read (struct thread *thread) +{ + int ret; + int sock; + int nbytes; + struct vty *vty; + unsigned char buf[VTY_READ_BUFSIZ]; + u_char header[4] = {0, 0, 0, 0}; + + sock = THREAD_FD (thread); + vty = THREAD_ARG (thread); + vty->t_read = NULL; + + nbytes = read (sock, buf, VTY_READ_BUFSIZ); + if (nbytes <= 0) + { + vty_close (vty); +#ifdef VTYSH_DEBUG + printf ("close vtysh\n"); +#endif /* VTYSH_DEBUG */ + return 0; + } + +#ifdef VTYSH_DEBUG + printf ("line: %s\n", buf); +#endif /* VTYSH_DEBUG */ + + vty_ensure (vty, nbytes); + memcpy (vty->buf, buf, nbytes); + + /* Pass this line to parser. */ + ret = vty_execute (vty); + + vty_clear_buf (vty); + + /* Return result. */ +#ifdef VTYSH_DEBUG + printf ("result: %d\n", ret); + printf ("vtysh node: %d\n", vty->node); +#endif /* VTYSH_DEBUG */ + + header[3] = ret; + write (vty->fd, header, 4); + + vty_event (VTYSH_READ, sock, vty); + + return 0; +} +#endif /* VTYSH */ + +/* Determine address family to bind. */ +void +vty_serv_sock (const char *hostname, unsigned short port, char *path) +{ + /* If port is set to 0, do not listen on TCP/IP at all! */ + if (port) + { + +#ifdef HAVE_IPV6 +#ifdef NRL + vty_serv_sock_family (port, AF_INET); + vty_serv_sock_family (port, AF_INET6); +#else /* ! NRL */ + vty_serv_sock_addrinfo (hostname, port); +#endif /* NRL*/ +#else /* ! HAVE_IPV6 */ + vty_serv_sock_family (port, AF_INET); +#endif /* HAVE_IPV6 */ + } + +#ifdef VTYSH + vty_serv_un (path); +#endif /* VTYSH */ +} + +/* Close vty interface. */ +void +vty_close (struct vty *vty) +{ + int i; + + /* Cancel threads.*/ + if (vty->t_read) + thread_cancel (vty->t_read); + if (vty->t_write) + thread_cancel (vty->t_write); + if (vty->t_timeout) + thread_cancel (vty->t_timeout); + if (vty->t_output) + thread_cancel (vty->t_output); + + /* Flush buffer. */ + if (! buffer_empty (vty->obuf)) + buffer_flush_all (vty->obuf, vty->fd); + + /* Free input buffer. */ + buffer_free (vty->obuf); + + /* Free SB buffer. */ + if (vty->sb_buffer) + buffer_free (vty->sb_buffer); + + /* Free command history. */ + for (i = 0; i < VTY_MAXHIST; i++) + if (vty->hist[i]) + XFREE (MTYPE_VTY_HIST, vty->hist[i]); + + /* Unset vector. */ + vector_unset (vtyvec, vty->fd); + + /* Close socket. */ + if (vty->fd > 0) + close (vty->fd); + + if (vty->address) + XFREE (0, vty->address); + if (vty->buf) + XFREE (MTYPE_VTY, vty->buf); + + /* Check configure. */ + vty_config_unlock (vty); + + /* OK free vty. */ + XFREE (MTYPE_VTY, vty); +} + +/* When time out occur output message then close connection. */ +static int +vty_timeout (struct thread *thread) +{ + struct vty *vty; + + vty = THREAD_ARG (thread); + vty->t_timeout = NULL; + vty->v_timeout = 0; + + /* Clear buffer*/ + buffer_reset (vty->obuf); + vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE); + + /* Close connection. */ + vty->status = VTY_CLOSE; + vty_close (vty); + + return 0; +} + +/* Read up configuration file from file_name. */ +static void +vty_read_file (FILE *confp) +{ + int ret; + struct vty *vty; + + vty = vty_new (); + vty->fd = 0; /* stdout */ + vty->type = VTY_TERM; + vty->node = CONFIG_NODE; + + /* Execute configuration file */ + ret = config_from_file (vty, confp); + + if (ret != CMD_SUCCESS) + { + switch (ret) + { + case CMD_ERR_AMBIGUOUS: + fprintf (stderr, "Ambiguous command.\n"); + break; + case CMD_ERR_NO_MATCH: + fprintf (stderr, "There is no such command.\n"); + break; + } + fprintf (stderr, "Error occured during reading below line.\n%s\n", + vty->buf); + vty_close (vty); + exit (1); + } + + vty_close (vty); +} + +FILE * +vty_use_backup_config (char *fullpath) +{ + char *fullpath_sav, *fullpath_tmp; + FILE *ret = NULL; + struct stat buf; + int tmp, sav; + int c; + char buffer[512]; + + fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1); + strcpy (fullpath_sav, fullpath); + strcat (fullpath_sav, CONF_BACKUP_EXT); + if (stat (fullpath_sav, &buf) == -1) + { + free (fullpath_sav); + return NULL; + } + + fullpath_tmp = malloc (strlen (fullpath) + 8); + sprintf (fullpath_tmp, "%s.XXXXXX", fullpath); + + /* Open file to configuration write. */ + tmp = mkstemp (fullpath_tmp); + if (tmp < 0) + { + free (fullpath_sav); + free (fullpath_tmp); + return NULL; + } + + sav = open (fullpath_sav, O_RDONLY); + if (sav < 0) + { + free (fullpath_sav); + free (fullpath_tmp); + unlink (fullpath_tmp); + return NULL; + } + + while((c = read (sav, buffer, 512)) > 0) + write (tmp, buffer, c); + + close (sav); + close (tmp); + + if (link (fullpath_tmp, fullpath) == 0) + ret = fopen (fullpath, "r"); + + unlink (fullpath_tmp); + + free (fullpath_sav); + free (fullpath_tmp); + return fopen (fullpath, "r"); +} + +/* Read up configuration file from file_name. */ +void +vty_read_config (char *config_file, + char *config_current_dir, + char *config_default_dir) +{ + char *cwd; + FILE *confp = NULL; + char *fullpath; + + /* If -f flag specified. */ + if (config_file != NULL) + { + if (! IS_DIRECTORY_SEP (config_file[0])) + { + cwd = getcwd (NULL, MAXPATHLEN); + fullpath = XMALLOC (MTYPE_TMP, + strlen (cwd) + strlen (config_file) + 2); + sprintf (fullpath, "%s/%s", cwd, config_file); + } + else + fullpath = config_file; + + confp = fopen (fullpath, "r"); + + if (confp == NULL) + { + confp = vty_use_backup_config (fullpath); + if (confp) + fprintf (stderr, "WARNING: using backup configuration file!\n"); + else + { + fprintf (stderr, "can't open configuration file [%s]\n", + config_file); + exit(1); + } + } + } + else + { + /* Relative path configuration file open. */ + if (config_current_dir) + { + confp = fopen (config_current_dir, "r"); + if (confp == NULL) + { + confp = vty_use_backup_config (config_current_dir); + if (confp) + fprintf (stderr, "WARNING: using backup configuration file!\n"); + } + } + + /* If there is no relative path exists, open system default file. */ + if (confp == NULL) + { +#ifdef VTYSH + int ret; + struct stat conf_stat; + + /* !!!!PLEASE LEAVE!!!! + This is NEEDED for use with vtysh -b, or else you can get + a real configuration food fight with a lot garbage in the + merged configuration file it creates coming from the per + daemon configuration files. This also allows the daemons + to start if there default configuration file is not + present or ignore them, as needed when using vtysh -b to + configure the daemons at boot - MAG */ + + /* Stat for vtysh Zebra.conf, if found startup and wait for + boot configuration */ + + if ( strstr(config_default_dir, "vtysh") == NULL) + { + ret = stat (integrate_default, &conf_stat); + if (ret >= 0) + { + return; + } + } +#endif /* VTYSH */ + + confp = fopen (config_default_dir, "r"); + if (confp == NULL) + { + confp = vty_use_backup_config (config_default_dir); + if (confp) + { + fprintf (stderr, "WARNING: using backup configuration file!\n"); + fullpath = config_default_dir; + } + else + { + fprintf (stderr, "can't open configuration file [%s]\n", + config_default_dir); + exit (1); + } + } + else + fullpath = config_default_dir; + } + else + { + /* Rleative path configuration file. */ + cwd = getcwd (NULL, MAXPATHLEN); + fullpath = XMALLOC (MTYPE_TMP, + strlen (cwd) + strlen (config_current_dir) + 2); + sprintf (fullpath, "%s/%s", cwd, config_current_dir); + } + } + vty_read_file (confp); + + fclose (confp); + + host_config_set (fullpath); +} + +/* Small utility function which output log to the VTY. */ +void +vty_log (const char *proto_str, const char *format, va_list va) +{ + int i; + struct vty *vty; + + for (i = 0; i < vector_max (vtyvec); i++) + if ((vty = vector_slot (vtyvec, i)) != NULL) + if (vty->monitor) + vty_log_out (vty, proto_str, format, va); +} + +int +vty_config_lock (struct vty *vty) +{ + if (vty_config == 0) + { + vty->config = 1; + vty_config = 1; + } + return vty->config; +} + +int +vty_config_unlock (struct vty *vty) +{ + if (vty_config == 1 && vty->config == 1) + { + vty->config = 0; + vty_config = 0; + } + return vty->config; +} + +/* Master of the threads. */ +extern struct thread_master *master; +/* struct thread_master *master; */ + +static void +vty_event (enum event event, int sock, struct vty *vty) +{ + struct thread *vty_serv_thread; + + switch (event) + { + case VTY_SERV: + vty_serv_thread = thread_add_read (master, vty_accept, vty, sock); + vector_set_index (Vvty_serv_thread, sock, vty_serv_thread); + break; +#ifdef VTYSH + case VTYSH_SERV: + thread_add_read (master, vtysh_accept, vty, sock); + break; + case VTYSH_READ: + thread_add_read (master, vtysh_read, vty, sock); + break; +#endif /* VTYSH */ + case VTY_READ: + vty->t_read = thread_add_read (master, vty_read, vty, sock); + + /* Time out treatment. */ + if (vty->v_timeout) + { + if (vty->t_timeout) + thread_cancel (vty->t_timeout); + vty->t_timeout = + thread_add_timer (master, vty_timeout, vty, vty->v_timeout); + } + break; + case VTY_WRITE: + if (! vty->t_write) + vty->t_write = thread_add_write (master, vty_flush, vty, sock); + break; + case VTY_TIMEOUT_RESET: + if (vty->t_timeout) + { + thread_cancel (vty->t_timeout); + vty->t_timeout = NULL; + } + if (vty->v_timeout) + { + vty->t_timeout = + thread_add_timer (master, vty_timeout, vty, vty->v_timeout); + } + break; + } +} + +DEFUN (config_who, + config_who_cmd, + "who", + "Display who is on vty\n") +{ + int i; + struct vty *v; + + for (i = 0; i < vector_max (vtyvec); i++) + if ((v = vector_slot (vtyvec, i)) != NULL) + vty_out (vty, "%svty[%d] connected from %s.%s", + v->config ? "*" : " ", + i, v->address, VTY_NEWLINE); + return CMD_SUCCESS; +} + +/* Move to vty configuration mode. */ +DEFUN (line_vty, + line_vty_cmd, + "line vty", + "Configure a terminal line\n" + "Virtual terminal\n") +{ + vty->node = VTY_NODE; + return CMD_SUCCESS; +} + +/* Set time out value. */ +int +exec_timeout (struct vty *vty, char *min_str, char *sec_str) +{ + unsigned long timeout = 0; + + /* min_str and sec_str are already checked by parser. So it must be + all digit string. */ + if (min_str) + { + timeout = strtol (min_str, NULL, 10); + timeout *= 60; + } + if (sec_str) + timeout += strtol (sec_str, NULL, 10); + + vty_timeout_val = timeout; + vty->v_timeout = timeout; + vty_event (VTY_TIMEOUT_RESET, 0, vty); + + + return CMD_SUCCESS; +} + +DEFUN (exec_timeout_min, + exec_timeout_min_cmd, + "exec-timeout <0-35791>", + "Set timeout value\n" + "Timeout value in minutes\n") +{ + return exec_timeout (vty, argv[0], NULL); +} + +DEFUN (exec_timeout_sec, + exec_timeout_sec_cmd, + "exec-timeout <0-35791> <0-2147483>", + "Set the EXEC timeout\n" + "Timeout in minutes\n" + "Timeout in seconds\n") +{ + return exec_timeout (vty, argv[0], argv[1]); +} + +DEFUN (no_exec_timeout, + no_exec_timeout_cmd, + "no exec-timeout", + NO_STR + "Set the EXEC timeout\n") +{ + return exec_timeout (vty, NULL, NULL); +} + +/* Set vty access class. */ +DEFUN (vty_access_class, + vty_access_class_cmd, + "access-class WORD", + "Filter connections based on an IP access list\n" + "IP access list\n") +{ + if (vty_accesslist_name) + XFREE(MTYPE_VTY, vty_accesslist_name); + + vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]); + + return CMD_SUCCESS; +} + +/* Clear vty access class. */ +DEFUN (no_vty_access_class, + no_vty_access_class_cmd, + "no access-class [WORD]", + NO_STR + "Filter connections based on an IP access list\n" + "IP access list\n") +{ + if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0]))) + { + vty_out (vty, "Access-class is not currently applied to vty%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + XFREE(MTYPE_VTY, vty_accesslist_name); + + vty_accesslist_name = NULL; + + return CMD_SUCCESS; +} + +#ifdef HAVE_IPV6 +/* Set vty access class. */ +DEFUN (vty_ipv6_access_class, + vty_ipv6_access_class_cmd, + "ipv6 access-class WORD", + IPV6_STR + "Filter connections based on an IP access list\n" + "IPv6 access list\n") +{ + if (vty_ipv6_accesslist_name) + XFREE(MTYPE_VTY, vty_ipv6_accesslist_name); + + vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]); + + return CMD_SUCCESS; +} + +/* Clear vty access class. */ +DEFUN (no_vty_ipv6_access_class, + no_vty_ipv6_access_class_cmd, + "no ipv6 access-class [WORD]", + NO_STR + IPV6_STR + "Filter connections based on an IP access list\n" + "IPv6 access list\n") +{ + if (! vty_ipv6_accesslist_name || + (argc && strcmp(vty_ipv6_accesslist_name, argv[0]))) + { + vty_out (vty, "IPv6 access-class is not currently applied to vty%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + XFREE(MTYPE_VTY, vty_ipv6_accesslist_name); + + vty_ipv6_accesslist_name = NULL; + + return CMD_SUCCESS; +} +#endif /* HAVE_IPV6 */ + +/* vty login. */ +DEFUN (vty_login, + vty_login_cmd, + "login", + "Enable password checking\n") +{ + no_password_check = 0; + return CMD_SUCCESS; +} + +DEFUN (no_vty_login, + no_vty_login_cmd, + "no login", + NO_STR + "Enable password checking\n") +{ + no_password_check = 1; + return CMD_SUCCESS; +} + +DEFUN (service_advanced_vty, + service_advanced_vty_cmd, + "service advanced-vty", + "Set up miscellaneous service\n" + "Enable advanced mode vty interface\n") +{ + host.advanced = 1; + return CMD_SUCCESS; +} + +DEFUN (no_service_advanced_vty, + no_service_advanced_vty_cmd, + "no service advanced-vty", + NO_STR + "Set up miscellaneous service\n" + "Enable advanced mode vty interface\n") +{ + host.advanced = 0; + return CMD_SUCCESS; +} + +DEFUN (terminal_monitor, + terminal_monitor_cmd, + "terminal monitor", + "Set terminal line parameters\n" + "Copy debug output to the current terminal line\n") +{ + vty->monitor = 1; + return CMD_SUCCESS; +} + +DEFUN (terminal_no_monitor, + terminal_no_monitor_cmd, + "terminal no monitor", + "Set terminal line parameters\n" + NO_STR + "Copy debug output to the current terminal line\n") +{ + vty->monitor = 0; + return CMD_SUCCESS; +} + +DEFUN (show_history, + show_history_cmd, + "show history", + SHOW_STR + "Display the session command history\n") +{ + int index; + + for (index = vty->hindex + 1; index != vty->hindex;) + { + if (index == VTY_MAXHIST) + { + index = 0; + continue; + } + + if (vty->hist[index] != NULL) + vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE); + + index++; + } + + return CMD_SUCCESS; +} + +/* Display current configuration. */ +int +vty_config_write (struct vty *vty) +{ + vty_out (vty, "line vty%s", VTY_NEWLINE); + + if (vty_accesslist_name) + vty_out (vty, " access-class %s%s", + vty_accesslist_name, VTY_NEWLINE); + + if (vty_ipv6_accesslist_name) + vty_out (vty, " ipv6 access-class %s%s", + vty_ipv6_accesslist_name, VTY_NEWLINE); + + /* exec-timeout */ + if (vty_timeout_val != VTY_TIMEOUT_DEFAULT) + vty_out (vty, " exec-timeout %ld %ld%s", + vty_timeout_val / 60, + vty_timeout_val % 60, VTY_NEWLINE); + + /* login */ + if (no_password_check) + vty_out (vty, " no login%s", VTY_NEWLINE); + + vty_out (vty, "!%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +struct cmd_node vty_node = +{ + VTY_NODE, + "%s(config-line)# ", +}; + +/* Reset all VTY status. */ +void +vty_reset () +{ + int i; + struct vty *vty; + struct thread *vty_serv_thread; + + for (i = 0; i < vector_max (vtyvec); i++) + if ((vty = vector_slot (vtyvec, i)) != NULL) + { + buffer_reset (vty->obuf); + vty->status = VTY_CLOSE; + vty_close (vty); + } + + for (i = 0; i < vector_max (Vvty_serv_thread); i++) + if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL) + { + thread_cancel (vty_serv_thread); + vector_slot (Vvty_serv_thread, i) = NULL; + close (i); + } + + vty_timeout_val = VTY_TIMEOUT_DEFAULT; + + if (vty_accesslist_name) + { + XFREE(MTYPE_VTY, vty_accesslist_name); + vty_accesslist_name = NULL; + } + + if (vty_ipv6_accesslist_name) + { + XFREE(MTYPE_VTY, vty_ipv6_accesslist_name); + vty_ipv6_accesslist_name = NULL; + } +} + +/* for ospf6d easy temprary reload function */ +/* vty_reset + close accept socket */ +void +vty_finish () +{ + int i; + struct vty *vty; + struct thread *vty_serv_thread; + + for (i = 0; i < vector_max (vtyvec); i++) + if ((vty = vector_slot (vtyvec, i)) != NULL) + { + buffer_reset (vty->obuf); + vty->status = VTY_CLOSE; + vty_close (vty); + } + + for (i = 0; i < vector_max (Vvty_serv_thread); i++) + if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL) + { + thread_cancel (vty_serv_thread); + vector_slot (Vvty_serv_thread, i) = NULL; + close (i); + } + + vty_timeout_val = VTY_TIMEOUT_DEFAULT; + + if (vty_accesslist_name) + { + XFREE(MTYPE_VTY, vty_accesslist_name); + vty_accesslist_name = NULL; + } + + if (vty_ipv6_accesslist_name) + { + XFREE(MTYPE_VTY, vty_ipv6_accesslist_name); + vty_ipv6_accesslist_name = NULL; + } +} + +void +vty_save_cwd () +{ + char *cwd; + + cwd = getcwd (NULL, MAXPATHLEN); + + vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1); + strcpy (vty_cwd, cwd); +} + +char * +vty_get_cwd () +{ + return vty_cwd; +} + +int +vty_shell (struct vty *vty) +{ + return vty->type == VTY_SHELL ? 1 : 0; +} + +int +vty_shell_serv (struct vty *vty) +{ + return vty->type == VTY_SHELL_SERV ? 1 : 0; +} + +void +vty_init_vtysh () +{ + vtyvec = vector_init (VECTOR_MIN_SIZE); +} + +/* Install vty's own commands like `who' command. */ +void +vty_init () +{ + /* For further configuration read, preserve current directory. */ + vty_save_cwd (); + + vtyvec = vector_init (VECTOR_MIN_SIZE); + + /* Initilize server thread vector. */ + Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE); + + /* Install bgp top node. */ + install_node (&vty_node, vty_config_write); + + install_element (VIEW_NODE, &config_who_cmd); + install_element (VIEW_NODE, &show_history_cmd); + install_element (ENABLE_NODE, &config_who_cmd); + install_element (CONFIG_NODE, &line_vty_cmd); + install_element (CONFIG_NODE, &service_advanced_vty_cmd); + install_element (CONFIG_NODE, &no_service_advanced_vty_cmd); + install_element (CONFIG_NODE, &show_history_cmd); + install_element (ENABLE_NODE, &terminal_monitor_cmd); + install_element (ENABLE_NODE, &terminal_no_monitor_cmd); + install_element (ENABLE_NODE, &show_history_cmd); + + install_default (VTY_NODE); + install_element (VTY_NODE, &exec_timeout_min_cmd); + install_element (VTY_NODE, &exec_timeout_sec_cmd); + install_element (VTY_NODE, &no_exec_timeout_cmd); + install_element (VTY_NODE, &vty_access_class_cmd); + install_element (VTY_NODE, &no_vty_access_class_cmd); + install_element (VTY_NODE, &vty_login_cmd); + install_element (VTY_NODE, &no_vty_login_cmd); +#ifdef HAVE_IPV6 + install_element (VTY_NODE, &vty_ipv6_access_class_cmd); + install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd); +#endif /* HAVE_IPV6 */ +} diff --git a/lib/vty.h b/lib/vty.h new file mode 100644 index 00000000..4d2a6a03 --- /dev/null +++ b/lib/vty.h @@ -0,0 +1,205 @@ +/* Virtual terminal [aka TeletYpe] interface routine + Copyright (C) 1997 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef _ZEBRA_VTY_H +#define _ZEBRA_VTY_H + +#define VTY_BUFSIZ 512 +#define VTY_MAXHIST 20 + +/* VTY struct. */ +struct vty +{ + /* File descripter of this vty. */ + int fd; + + /* Is this vty connect to file or not */ + enum {VTY_TERM, VTY_FILE, VTY_SHELL, VTY_SHELL_SERV} type; + + /* Node status of this vty */ + int node; + + /* What address is this vty comming from. */ + char *address; + + /* Privilege level of this vty. */ + int privilege; + + /* Failure count */ + int fail; + + /* Output buffer. */ + struct buffer *obuf; + + /* Command input buffer */ + char *buf; + + /* Command cursor point */ + int cp; + + /* Command length */ + int length; + + /* Command max length. */ + int max; + + /* Histry of command */ + char *hist[VTY_MAXHIST]; + + /* History lookup current point */ + int hp; + + /* History insert end point */ + int hindex; + + /* For current referencing point of interface, route-map, + access-list etc... */ + void *index; + + /* For multiple level index treatment such as key chain and key. */ + void *index_sub; + + /* For escape character. */ + unsigned char escape; + + /* Current vty status. */ + enum {VTY_NORMAL, VTY_CLOSE, VTY_MORE, VTY_MORELINE, + VTY_START, VTY_CONTINUE} status; + + /* IAC handling */ + unsigned char iac; + + /* IAC SB handling */ + unsigned char iac_sb_in_progress; + struct buffer *sb_buffer; + + /* Window width/height. */ + int width; + int height; + + int scroll_one; + + /* Configure lines. */ + int lines; + + /* Current executing function pointer. */ + int (*func) (struct vty *, void *arg); + + /* Terminal monitor. */ + int monitor; + + /* In configure mode. */ + int config; + + /* Read and write thread. */ + struct thread *t_read; + struct thread *t_write; + + /* Timeout seconds and thread. */ + unsigned long v_timeout; + struct thread *t_timeout; + + /* Thread output function. */ + struct thread *t_output; + + /* Output data pointer. */ + int (*output_func) (struct vty *, int); + void (*output_clean) (struct vty *); + void *output_rn; + unsigned long output_count; + int output_type; + void *output_arg; +}; + +/* Integrated configuration file. */ +#define INTEGRATE_DEFAULT_CONFIG "Zebra.conf" + +/* Small macro to determine newline is newline only or linefeed needed. */ +#define VTY_NEWLINE ((vty->type == VTY_TERM) ? "\r\n" : "\n") + +/* Default time out value */ +#define VTY_TIMEOUT_DEFAULT 600 + +/* Vty read buffer size. */ +#define VTY_READ_BUFSIZ 512 + +/* Directory separator. */ +#ifndef DIRECTORY_SEP +#define DIRECTORY_SEP '/' +#endif /* DIRECTORY_SEP */ + +#ifndef IS_DIRECTORY_SEP +#define IS_DIRECTORY_SEP(c) ((c) == DIRECTORY_SEP) +#endif + +/* GCC have printf type attribute check. */ +#ifdef __GNUC__ +#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b))) +#else +#define PRINTF_ATTRIBUTE(a,b) +#endif /* __GNUC__ */ + +/* Utility macro to convert VTY argument to unsigned integer. */ +#define VTY_GET_INTEGER(NAME,V,STR) \ +{ \ + char *endptr = NULL; \ + (V) = strtoul ((STR), &endptr, 10); \ + if ((V) == ULONG_MAX || *endptr != '\0') \ + { \ + vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ +} + +#define VTY_GET_INTEGER_RANGE(NAME,V,STR,MIN,MAX) \ +{ \ + char *endptr = NULL; \ + (V) = strtoul ((STR), &endptr, 10); \ + if ((V) == ULONG_MAX || *endptr != '\0' \ + || (V) < (MIN) || (V) > (MAX)) \ + { \ + vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ +} + +/* Exported variables */ +extern char integrate_default[]; + +/* Prototypes. */ +void vty_init (void); +void vty_init_vtysh (void); +void vty_reset (void); +void vty_finish (void); +struct vty *vty_new (void); +int vty_out (struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3); +void vty_read_config (char *, char *, char *); +void vty_time_print (struct vty *, int); +void vty_serv_sock (const char *, unsigned short, char *); +void vty_close (struct vty *); +char *vty_get_cwd (void); +void vty_log (const char *, const char *, va_list); +int vty_config_lock (struct vty *); +int vty_config_unlock (struct vty *); +int vty_shell (struct vty *); +int vty_shell_serv (struct vty *); +void vty_hello (struct vty *); + +#endif /* _ZEBRA_VTY_H */ diff --git a/lib/zclient.c b/lib/zclient.c new file mode 100644 index 00000000..5e371546 --- /dev/null +++ b/lib/zclient.c @@ -0,0 +1,901 @@ +/* Zebra's client library. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "stream.h" +#include "network.h" +#include "if.h" +#include "log.h" +#include "thread.h" +#include "zclient.h" +#include "memory.h" +#include "table.h" + +#include "zebra/rib.h" +#include "zebra/zserv.h" + +/* Zebra client events. */ +enum event {ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT}; + +/* Prototype for event manager. */ +static void zclient_event (enum event, struct zclient *); + +/* This file local debug flag. */ +int zclient_debug = 0; + +/* Allocate zclient structure. */ +struct zclient * +zclient_new () +{ + struct zclient *zclient; + zclient = XMALLOC (MTYPE_ZCLIENT, sizeof (struct zclient)); + memset (zclient, 0, sizeof (struct zclient)); + + zclient->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ); + zclient->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ); + + return zclient; +} + +/* Free zclient structure. */ +void +zclient_free (struct zclient *zclient) +{ + XFREE (MTYPE_ZCLIENT, zclient); +} + +/* Initialize zebra client. Argument redist_default is unwanted + redistribute route type. */ +void +zclient_init (struct zclient *zclient, int redist_default) +{ + int i; + + /* Enable zebra client connection by default. */ + zclient->enable = 1; + + /* Set -1 to the default socket value. */ + zclient->sock = -1; + + /* Clear redistribution flags. */ + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + zclient->redist[i] = 0; + + /* Set unwanted redistribute route. bgpd does not need BGP route + redistribution. */ + zclient->redist_default = redist_default; + zclient->redist[redist_default] = 1; + + /* Set default-information redistribute to zero. */ + zclient->default_information = 0; + + /* Schedule first zclient connection. */ + if (zclient_debug) + zlog_info ("zclient start scheduled"); + + zclient_event (ZCLIENT_SCHEDULE, zclient); +} + +/* Stop zebra client services. */ +void +zclient_stop (struct zclient *zclient) +{ + if (zclient_debug) + zlog_info ("zclient stopped"); + + /* Stop threads. */ + if (zclient->t_read) + { + thread_cancel (zclient->t_read); + zclient->t_read = NULL; + } + if (zclient->t_connect) + { + thread_cancel (zclient->t_connect); + zclient->t_connect = NULL; + } + + /* Close socket. */ + if (zclient->sock >= 0) + { + close (zclient->sock); + zclient->sock = -1; + } + zclient->fail = 0; +} + +void +zclient_reset (struct zclient *zclient) +{ + zclient_stop (zclient); + zclient_init (zclient, zclient->redist_default); +} + +/* Make socket to zebra daemon. Return zebra socket. */ +int +zclient_socket () +{ + int sock; + int ret; + struct sockaddr_in serv; + + /* We should think about IPv6 connection. */ + sock = socket (AF_INET, SOCK_STREAM, 0); + if (sock < 0) + return -1; + + /* Make server socket. */ + memset (&serv, 0, sizeof (struct sockaddr_in)); + serv.sin_family = AF_INET; + serv.sin_port = htons (ZEBRA_PORT); +#ifdef HAVE_SIN_LEN + serv.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + /* Connect to zebra. */ + ret = connect (sock, (struct sockaddr *) &serv, sizeof (serv)); + if (ret < 0) + { + close (sock); + return -1; + } + return sock; +} + +/* For sockaddr_un. */ +#include + +int +zclient_socket_un (char *path) +{ + int ret; + int sock, len; + struct sockaddr_un addr; + + sock = socket (AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + return -1; + + /* Make server socket. */ + memset (&addr, 0, sizeof (struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy (addr.sun_path, path, strlen (path)); +#ifdef HAVE_SUN_LEN + len = addr.sun_len = SUN_LEN(&addr); +#else + len = sizeof (addr.sun_family) + strlen (addr.sun_path); +#endif /* HAVE_SUN_LEN */ + + ret = connect (sock, (struct sockaddr *) &addr, len); + if (ret < 0) + { + close (sock); + return -1; + } + return sock; +} + +/* Send simple Zebra message. */ +int +zebra_message_send (struct zclient *zclient, int command) +{ + struct stream *s; + + /* Get zclient output buffer. */ + s = zclient->obuf; + stream_reset (s); + + /* Send very simple command only Zebra message. */ + stream_putw (s, 3); + stream_putc (s, command); + + return writen (zclient->sock, s->data, 3); +} + +/* Make connection to zebra daemon. */ +int +zclient_start (struct zclient *zclient) +{ + int i; + + if (zclient_debug) + zlog_info ("zclient_start is called"); + + /* zclient is disabled. */ + if (! zclient->enable) + return 0; + + /* If already connected to the zebra. */ + if (zclient->sock >= 0) + return 0; + + /* Check connect thread. */ + if (zclient->t_connect) + return 0; + + /* Make socket. */ +#ifdef HAVE_TCP_ZEBRA + zclient->sock = zclient_socket (); +#else + zclient->sock = zclient_socket_un (ZEBRA_SERV_PATH); +#endif /* HAVE_TCP_ZEBRA */ + if (zclient->sock < 0) + { + if (zclient_debug) + zlog_info ("zclient connection fail"); + zclient->fail++; + zclient_event (ZCLIENT_CONNECT, zclient); + return -1; + } + + /* Clear fail count. */ + zclient->fail = 0; + if (zclient_debug) + zlog_info ("zclient connect success with socket [%d]", zclient->sock); + + /* Create read thread. */ + zclient_event (ZCLIENT_READ, zclient); + + /* We need interface information. */ + zebra_message_send (zclient, ZEBRA_INTERFACE_ADD); + + /* Flush all redistribute request. */ + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + if (i != zclient->redist_default && zclient->redist[i]) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, i); + + /* If default information is needed. */ + if (zclient->default_information) + zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_ADD); + + return 0; +} + +/* This function is a wrapper function for calling zclient_start from + timer or event thread. */ +int +zclient_connect (struct thread *t) +{ + struct zclient *zclient; + + zclient = THREAD_ARG (t); + zclient->t_connect = NULL; + + if (zclient_debug) + zlog_info ("zclient_connect is called"); + + return zclient_start (zclient); +} + +int +zapi_ipv4_add (struct zclient *zclient, struct prefix_ipv4 *p, + struct zapi_ipv4 *api) +{ + int i; + int psize; + struct stream *s; + + /* Reset stream. */ + s = zclient->obuf; + stream_reset (s); + + /* Length place holder. */ + stream_putw (s, 0); + + /* Put command, type and nexthop. */ + stream_putc (s, ZEBRA_IPV4_ROUTE_ADD); + stream_putc (s, api->type); + stream_putc (s, api->flags); + stream_putc (s, api->message); + + /* Put prefix information. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *)&p->prefix, psize); + + /* Nexthop, ifindex, distance and metric information. */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) + { + if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE)) + { + stream_putc (s, 1); + stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE); + } + else + stream_putc (s, api->nexthop_num + api->ifindex_num); + + for (i = 0; i < api->nexthop_num; i++) + { + stream_putc (s, ZEBRA_NEXTHOP_IPV4); + stream_put_in_addr (s, api->nexthop[i]); + } + for (i = 0; i < api->ifindex_num; i++) + { + stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); + stream_putl (s, api->ifindex[i]); + } + } + + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE)) + stream_putc (s, api->distance); + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC)) + stream_putl (s, api->metric); + + /* Put length at the first point of the stream. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + return writen (zclient->sock, s->data, stream_get_endp (s)); +} + +int +zapi_ipv4_delete (struct zclient *zclient, struct prefix_ipv4 *p, + struct zapi_ipv4 *api) +{ + int i; + int psize; + struct stream *s; + + /* Reset stream. */ + s = zclient->obuf; + stream_reset (s); + + /* Length place holder. */ + stream_putw (s, 0); + + /* Put command, type and nexthop. */ + stream_putc (s, ZEBRA_IPV4_ROUTE_DELETE); + stream_putc (s, api->type); + stream_putc (s, api->flags); + stream_putc (s, api->message); + + /* Put prefix information. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *)&p->prefix, psize); + + /* Nexthop, ifindex, distance and metric information. */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) + { + if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE)) + { + stream_putc (s, 1); + stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE); + } + else + stream_putc (s, api->nexthop_num + api->ifindex_num); + + for (i = 0; i < api->nexthop_num; i++) + { + stream_putc (s, ZEBRA_NEXTHOP_IPV4); + stream_put_in_addr (s, api->nexthop[i]); + } + for (i = 0; i < api->ifindex_num; i++) + { + stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); + stream_putl (s, api->ifindex[i]); + } + } + + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE)) + stream_putc (s, api->distance); + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC)) + stream_putl (s, api->metric); + + /* Put length at the first point of the stream. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + return writen (zclient->sock, s->data, stream_get_endp (s)); +} + +#ifdef HAVE_IPV6 +int +zapi_ipv6_add (struct zclient *zclient, struct prefix_ipv6 *p, + struct zapi_ipv6 *api) +{ + int i; + int psize; + struct stream *s; + + /* Reset stream. */ + s = zclient->obuf; + stream_reset (s); + + /* Length place holder. */ + stream_putw (s, 0); + + /* Put command, type and nexthop. */ + stream_putc (s, ZEBRA_IPV6_ROUTE_ADD); + stream_putc (s, api->type); + stream_putc (s, api->flags); + stream_putc (s, api->message); + + /* Put prefix information. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *)&p->prefix, psize); + + /* Nexthop, ifindex, distance and metric information. */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) + { + stream_putc (s, api->nexthop_num + api->ifindex_num); + + for (i = 0; i < api->nexthop_num; i++) + { + stream_putc (s, ZEBRA_NEXTHOP_IPV6); + stream_write (s, (u_char *)api->nexthop[i], 16); + } + for (i = 0; i < api->ifindex_num; i++) + { + stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); + stream_putl (s, api->ifindex[i]); + } + } + + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE)) + stream_putc (s, api->distance); + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC)) + stream_putl (s, api->metric); + + /* Put length at the first point of the stream. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + return writen (zclient->sock, s->data, stream_get_endp (s)); +} + +int +zapi_ipv6_delete (struct zclient *zclient, struct prefix_ipv6 *p, + struct zapi_ipv6 *api) +{ + int i; + int psize; + struct stream *s; + + /* Reset stream. */ + s = zclient->obuf; + stream_reset (s); + + /* Length place holder. */ + stream_putw (s, 0); + + /* Put command, type and nexthop. */ + stream_putc (s, ZEBRA_IPV6_ROUTE_DELETE); + stream_putc (s, api->type); + stream_putc (s, api->flags); + stream_putc (s, api->message); + + /* Put prefix information. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *)&p->prefix, psize); + + /* Nexthop, ifindex, distance and metric information. */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) + { + stream_putc (s, api->nexthop_num + api->ifindex_num); + + for (i = 0; i < api->nexthop_num; i++) + { + stream_putc (s, ZEBRA_NEXTHOP_IPV6); + stream_write (s, (u_char *)api->nexthop[i], 16); + } + for (i = 0; i < api->ifindex_num; i++) + { + stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); + stream_putl (s, api->ifindex[i]); + } + } + + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE)) + stream_putc (s, api->distance); + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC)) + stream_putl (s, api->metric); + + /* Put length at the first point of the stream. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + return writen (zclient->sock, s->data, stream_get_endp (s)); +} + +#endif /* HAVE_IPV6 */ + +int +zebra_redistribute_send (int command, int sock, int type) +{ + int ret; + struct stream *s; + + s = stream_new (ZEBRA_MAX_PACKET_SIZ); + + /* Total length of the messages. */ + stream_putw (s, 4); + + stream_putc (s, command); + stream_putc (s, type); + + ret = writen (sock, s->data, 4); + + stream_free (s); + + return ret; +} + +/* Interface addition from zebra daemon. */ +struct interface * +zebra_interface_add_read (struct stream *s) +{ + struct interface *ifp; + u_char ifname_tmp[INTERFACE_NAMSIZ]; + + /* Read interface name. */ + stream_get (ifname_tmp, s, INTERFACE_NAMSIZ); + + /* Lookup this by interface name. */ + ifp = if_lookup_by_name (ifname_tmp); + + /* If such interface does not exist, make new one. */ + if (! ifp) + { + ifp = if_create (); + strncpy (ifp->name, ifname_tmp, IFNAMSIZ); + } + + /* Read interface's index. */ + ifp->ifindex = stream_getl (s); + + /* Read interface's value. */ + ifp->flags = stream_getl (s); + ifp->metric = stream_getl (s); + ifp->mtu = stream_getl (s); + ifp->bandwidth = stream_getl (s); +#ifdef HAVE_SOCKADDR_DL + stream_get (&ifp->sdl, s, sizeof (ifp->sdl)); +#else + ifp->hw_addr_len = stream_getl (s); + if (ifp->hw_addr_len) + stream_get (ifp->hw_addr, s, ifp->hw_addr_len); +#endif /* HAVE_SOCKADDR_DL */ + + return ifp; +} + +/* Read interface up/down msg from zebra daemon. */ +struct interface * +zebra_interface_state_read (struct stream *s) +{ + struct interface *ifp; + u_char ifname_tmp[INTERFACE_NAMSIZ]; + + /* Read interface name. */ + stream_get (ifname_tmp, s, INTERFACE_NAMSIZ); + + /* Lookup this by interface index. */ + ifp = if_lookup_by_name (ifname_tmp); + + /* If such interface does not exist, indicate an error */ + if (! ifp) + return NULL; + + /* Read interface's index. */ + ifp->ifindex = stream_getl (s); + + /* Read interface's value. */ + ifp->flags = stream_getl (s); + ifp->metric = stream_getl (s); + ifp->mtu = stream_getl (s); + ifp->bandwidth = stream_getl (s); + + return ifp; +} + +struct connected * +zebra_interface_address_add_read (struct stream *s) +{ + unsigned int ifindex; + struct interface *ifp; + struct connected *ifc; + struct prefix *p; + int family; + int plen; + + /* Get interface index. */ + ifindex = stream_getl (s); + + /* Lookup index. */ + ifp = if_lookup_by_index (ifindex); + if (ifp == NULL) + { + zlog_warn ("zebra_interface_address_add_read: Can't find interface by ifindex: %d ", ifindex); + return NULL; + } + + /* Allocate new connected address. */ + ifc = connected_new (); + ifc->ifp = ifp; + + /* Fetch flag. */ + ifc->flags = stream_getc (s); + + /* Fetch interface address. */ + p = prefix_new (); + family = p->family = stream_getc (s); + + plen = prefix_blen (p); + stream_get (&p->u.prefix, s, plen); + p->prefixlen = stream_getc (s); + ifc->address = p; + + /* Fetch destination address. */ + p = prefix_new (); + stream_get (&p->u.prefix, s, plen); + p->family = family; + + ifc->destination = p; + + p = ifc->address; + + /* Add connected address to the interface. */ + listnode_add (ifp->connected, ifc); + + return ifc; +} + +struct connected * +zebra_interface_address_delete_read (struct stream *s) +{ + unsigned int ifindex; + struct interface *ifp; + struct connected *ifc; + struct prefix p; + struct prefix d; + int family; + int len; + u_char flags; + + /* Get interface index. */ + ifindex = stream_getl (s); + + /* Lookup index. */ + ifp = if_lookup_by_index (ifindex); + if (ifp == NULL) + { + zlog_warn ("zebra_interface_address_delete_read: Can't find interface by ifindex: %d ", ifindex); + return NULL; + } + + /* Fetch flag. */ + flags = stream_getc (s); + + /* Fetch interface address. */ + family = p.family = stream_getc (s); + + len = prefix_blen (&p); + stream_get (&p.u.prefix, s, len); + p.prefixlen = stream_getc (s); + + /* Fetch destination address. */ + stream_get (&d.u.prefix, s, len); + d.family = family; + + ifc = connected_delete_by_prefix (ifp, &p); + + return ifc; +} + +/* Zebra client message read function. */ +int +zclient_read (struct thread *thread) +{ + int ret; + int nbytes; + int sock; + zebra_size_t length; + zebra_command_t command; + struct zclient *zclient; + + /* Get socket to zebra. */ + sock = THREAD_FD (thread); + zclient = THREAD_ARG (thread); + zclient->t_read = NULL; + + /* Clear input buffer. */ + stream_reset (zclient->ibuf); + + /* Read zebra header. */ + nbytes = stream_read (zclient->ibuf, sock, ZEBRA_HEADER_SIZE); + + /* zebra socket is closed. */ + if (nbytes == 0) + { + if (zclient_debug) + zlog_info ("zclient connection closed socket [%d].", sock); + zclient->fail++; + zclient_stop (zclient); + zclient_event (ZCLIENT_CONNECT, zclient); + return -1; + } + + /* zebra read error. */ + if (nbytes < 0 || nbytes != ZEBRA_HEADER_SIZE) + { + if (zclient_debug) + zlog_info ("Can't read all packet (length %d).", nbytes); + zclient->fail++; + zclient_stop (zclient); + zclient_event (ZCLIENT_CONNECT, zclient); + return -1; + } + + /* Fetch length and command. */ + length = stream_getw (zclient->ibuf); + command = stream_getc (zclient->ibuf); + + /* Length check. */ + if (length >= zclient->ibuf->size) + { + stream_free (zclient->ibuf); + zclient->ibuf = stream_new (length + 1); + } + length -= ZEBRA_HEADER_SIZE; + + /* Read rest of zebra packet. */ + nbytes = stream_read (zclient->ibuf, sock, length); + if (nbytes != length) + { + if (zclient_debug) + zlog_info ("zclient connection closed socket [%d].", sock); + zclient->fail++; + zclient_stop (zclient); + zclient_event (ZCLIENT_CONNECT, zclient); + return -1; + } + + switch (command) + { + case ZEBRA_INTERFACE_ADD: + if (zclient->interface_add) + ret = (*zclient->interface_add) (command, zclient, length); + break; + case ZEBRA_INTERFACE_DELETE: + if (zclient->interface_delete) + ret = (*zclient->interface_delete) (command, zclient, length); + break; + case ZEBRA_INTERFACE_ADDRESS_ADD: + if (zclient->interface_address_add) + ret = (*zclient->interface_address_add) (command, zclient, length); + break; + case ZEBRA_INTERFACE_ADDRESS_DELETE: + if (zclient->interface_address_delete) + ret = (*zclient->interface_address_delete) (command, zclient, length); + break; + case ZEBRA_INTERFACE_UP: + if (zclient->interface_up) + ret = (*zclient->interface_up) (command, zclient, length); + break; + case ZEBRA_INTERFACE_DOWN: + if (zclient->interface_down) + ret = (*zclient->interface_down) (command, zclient, length); + break; + case ZEBRA_IPV4_ROUTE_ADD: + if (zclient->ipv4_route_add) + ret = (*zclient->ipv4_route_add) (command, zclient, length); + break; + case ZEBRA_IPV4_ROUTE_DELETE: + if (zclient->ipv4_route_delete) + ret = (*zclient->ipv4_route_delete) (command, zclient, length); + break; + case ZEBRA_IPV6_ROUTE_ADD: + if (zclient->ipv6_route_add) + ret = (*zclient->ipv6_route_add) (command, zclient, length); + break; + case ZEBRA_IPV6_ROUTE_DELETE: + if (zclient->ipv6_route_delete) + ret = (*zclient->ipv6_route_delete) (command, zclient, length); + break; + default: + break; + } + + /* Register read thread. */ + zclient_event (ZCLIENT_READ, zclient); + + return 0; +} + +void +zclient_redistribute_set (struct zclient *zclient, int type) +{ + if (zclient->redist[type]) + return; + + zclient->redist[type] = 1; + + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type); +} + +void +zclient_redistribute_unset (struct zclient *zclient, int type) +{ + if (! zclient->redist[type]) + return; + + zclient->redist[type] = 0; + + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type); +} + +void +zclient_redistribute_default_set (struct zclient *zclient) +{ + if (zclient->default_information) + return; + + zclient->default_information = 1; + + if (zclient->sock > 0) + zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_ADD); +} + +void +zclient_redistribute_default_unset (struct zclient *zclient) +{ + if (! zclient->default_information) + return; + + zclient->default_information = 0; + + if (zclient->sock > 0) + zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_DELETE); +} + +extern struct thread_master *master; + +static void +zclient_event (enum event event, struct zclient *zclient) +{ + switch (event) + { + case ZCLIENT_SCHEDULE: + if (! zclient->t_connect) + zclient->t_connect = + thread_add_event (master, zclient_connect, zclient, 0); + break; + case ZCLIENT_CONNECT: + if (zclient->fail >= 10) + return; + if (zclient_debug) + zlog_info ("zclient connect schedule interval is %d", + zclient->fail < 3 ? 10 : 60); + if (! zclient->t_connect) + zclient->t_connect = + thread_add_timer (master, zclient_connect, zclient, + zclient->fail < 3 ? 10 : 60); + break; + case ZCLIENT_READ: + zclient->t_read = + thread_add_read (master, zclient_read, zclient, zclient->sock); + break; + } +} diff --git a/lib/zclient.h b/lib/zclient.h new file mode 100644 index 00000000..66307c94 --- /dev/null +++ b/lib/zclient.h @@ -0,0 +1,164 @@ +/* Zebra's client header. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_ZCLIENT_H +#define _ZEBRA_ZCLIENT_H + +/* For struct interface and struct connected. */ +#include "if.h" + +/* For input/output buffer to zebra. */ +#define ZEBRA_MAX_PACKET_SIZ 4096 + +/* Zebra header size. */ +#define ZEBRA_HEADER_SIZE 3 + +/* Structure for the zebra client. */ +struct zclient +{ + /* Socket to zebra daemon. */ + int sock; + + /* Flag of communication to zebra is enabled or not. Default is on. + This flag is disabled by `no router zebra' statement. */ + int enable; + + /* Connection failure count. */ + int fail; + + /* Input buffer for zebra message. */ + struct stream *ibuf; + + /* Output buffer for zebra message. */ + struct stream *obuf; + + /* Read and connect thread. */ + struct thread *t_read; + struct thread *t_connect; + + /* Redistribute information. */ + u_char redist_default; + u_char redist[ZEBRA_ROUTE_MAX]; + + /* Redistribute defauilt. */ + u_char default_information; + + /* Pointer to the callback functions. */ + int (*interface_add) (int, struct zclient *, zebra_size_t); + int (*interface_delete) (int, struct zclient *, zebra_size_t); + int (*interface_up) (int, struct zclient *, zebra_size_t); + int (*interface_down) (int, struct zclient *, zebra_size_t); + int (*interface_address_add) (int, struct zclient *, zebra_size_t); + int (*interface_address_delete) (int, struct zclient *, zebra_size_t); + int (*ipv4_route_add) (int, struct zclient *, zebra_size_t); + int (*ipv4_route_delete) (int, struct zclient *, zebra_size_t); + int (*ipv6_route_add) (int, struct zclient *, zebra_size_t); + int (*ipv6_route_delete) (int, struct zclient *, zebra_size_t); +}; + +/* Zebra API message flag. */ +#define ZAPI_MESSAGE_NEXTHOP 0x01 +#define ZAPI_MESSAGE_IFINDEX 0x02 +#define ZAPI_MESSAGE_DISTANCE 0x04 +#define ZAPI_MESSAGE_METRIC 0x08 + +/* Zebra IPv4 route message API. */ +struct zapi_ipv4 +{ + u_char type; + + u_char flags; + + u_char message; + + u_char nexthop_num; + struct in_addr **nexthop; + + u_char ifindex_num; + unsigned int *ifindex; + + u_char distance; + + u_int32_t metric; +}; + +int +zapi_ipv4_add (struct zclient *, struct prefix_ipv4 *, struct zapi_ipv4 *); + +int +zapi_ipv4_delete (struct zclient *, struct prefix_ipv4 *, struct zapi_ipv4 *); + +/* Prototypes of zebra client service functions. */ +struct zclient *zclient_new (void); +void zclient_free (struct zclient *); +void zclient_init (struct zclient *, int); +int zclient_start (struct zclient *); +void zclient_stop (struct zclient *); +void zclient_reset (struct zclient *); +int zclient_socket (); +int zclient_socket_un (char *); + +void zclient_redistribute_set (struct zclient *, int); +void zclient_redistribute_unset (struct zclient *, int); + +void zclient_redistribute_default_set (struct zclient *); +void zclient_redistribute_default_unset (struct zclient *); + +/* struct zebra *zebra_new (); */ +int zebra_redistribute_send (int, int, int); + +struct interface *zebra_interface_add_read (struct stream *); +struct interface *zebra_interface_state_read (struct stream *s); +struct connected *zebra_interface_address_add_read (struct stream *); +struct connected *zebra_interface_address_delete_read (struct stream *); + +#ifdef HAVE_IPV6 +/* IPv6 prefix add and delete function prototype. */ + +struct zapi_ipv6 +{ + u_char type; + + u_char flags; + + u_char message; + + u_char nexthop_num; + struct in6_addr **nexthop; + + u_char ifindex_num; + unsigned int *ifindex; + + u_char distance; + + u_int32_t metric; +}; + +int +zapi_ipv6_add (struct zclient *zclient, struct prefix_ipv6 *p, + struct zapi_ipv6 *api); +int +zapi_ipv6_delete (struct zclient *zclient, struct prefix_ipv6 *p, + struct zapi_ipv6 *api); + +#endif /* HAVE_IPV6 */ + +#endif /* _ZEBRA_ZCLIENT_H */ diff --git a/lib/zebra.h b/lib/zebra.h new file mode 100644 index 00000000..06302b3d --- /dev/null +++ b/lib/zebra.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_STROPTS_H +#include +#endif /* HAVE_STROPTS_H */ +#include +#ifdef HAVE_SYS_SELECT_H +#include +#endif /* HAVE_SYS_SELECT_H */ +#include +#include +#include +#include +#ifdef HAVE_SYS_SYSCTL_H +#include +#endif /* HAVE_SYS_SYSCTL_H */ +#include +#ifdef HAVE_SYS_CONF_H +#include +#endif /* HAVE_SYS_CONF_H */ +#ifdef HAVE_SYS_KSYM_H +#include +#endif /* HAVE_SYS_KSYM_H */ +#include +#include +#include +#include +#ifdef HAVE_RUSAGE +#include +#endif /* HAVE_RUSAGE */ + +/* machine dependent includes */ +#ifdef SUNOS_5 +#include +#include +#endif /* SUNOS_5 */ + +/* machine dependent includes */ +#ifdef HAVE_LINUX_VERSION_H +#include +#endif /* HAVE_LINUX_VERSION_H */ + +#ifdef HAVE_ASM_TYPES_H +#include +#endif /* HAVE_ASM_TYPES_H */ + +/* misc include group */ +#include +#include + +/* network include group */ + +#include + +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif /* HAVE_SYS_SOCKIO_H */ + +#ifdef HAVE_NETINET_IN_H +#include +#endif /* HAVE_NETINET_IN_H */ +#include +#include +#include + +#ifdef HAVE_NET_NETOPT_H +#include +#endif /* HAVE_NET_NETOPT_H */ + +#include + +#ifdef HAVE_NET_IF_DL_H +#include +#endif /* HAVE_NET_IF_DL_H */ + +#ifdef HAVE_NET_IF_VAR_H +#include +#endif /* HAVE_NET_IF_VAR_H */ + +#include + +#ifdef HAVE_NETLINK +#include +#include +#else +#define RT_TABLE_MAIN 0 +#endif /* HAVE_NETLINK */ + +#ifdef HAVE_NETDB_H +#include +#endif /* HAVE_NETDB_H */ + +#include +#include + +#ifdef HAVE_INET_ND_H +#include +#endif /* HAVE_INET_ND_H */ + +#ifdef HAVE_NETINET_IN_VAR_H +#include +#endif /* HAVE_NETINET_IN_VAR_H */ + +#ifdef HAVE_NETINET_IN6_VAR_H +#include +#endif /* HAVE_NETINET_IN6_VAR_H */ + +#ifdef HAVE_NETINET6_IN_H +#include +#endif /* HAVE_NETINET6_IN_H */ + + +#ifdef HAVE_NETINET6_IP6_H +#include +#endif /* HAVE_NETINET6_IP6_H */ + +#ifdef HAVE_NETINET_ICMP6_H +#include +#endif /* HAVE_NETINET_ICMP6_H */ + +#ifdef HAVE_NETINET6_ND6_H +#include +#endif /* HAVE_NETINET6_ND6_H */ + +#ifdef HAVE_LIBUTIL_H +#include +#endif /* HAVE_LIBUTIL_H */ + +#ifdef BSDI_NRL + +#ifdef HAVE_NETINET6_IN6_H +#include +#endif /* HAVE_NETINET6_IN6_H */ + +#ifdef NRL +#include +#endif /* NRL */ + +#define IN6_ARE_ADDR_EQUAL IN6_IS_ADDR_EQUAL + +/* BSD/OS 4.0 has lost belows defines, it should appear at + /usr/include/sys/socket.h. */ +#define CMSG_ALIGN(n) (((n) + 3) & ~3) +#define CMSG_SPACE(l) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(l)) +#define CMSG_LEN(l) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (l)) + +#endif /* BSDI_NRL */ + +/* The definition of struct in_pktinfo is missing in old version of + GLIBC 2.1 (Redhat 6.1). */ +#if defined (GNU_LINUX) && ! defined (HAVE_INPKTINFO) +struct in_pktinfo +{ + int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; +}; +#endif + +/* 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 index 00000000..dd583709 --- /dev/null +++ b/missing @@ -0,0 +1,336 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright 1996, 1997, 1999, 2000 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch]" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing 0.4 - GNU automake" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal*) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. + You can get \`$1Help2man' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then + # We have makeinfo, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + tar) + shift + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + fi + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar ${1+"$@"} && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar ${1+"$@"} && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" ${1+"$@"} && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" ${1+"$@"} && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 00000000..f20ccf3c --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,101 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Public domain + +# $Id: mkinstalldirs,v 1.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 index 00000000..cec4061c --- /dev/null +++ b/ospf6d/.cvsignore @@ -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 index 00000000..b7871c13 --- /dev/null +++ b/ospf6d/ChangeLog @@ -0,0 +1,809 @@ +2002-11-09 Vincent Jardin + + * ospf6_interface.c: update link-local address on interface creation. + +2002-11-09 Yasuhiro Ohara + + * ospf6_asbr.c: apply MinLSInterval to AS-External-LSA origination. + * ospf6_lsa.c: change not to issue flooding caused by expire event + when the received LSA is (already) MaxAge. + * ospf6_spf.c: fix a bug which is that ospf6d calculates + wrong nexthop when failed to find Link-LSA for the neighbor. + * ospf6_damp.c ospf6_dbex.c ospf6_neighbor.c ospf6_spf.c: + some clean up + * version: 0.9.6o + +2002-10-04 Yasuhiro Ohara + + * ospf6_asbr.c: bug of failing ASE lsa refresh fixed. + * version: 0.9.6n + +2002-10-01 Yasuhiro Ohara + + * ospf6_asbr.c: AS-External-LSA origination function + is re-written. + * ospf6_damp.[ch]: New feature that damps flaps is added. + * version: 0.9.6m + +2002-07-14 Yasuhiro Ohara + + * ospf6_spf.c: unwanted assert() in ospf6_spf_nexthop_calculation() + is deleted. + * version: 0.9.6l + +2002-07-14 Yasuhiro Ohara + + * ospf6_dbex.c: bug that ospf6d fails to refresh self-originated + LSA if he have not the LSA before has been fixed. + * ospf6_asbr.c: bug of failing removing ASE LSA when remove + message arrived from zebra has been fixed. + * version: 0.9.6k + +2002-07-13 Yasuhiro Ohara + + * ospf6_zebra.c: bug reported [zebra 14642] fixed. + The bug was related to the synchronization between zebra + and ospf6d. Now synchronization will be correctly done. + * version: 0.9.6j + +2002-07-07 Yasuhiro Ohara + + * ospf6_lsdb.c: bug fixed in ospf6_lsdb_type_router (). + * ospf6_dbex.c: because of retrans list structure changed + due to LSDB change, removal of old instance from retrans-list + is not necessary anymore. this caused crash but now fixed. + * version: 0.9.6i + +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2002-07-07 Yasuhiro Ohara + + * ospf6_lsdb.c: entirely rewritten. now ospf6d uses + radix tree by using lib/table.[ch] for LSDB lookup. + * ospf6_abr.c, ospf6_asbr.c, ospf6_intra.c: hook changed + due to rewriting of lsdb module. + * ospf6_neighbor.c: lack of check existence and find correct + instance of the LSA which is going to be removed from neighbor's + retransmission was filled. + * version: 0.9.6h + +2002-07-07 Yasuhiro Ohara + + * ospf6_intra.c: bug fix for Intra-route deletion. + * ospf6_route.c: bug fix for path comparison. + * version: 0.9.6g + +2002-06-28 Yasuhiro Ohara + + * ospf6_route.c: some logs trying to find the situation + when assert occur are added. route duration statistics + added. + * ospf6_zebra.c: trying to fix the problem reported by + [zebra 14318] but not yet sure. + * version: 0.9.6f + +2002-06-25 Yasuhiro Ohara + + * ospf6_intra.c: new file for management of intra-prefix LSA. + * ospf6_abr.c: inter area route calculation code added. + * version: 0.9.6e + +2002-06-22 Yasuhiro Ohara + + * ospf6_asbr.c: All AS-External route was removed when + one of the ASBR path was gone, but the route from other ASBR + path should stay remained. this bug is fixed. + * version: 0.9.6d + +2002-06-22 Yasuhiro Ohara + + * ospf6_route.c: route table calculation bug fixed. [zebra 14105] + * ospf6_spf.c, ospf6_route.c, etc.: log message cleaned up. + * version: 0.9.6c + +2002-04-27 Yasuhiro Ohara + + * ospf6_route.c: [zebra 13514] bug fix. + thanks to Harald Koch. + * version: 0.9.6b + +2002-04-22 Yasuhiro Ohara + + * ospf6_dump.c: fix bug of log function + * ospf6_area.c: fix bug of intra route deletion + * version: 0.9.6a + +2002-04-20 Yasuhiro Ohara + + * merged with "current" version. + * version: 0.9.6 + +2001-03-11 Yasuhiro Ohara + + * ospf6_lsdb.c ospf6_spf.c: log message changed for debug. + +2001-02-20 Yasuhiro Ohara + + * version: 0.9.5i + + * ospf6_asbr.c: Added code that finds alternative + AS-External route when remove AS-External route. + This is temporary fix ... + + * ospf6_redistribute.c: remove redistributed routes + immediately when 'no redistribute ...' + +2001-02-20 Yasuhiro Ohara + + * version: 0.9.5h + + * ospf6_spf.c, ospf6_lsa.c: Change to originate Link-LSA on + point-to-point links. + + * ospf6_message.c: Bug of log messages of self-originated + Hello packet fixed. + +2001-02-09 Yasuhiro Ohara + + * version: 0.9.5g + * ospf6_asbr.c: fix for the bug that AS-External route + is not get removed. + +2001-02-09 Yasuhiro Ohara + + * ospf6_lsdb.c: crash bug while receiving wrong LSA scope bit + has been temporarily fixed + +2001-12-20 Yasuhiro Ohara + + * ospf6_asbr.[ch]: The byte order bug in encoding/decoding + the bits/metric field in AS-External-LSA fixed. + Fixed to update E-bit in Router-LSA of itself. + Reported by Taisuke Sasaki ([zebra 11548]). + + * README: updated. + + * version: 0.9.5f + +2001-11-21 Yasuhiro Ohara + + * ospf6_prefix.c: Intra-prefix-LSA bug fixed. + * ospf6_abr.[ch]: added (only just placeholder yet) + +2001-11-20 Yasuhiro Ohara + + * ospf6_route.c: fix to overwrite a prefix when another + addition to the prefix is given. freeze function changed + not to remove routes by default. + + * version: 0.9.5e + +2001-11-19 Yasuhiro Ohara + + * version: 0.9.5d + + * ospf6_lsa.c ospf6_spf.c: SPF Calculations are now + scheduled by hook. + + * ospf6_route.c: ospf6_route_add bug fix, + ospf6_route_remove_all corrected. + +2001-11-15 Yasuhiro Ohara + + * ospf6_hook.[ch]: added. + * Almost half of the code has been rewritten. + especially, ospf6_route.[ch]. Hook call has been injected + much. + * ospf6_asbr.[ch]: added. + +2001-10-17 Yasuhiro Ohara + + * ospf6_dbex.c: ospf6d was wrong to omit reoriginating + of LSA when the self-originated LSA was received from others. + fixed. + * ospf6d.h: version: 0.9.5c + +2001-10-16 Yasuhiro Ohara + + * ospf6_lsa.c: 'force-prefix' was not executed. fixed. + * ospf6d.h: version: 0.9.5b + +2001-10-13 Yasuhiro Ohara + + * ospf6_interface.c: 'passive-interface' is now moved to + 'ipv6 ospf6 passive' in INTERFACE NODE. 'prefix-list' which + specifies the filter prefix for connected address prefix also + moved to INTERFACE NODE as 'ipv6 ospf6 advertise prefix-list WORD'. + The old obsoleted commands are still acceptable though. New command + 'ipv6 ospf6 advertise force-prefix' added, which which tells ospf6d + to advertise rather prefix than stub local-address even on loopback + or pointopoint interfaces. + + * ospf6_dump.c: 'ospf6 debug hello' -> 'ospf6 debug message hello'. + same for other message type. The older is still acceptable. + + * ospf6_lsa.c: Changed AS-External generation to new one which uses + LSA hooks. Delete old garbage. + +2001-10-02 Yasuhiro Ohara + + * ospf6d.c: turn off and turn on sequence with + 'no interface' 'interface' cmds was not work. fixed. + + * ospf6_lsa.c: generating Intra-Area-Prefix-LSA for stub + did not care duplicate prefixes. fixed. + +2001-09-07 Yasuhiro Ohara + + * ospf6_message.c: There was a bug that prevent LSDB + to syncronize. It was a DbDesc packet bug that Slave + sends two different DbDesc packet on the same sequence + number. This cause many LSAs are dropped when Exchanging + LSDB, because the latter DbDesc packet that have the same + sequence number will be ignored as duplicate packet. + This seems to be exist at least before 0.9.4 version. + Now this is the most stable candidate. + + * ospf6d.h: version 0.9.5a + +2001-09-06 Yasuhiro Ohara + + * ospf6_zebra.c ospf6_spf.c ospf6_lsa.c : + delete nexthop check to certify the nexthop is Link-local address. + Suppress Link-LSA origination on links other than Broadcast. + SPF's nexthop calculation first checks linklocal address + in Link-LSA, then checks source address of neighbor's packets. + + * ospf6_interface.c ospf6_ism.c ospf6_lsa.c ospf6_nsm.c: + intra-area-prefix-lsa origination func moved to new one. + + * ospf6_interface.h ospf6d.[ch] ospf6_lsa.c: + interface_area_cmd now changed to have 'passive' + and 'prefix-list' option. + + * ospf6_prefix.c: + clean up. + +2001-09-04 Yasuhiro Ohara + + * ospf6_dbex.c ospf6_interface.c ospf6_ism.c ospf6_lsa.[ch]: + clean up and new LSA origination functions added. + + * ospf6_route.c ospf6_lsdb.c: make vty function more + clean/understandable. + + * ospf6d.h: version 0.9.5 + +2001-08-24 Kunihiro Ishiguro + + * ospf6_lsdb.c: Use IS_LSA_MAXAGE macro instead of + ospf6_lsa_is_maxage. + + * ospf6_lsa.h (IS_LSA_MAXAGE): Add new macro to check MaxAge. + +2001-08-21 Yasuhiro Ohara + + * ospf6_lsdb.c: if There's no previous prefix + ospf6d was wrongly not calculate the prefix. + this reported by (v6 16029) is fixed. + + * ospf6_neighbor.c: Instance of LSA Summary included + in DbDesc packet was wrongly freed. The bug cause + malformed DbDesc, ExChange <-> ExStart flapping, + and then crash. + + * ospf6d.h: version 0.9.4 + +2001-08-21 Yasuhiro Ohara + + * ospf6_route.[ch]: Showing format is changed. + 'show ipv6 route ospf6' -> 'show ipv6 ospf6 route' + 'show ipv6 route ospf6 external' -> + 'show ipv6 ospf6 route redistribute' + + * ospf6_lsdb.c ospf6_lsa.c ospf6_neighbor.c ospf6_interface.c: + memory leak in LS list fixed. + + * all: clean up + + * ospf6d.h: version 0.9.3 + +2001-08-20 Kunihiro Ishiguro + + * ospf6d.c (ospf6_timeval_sub_equal): Remove function. + + * ospf6_spf.c (ospf6_timeval_cmp): Rewrite ospf6_timeval_cmp(). + (ospf6_timeval_add_equal): Function moved from ospf6d.c + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-08-09 Yasuhiro Ohara + + * ospf6_lsdb.c ospf6_neighbor.c: + LSDB function/structure and LS list function has been rewritten. + memory leak has been decreased. + + * ospf6_lsa.[ch] ospf6_dbex.c: garbage code has been deleted. + + * ospf6d.h: version 0.9.2 + +2001-08-07 Yasuhiro Ohara + + * ospf6_dbex.c ospf6_lsdb.c: + Retransmition list had a critical bug that breaks LSDB + synchronization. When new LSA be added to retrans-list, + old must be removed, but it was not. So new LSA dropped, + and LSA Acknowledgement did not work. The bug was fixed. + + * ospf6d.h: version 0.9.1 + +2001-06-20 Yasuhiro Ohara + + * ospf6_spf.c: crash bug fix in temporary treat code for + Router-LSA whose LS-ID != 0 + + * ospf6_dbex.c: RFC2328 13.(4) was wrongly coded. + (4) Else if the LSA's LS age is equal to MaxAge, and there is + currently *NO* instance of the LSA in the router's link state + ... + + * ospf6_lsa.c: RFC2328 13.1 checksum tie breaker + had been neglected, and has just added now. + + * ospf6d.h: version 0.9.0 + ospf6d expected to work with hitachi gr2000 from these fixes. + +2001-06-12 Yasuhiro Ohara + + * ospf6_lsa.c: Fix bug in creating Intra-Area-Prefix-LSA. + DR was mis-include others prefixes advertised by their Link-LSA. + + * ospf6_route.c: Fix bug in calculating intra area routes. + Not all prefixes in Intra-Area-Prefix-LSA was calculated. + + * ospf6_spf.c: + Changed to quit when a error occured in calculating SPF tree. + Very messy hack for the bug reported by [zebra 8807]. This + is not tested yet. + Changed to quit SPF calculation when a nexthop calculation + errors. + + * ospf6_zebra.c: + Support for interface address deletion. + + * ospf6d.h: + version: 0.8.y + +2001-04-18 Yasuhiro Ohara + + * ospf6d.h + Due to previous change (DR Election algorithm changed), + backward compatibility will be lost from this version. + version: 0.8.x + +2001-04-18 Yasuhiro Ohara + + * ospf6_message.c ospf6_ism.c: + Bug of router_id comparison + +2001-04-17 Yasuhiro Ohara + + * ospf6_dbex.c: ospf6_dbex_is_maxage_to_be_dropped() had + some bug causing Loading state lasts long. + version: 0.8.v + +2001-04-08 Yasuhiro Ohara + + * ospf6_route.c: BUG in AS-External route calculation fixed. + It was using OLD LSDB... + Version: 0.8.u- + +2001-04-08 Yasuhiro Ohara + + * ospf6_area.c, ospf6_dbex.c, ospf6_interface.c, + ospf6_lsa.c, ospf6_lsdb.c, ospf6_lsdb.h, ospf6_message.c, + ospf6_neighbor.c, ospf6_neighbor.h, ospf6_nsm.c, + ospf6_redistribute.c, ospf6_route.c, ospf6_spf.c: + Delete old LSDB function. + + * ospf6d.h: + Version: 0.8.u + +2001-04-05 Yasuhiro Ohara + + * ospf6_area.c, ospf6_area.h, ospf6_dbex.c, ospf6_interface.c, + ospf6_interface.h, ospf6_lsa.c, ospf6_lsdb.c, ospf6_lsdb.h, + ospf6_message.c, ospf6_nsm.c, ospf6_redistribute.c, ospf6_route.c, + ospf6_spf.c, ospf6_top.c, ospf6_top.h, ospf6d.h: + Changed to use New LSDB. + Version: 0.8.t + +2001-04-02 Yasuhiro Ohara + + * ospf6_lsa.c: + Interface stub check in Intra-Area-Prefix-LSA origination + was wrong. - fixed. + + * ospf6_area.h, ospf6_dbex.c, ospf6_interface.c, + ospf6_interface.h, ospf6_lsa.c, ospf6_lsa.h, ospf6_lsdb.c, + ospf6_message.c, ospf6_neighbor.c, ospf6_nsm.c, + ospf6_redistribute.c, ospf6_top.c, ospf6_top.h, ospf6d.c: + New LSDB functions, but not changed to be used. + + * ospf6d.h: + Version: 0.8.s + +2001-03-28 Yasuhiro Ohara + + * ospf6_area.c ospf6_area.h ospf6_dbex.c ospf6_dump.c + ospf6_interface.c ospf6_interface.h ospf6_lsa.c + ospf6_message.c ospf6_redistribute.c ospf6_spf.c ospf6_top.c + ospf6_top.h ospf6_zebra.c ospf6d.c ospf6d.h: cleaning. + +2001-03-24 Yasuhiro Ohara + + * ospf6d.h: + version: 0.8.r + + * ospf6_neighbor.[ch], ospf6_lsa.[ch]: + just clean up and log clearify. + + * ospf6_message.[ch]: + Packet receiving function and dumping OSPFv3 packet has been + changed simple and clean. + + * ospf6_dbex.[ch], ospf6_interface.[ch], ospf6_lsdb.[ch], + ospf6_neighbor.[ch], ospf6_nsm.[ch]: + LSList(i.e. summary list, request list, retrans list, etc) have + been rewritten based on new LSDB module. The main LSDB have not + yet shifted to this new module, but will shift eventually. + This change expected to resolve the problem that the ospf6d keeps + on sending redundant LSUpdate/LSAck. + + * ospf6_interface.c: changed default MTU from 1500 to 1280. + It was possible that the ospf6d could not send packet (e.g. + LSUpdate in response to LSReq in my case) when the packet + size accidentally reached near 1500 (I was forget about IP + header :p). It is a bit illegal to set MTU 1280 constantly, + but I failed once with I/F MTU from kernel (through zebra), + and thinks that 1280 is more stable than kernel variable. + Comments will be appriciated. + +2001-03-15 Yasuhiro Ohara + + * ospf6_dbex.c, ospf6_interface.c, ospf6_ism.c, ospf6_lsdb.[ch], + ospf6_neighbor.c, ospf6_spf.c, ospf6d.c: + Fix for crash. ospf6d has ever been crashing when + 'no interface' command executed, and when starting up with + the configuration which does not include 'router ospf6'. + these has been fixed. + +2001-02-24 Yasuhiro Ohara + + * ospf6_lsa.c, ospf6_message.c: + LSA summary (exchanged while Adjacency bring up) may expire + (may reach MaxAge). Handling this has been added but + it's a little bit quick hack. + + * ospf6_message.c: + Thread chain bug fixed. Read network thread chain has been cut + when receive packets on not-enabled interface. this was wrong + and fixed. + +2001-02-24 Yasuhiro Ohara + + * ospf6_message.c: + I/F MTU check part on sending packet had some bug, and it's fixed. + Ospf6d has believed a value from zebra as I/F MTU, but from now + I/F MTU is set to constant 1500. This is workaround for ATM. + +2001-02-01 Kunihiro Ishiguro + + * zebra-0.91 is released. + +2001-01-04 Yasuhiro Ohara + + * just code clean up of almost all module. + * ospf6_dump.c, ospf6_lsa.c: file dependency. + * ospf6_mesg.[ch]: changed filename to ospf6_message.[ch] + +2001-01-09 Kunihiro Ishiguro + + * zebra-0.90 is released. + +2001-01-04 Yasuhiro Ohara + + * ospf6_mesg.c,ospf6_lsa.c: doubly cancel thread bug fixed. + version 0.8.k CRASHed for this. + * ospf6_lsa.c: bug of logging fixed. + version: 0.8.l + +2001-01-04 Yasuhiro Ohara + + * ospf6_neighbor.c: fix typo when trying to delete + MaxAge AS-External LSA. MaxAge LSA remaining bug is expected + to be fixed. + version: 0.8.k + +2001-01-04 Yasuhiro Ohara + + * ospf6_mesg.c: add I/F Mtu check for sending LS Update. + + * ospf6_dbex.c, ospf6_mesg.c, ospf6_neighbor.c, ospf6_neighbor.h, + ospf6_spf.c: Changed type of hisaddr field in ospf6_neighbor + structure, from sockaddr_in6 to in6_addr. No protocol/processing + changed. + +2001-01-04 Yasuhiro Ohara + + * ospf6_mesg.c, ospf6_neighbor.[ch]: Speed up of + Database Exchange. + version: 0.8.j + + Because the LS Request list was checked only when attempt + to send (retransmit) LS Request packet, Loading state lasted + long (for RxmtInterval) unexpectedly. This was fixed; LS Request + packet will be send as soon as one received a LS Update packet. + +2001-01-01 Kunihiro Ishiguro + + * ospf6d.h (OSPF6_VTYSH_PATH): Change "/tmp/ospf6d" to + /tmp/.ospf6d". + +2000-12-29 Yasuhiro Ohara + + * ospf6_dump.[ch]: simplified. + +2000-12-19 Yasuhiro Ohara + + * ospf6_route.c: Fix bug of using unavailable route. + version: 0.8.d + +2000-11-30 Yasuhiro Ohara + + * ospf6_spf.c: calculate statistics. version: 0.8.d + +2000-11-26 Yasuhiro Ohara + + * ospf6_mesg.c, ospf6_nsm.c: LSDB sync bug fixed. + version: 0.8.c + +2000-11-26 Yasuhiro Ohara + + * ospf6_dbex.c: Start debugging and cleaning. + + * ospf6_area.c, ospf6_dbex.c, ospf6_interface.c, ospf6_lsa.c, + ospf6_proto.c, ospf6_top.c: add some function to clarify codes. + +2000-11-26 Yasuhiro Ohara + + * ospf6_spf.c: Delete old garbage (which was enclosed by #if 0) + + * ospf6_redistribute.c: "redistribute ospf6" was generated in + "router ospf6" in config file. It is a bug, and fixed. + wrong warning message was deleted. + + * ospf6_main.c: If daemon mode, ospf6d was silent even if + the config file was wrong. It is a bug, and fixed. + + * ospf6_route.c, ospf6_zebra.c: Zebra syncronization method + has been changed. delete garbages. allow nexthop of :: in case + of connected route. + + * ospf6_dbex.c: Delete annoying log messages. + + * ospf6_lsa.c: Changed string for LSA log. + +2000-11-21 Yasuhiro Ohara + + * ospf6_spf.c: some careless bug fixed. + + * ospf6_route.c: changed not to send garbage route + whose nexthop is not linklocal address. + +2000-11-09 Yasuhiro Ohara + + * ospf6_rtable.c: renamed to ospf6_route.c + whole functionality has been rewritten as new code. + new functions not yet installs routes; the old + functions still remains. cleaning log messages. + + * ospf6_spf.c: whole functionality has been rewritten + as new code. new command "show ipv6 ospf6 spf node", + "show ipv6 ospf6 spf tree", "show ipv6 ospf6 spf table" + has been added. Memory leak was fixed. cleaning log messages. + + * ospf6d version: 0.7.c + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 is released. + +2000-09-10 Kunihiro Ishiguro + + * ospf6_lsdb.c (ospf6_lsdb_remove_maxage_lsa): Fix compile + warnings. + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 is released. + +2000-08-06 Kunihiro Ishiguro + + * ospf6_rtable.h (struct ospf6_nexthop): Change ifindex type from + unsigned long to unsigned int. + +2000-04-28 Kunihiro Ishiguro + + * ospf6d.h: Include some headers for avoid warning. + + * ospf6_routemap.h: Add newfile. + +1999-11-21 Kunihiro Ishiguro + + * ospf6_network.c: Respect IPV6_JOIN_GROUP and IPV6_LEAVE_GROUP + rather than RFC2133. + +1999-10-21 Jun-ichiro itojun Hagino + + * ospf6_network.c (ospf6_ipv6_decode_ipv4): Fix bug of conversion + from IPv4 Mapped Address to IPv4 address. + +1999-08-08 Kunihiro Ishiguro + + * ospf6_lsa.c (construct_link_lsa): Enclose KAME specific part by + #ifdef/#endif. + +1999-07-29 Yasuhiro Ohara + + * ospf6_mesg.c: add new message process function. + +1999-07-25 Kunihiro Ishiguro + + * ospf6_main.c (sighup): Call of log_rotate() removed. + +1999-07-24 Yasuhiro Ohara + + ospf6_dbex.{c,h}: variable "acknowledge" has been deleted. + +1999-07-22 Yasuhiro Ohara + + * *.{c,h}: lsa data structure has been drastically + changed. + +1999-07-16 Yasuhiro Ohara + + * *.{c,h}: bug of updating LSA's which is self + originated has been fixed. + +1999-07-14 Yasuhiro Ohara + + * *.{c,h} : log clean up. + +1999-07-05 Kunihiro Ishiguro + + * ospf6d.c (ospf6_init): Change to use install_default. + +1999-07-03 Yasuhiro Ohara + + * ospf6_rtable.c (nexthop_*): added some function that handles + new nexthop structure. + +1999-07-01 Rick Payne + + * ospf6_zebra.c (ospf6_zebra_init): Install standard commands to + ZEBRA_NODE. + +1999-06-09 Yasuhiro Ohara + + * ospf6_rtable.h: added for new routing table of ospf6d + +1999-05-14 Stephen R. van den Berg + + * ospf6_main.c (signal_init): SIGTERM call sigint. + (sigint): Loggging more better message. + +1999-05-13 Yasuhiro Ohara + + *ospf6_spf.c (get_prefix_lsa_of_vertex): bug fix about network vertex. + +1999-05-08 Kunihiro Ishiguro + + * ospf6_network.c (send_linkstate_ack): Check HAVE_SIN6_SCOPE_ID + is defined. + * ospf6_mesg.c (make_hello): Likewise. + * ospf6_lsa.c (lsa_flood): Likewise. + +1999-05-07 Yasuhiro Ohara + + * ospf6_spf.c, etc: Many bug fix. + intra-area-prefix-LSA treatment changed. + network byte order of neighbor ifid changed. + +1999-05-07 Kunihiro Ishiguro + + * ospf6_zebra.h (struct zebra): Add hitory entry to structure. + +1999-05-05 Kunihiro Ishiguro + + * ospf6_main.c (main): Add KAME check for binding vty socket. + (main): Delete old interface get routine garbage. + + * ospf6d.c: Change all `show ip6' statement to `show ipv6'. + (show_ipv6_ospf6_requestlist): Add description. + +1999-05-04 Yasuhiro Ohara + + * ospf6_lsa.c, etc: Many bug fix, now two routers + on the same segment can become FULL neighbor state + each other. + +1999-05-03 Kunihiro Ishiguro + + * Makefile.am: Add file dependency. + (depend): Add target. + +1999-05-02 Yasuhiro Ohara + + * Clean up and fix have been almost done. This code + now testing stage of Intra area routing. + + * Configuration Vty become more similar to Cisco. + +1999-04-22 Kunihiro Ishiguro + + * Trim training newline from zlog format arguemnt. + + * ospf6_dump.c (ospf6_err): Commented out ospf6_err and + ospf6_warn. Same kind of function should be implemented as + zlog_err or zlog_warn or someting. + + * ospf6d.c: Change OSPF_NODE to OSPF6_NODE. + Change OSPF_DEFAULT_CONFIG to OSPF6_DEFAULT_CONFIG. + + +1999-04-21 Kunihiro Ishiguro + + * ospf6_mesg.c (make_hello): Add check of SIN6_LEN + +1999-04-16 Kunihiro Ishiguro + + * ospf6_neighbor.c: Change list_clear_all to list_delete_all_node. + Remove list_delete_all fuction and use lib/linklist.c's one. + +1999-04-14 Kunihiro Ishiguro + + * mcast_join(),mcast_leave()'s argument socket length is removed. + +1999-04-08 + + * ospf6_zebra.h (ospf_zebra_read): Fix typo. + + * ospf6_interface.h: Tempolary add struct rt_addrinfo. + +1999-03-05 Kunihiro Ishiguro + + * Merge from ospfd-zebra-990303 codes. + +1999-02-23 Kunihiro Ishiguro + + * Makefile.in: add new file. + + * Makefile.am: @INCLUDES@ is added for OS/library specific IPv6 + directory search. + + * Import files from Yasuhiro Ohara 's ospfd. + Impterted files are: + Makefile.am, ospf_area.h, ospf_dump.c, ospf_interface.c, + ospf_interface.h, ospf_lsa.c, ospf_lsa.h, ospf_main.c, + ospf_mesg.c, ospf_mesg.h, ospf_neighbor.c, + ospf_neighbor.h,ospf_network.c, ospf_network.h, ospf_proto.h, + ospf_spf.c, ospf_spf.h, ospf_types.h, ospfd.c, ospfd.h diff --git a/ospf6d/Makefile.am b/ospf6d/Makefile.am new file mode 100644 index 00000000..e1b78cbc --- /dev/null +++ b/ospf6d/Makefile.am @@ -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 index 00000000..fed57d95 --- /dev/null +++ b/ospf6d/Makefile.in @@ -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 index 00000000..b3b4d16d --- /dev/null +++ b/ospf6d/README @@ -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 + by E-mail. Patches will be appriciated. + +ospf6d's vty port was default to 2606/tcp. +Use commands below. + +VIEW NODE: + show ipv6 ospf6 + To see Router-ID, uptime of ospf6d, some statistics. + + show ipv6 ospf6 database ... + This command shows LSA database. You can specify + LS-type/LS-ID/Advertising-Router of LSAs. '*' is recognized. + + show ipv6 ospf6 interface ... + To see the status of the OSPF interface, and the configuration + like interface costs. + + show ipv6 ospf6 neighbor ... + Shows state of neighbors and choosed (Backup) DR on the I/F. + + show ipv6 ospf6 route (X::X) + This command shows internal routing table of the ospf6d. + Routes not calculated by OSPFv3 (like connected routes) + are not shown. If Address is specified (X::X), shows the route + that the address matches. + + show ipv6 ospf6 route redistribute (X::X) + Shows the routes advertised as AS-External routes by the router + itself. If Address is specified (X::X), shows the route + that the address matches. + +CONFIG NODE: + interface NAME + To enter INTERFACE NODE + + router ospf6 ... + To enter OSPF6 NODE + +INTERFACE NODE: + ipv6 ospf6 cost COST + Sets the interface's output cost. default 1 + + ipv6 ospf6 hello-interval HELLOINTERVAL + Sets the interface's Hello Interval. default 10 + + ipv6 ospf6 dead-interval DEADINTERVAL + Sets the interface's Router Dead Interval. default 40 + + ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL + Sets the interface's Rxmt Interval. default 5 + + ipv6 ospf6 priority PRIORITY + Sets the interface's Router Priority. default 1 + + ipv6 ospf6 transmit-delay TRANSMITDELAY + Sets the interface's Inf-Trans-Delay. default 1 + +OSPF6 NODE: + router-id A.B.C.D + Sets the router's Router-ID + + interface NAME area AREA + Binds interface to specified Area, and start + sending OSPFv3 packets. + +Sample configuration is in ospf6d.conf.sample. + +-- +Yasuhiro Ohara +Kunihiro Ishiguro + diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c new file mode 100644 index 00000000..864e0c23 --- /dev/null +++ b/ospf6d/ospf6_abr.c @@ -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 index 00000000..510532e8 --- /dev/null +++ b/ospf6d/ospf6_abr.h @@ -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 index 00000000..51af5080 --- /dev/null +++ b/ospf6d/ospf6_area.c @@ -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; +} + + + +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 index 00000000..06844646 --- /dev/null +++ b/ospf6d/ospf6_area.h @@ -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 index 00000000..00a2b66c --- /dev/null +++ b/ospf6d/ospf6_asbr.c @@ -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 + +#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 index 00000000..153ed21e --- /dev/null +++ b/ospf6d/ospf6_asbr.h @@ -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 index 00000000..c1e9e558 --- /dev/null +++ b/ospf6d/ospf6_bintree.c @@ -0,0 +1,436 @@ + +#include +#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 index 00000000..fad8bbdd --- /dev/null +++ b/ospf6d/ospf6_bintree.h @@ -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 index 00000000..4e807a70 --- /dev/null +++ b/ospf6d/ospf6_damp.c @@ -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 +#include + +#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 index 00000000..19bdbc7a --- /dev/null +++ b/ospf6d/ospf6_damp.h @@ -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 index 00000000..b10d9aeb --- /dev/null +++ b/ospf6d/ospf6_dbex.c @@ -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 index 00000000..fbb7dc5e --- /dev/null +++ b/ospf6d/ospf6_dbex.h @@ -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 index 00000000..e950ec8c --- /dev/null +++ b/ospf6d/ospf6_dump.c @@ -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 + +/* 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 index 00000000..18a6e466 --- /dev/null +++ b/ospf6d/ospf6_dump.h @@ -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 index 00000000..fc9e185d --- /dev/null +++ b/ospf6d/ospf6_hook.c @@ -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 + +#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 index 00000000..fa882a53 --- /dev/null +++ b/ospf6d/ospf6_hook.h @@ -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 index 00000000..d394f21b --- /dev/null +++ b/ospf6d/ospf6_interface.c @@ -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 index 00000000..a96ef25a --- /dev/null +++ b/ospf6d/ospf6_interface.h @@ -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 + + +/* 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 index 00000000..b9c9ebd0 --- /dev/null +++ b/ospf6d/ospf6_intra.c @@ -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); + } +} + + +/*****************************************/ +/* 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 index 00000000..4fb68e95 --- /dev/null +++ b/ospf6d/ospf6_intra.h @@ -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 index 00000000..d13be127 --- /dev/null +++ b/ospf6d/ospf6_ism.c @@ -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; +} + + +/* 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; +} + + +/* 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 index 00000000..12470d98 --- /dev/null +++ b/ospf6d/ospf6_ism.h @@ -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 + + + +/* 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 index 00000000..8c179359 --- /dev/null +++ b/ospf6d/ospf6_linklist.c @@ -0,0 +1,193 @@ + +#include + +#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 index 00000000..6d978999 --- /dev/null +++ b/ospf6d/ospf6_linklist.h @@ -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 index 00000000..b14979ff --- /dev/null +++ b/ospf6d/ospf6_lsa.c @@ -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 + +/* 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); +} + + +/* 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; +} + + + +/* 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; +} + + +/*******************/ +/* 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 index 00000000..02ad7c6f --- /dev/null +++ b/ospf6d/ospf6_lsa.h @@ -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 index 00000000..ad53eb4f --- /dev/null +++ b/ospf6d/ospf6_lsdb.c @@ -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 + +#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); + } +} + + + +/* 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 index 00000000..50eedc85 --- /dev/null +++ b/ospf6d/ospf6_lsdb.h @@ -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 index 00000000..5ab517f3 --- /dev/null +++ b/ospf6d/ospf6_main.c @@ -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 +#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); +} + + +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); +} + +/* 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 index 00000000..f6577a99 --- /dev/null +++ b/ospf6d/ospf6_message.c @@ -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)); +} + + +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; +} + + +/* 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 index 00000000..105cb4f0 --- /dev/null +++ b/ospf6d/ospf6_message.h @@ -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 index 00000000..72735d5d --- /dev/null +++ b/ospf6d/ospf6_neighbor.c @@ -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 + +#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; +} + + + +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; +} + + +/* 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 index 00000000..c3821c67 --- /dev/null +++ b/ospf6d/ospf6_neighbor.h @@ -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[]; + + +/* 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 index 00000000..041d829b --- /dev/null +++ b/ospf6d/ospf6_network.c @@ -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 +#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; + } +} + + +/* 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 index 00000000..934cce59 --- /dev/null +++ b/ospf6d/ospf6_network.h @@ -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 + + + +/* 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 index 00000000..aa08d40b --- /dev/null +++ b/ospf6d/ospf6_nsm.c @@ -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 index 00000000..d70f1e88 --- /dev/null +++ b/ospf6d/ospf6_nsm.h @@ -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 + + + +/* 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 index 00000000..1542200c --- /dev/null +++ b/ospf6d/ospf6_prefix.c @@ -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 + +#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 index 00000000..65a8cbc8 --- /dev/null +++ b/ospf6d/ospf6_prefix.h @@ -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))) + + + +/* 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 index 00000000..71e575f1 --- /dev/null +++ b/ospf6d/ospf6_proto.c @@ -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 + +#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 index 00000000..9a95444a --- /dev/null +++ b/ospf6d/ospf6_proto.h @@ -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 index 00000000..c35efa6e --- /dev/null +++ b/ospf6d/ospf6_route.c @@ -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]) + + + +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); + } + } + } +} + + +/* 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 index 00000000..71b2562b --- /dev/null +++ b/ospf6d/ospf6_route.h @@ -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; +}; + + + +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 index 00000000..14df7940 --- /dev/null +++ b/ospf6d/ospf6_routemap.c @@ -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 + +#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 index 00000000..c68e0ffc --- /dev/null +++ b/ospf6d/ospf6_routemap.h @@ -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 index 00000000..fd7fc779 --- /dev/null +++ b/ospf6d/ospf6_spf.c @@ -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); + } +} + + +#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); +} + + +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 index 00000000..de50e94a --- /dev/null +++ b/ospf6d/ospf6_spf.h @@ -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 index 00000000..a8a058f2 --- /dev/null +++ b/ospf6d/ospf6_top.c @@ -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 + +#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 index 00000000..4c687563 --- /dev/null +++ b/ospf6d/ospf6_top.h @@ -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 index 00000000..574e2f35 --- /dev/null +++ b/ospf6d/ospf6_types.h @@ -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 index 00000000..7b8a8dcf --- /dev/null +++ b/ospf6d/ospf6_zebra.c @@ -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; +} + + + +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; +} + + +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 index 00000000..d86b2db7 --- /dev/null +++ b/ospf6d/ospf6_zebra.h @@ -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 index 00000000..dbe7a88f --- /dev/null +++ b/ospf6d/ospf6d.c @@ -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; + + +#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)++; +} + +/* 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 index 00000000..71972f59 --- /dev/null +++ b/ospf6d/ospf6d.conf.sample @@ -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 index 00000000..e0d310a9 --- /dev/null +++ b/ospf6d/ospf6d.h @@ -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 +#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" + + +/* 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 index 00000000..d7e3a7e2 --- /dev/null +++ b/ospfd/.cvsignore @@ -0,0 +1,7 @@ +Makefile +*.o +ospfd +ospfd.conf +tags +TAGS +.deps diff --git a/ospfd/ChangeLog b/ospfd/ChangeLog new file mode 100644 index 00000000..31c5b0f7 --- /dev/null +++ b/ospfd/ChangeLog @@ -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 + + * ospf_vty.c (show_ip_ospf_database): Fix CLI parse. + +2002-10-23 Juris Kalnins + + * ospf_interface.c (ospf_if_stream_unset): When write queue + becomes empty stop write timer. + +2002-10-10 Greg Troxel + + * ospf_packet.c (ospf_check_md5_digest): Change >= to > to make it + conform to RFC. + +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2002-06-19 Kunihiro Ishiguro + + * ospf_spf.c (ospf_nexthop_calculation): Add NULL set to oi and + check of l2. Reported by: Daniel Drown + (ospf_lsa_has_link): LSA Length calculation fix. Reported by: + Paul Jakma . + + * ospfd.c (ospf_if_update): Fix nextnode reference bug. Reported + by: juris@mt.lv. + +2002-01-21 Kunihiro Ishiguro + + * ospfd.c: Merge [zebra 11445] Masahiko ENDO's Opaque-LSA support. + +2001-08-27 Kunihiro Ishiguro + + * ospf_interface.c (ospf_add_to_if): Use /32 address to register + OSPF interface information. + (ospf_delete_from_if): Likewise. + + * ospf_zebra.c (ospf_interface_address_delete): Likewise. + +2001-08-23 Kunihiro Ishiguro + + * ospf_zebra.c (ospf_redistribute_unset): When redistribute type + is OSPF, do not unset redistribute flag. + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-08-12 Kunihiro Ishiguro + + * ospfd.c (ospf_config_write): auto-cost reference-bandwidth + configuration display. + +2001-07-24 David Watson + + * ospf_spf.c (ospf_spf_next): Modify ospf_vertex_add_parent to + check for an existing link before connecting the parent and child. + ospf_nexthop_calculation is also modified to check for duplicate + entries when copying from the parent. Finally, ospf_spf_next + removes duplicates when it merges two equal cost candidates. + +2001-07-23 itojun@iijlab.net + + * ospfd.c (show_ip_ospf_neighbor): Check ospf_top before use it + [zebra 8549]. + +2001-07-23 Kunihiro Ishiguro + + * ospf_packet.c (ospf_write): Remove defined(__OpenBSD__) to make + it work on OpenBSD. + +2001-06-26 Kunihiro Ishiguro + + * ospf_zebra.c (config_write_ospf_default_metric): Display + default-metric configuration. + +2001-06-18 Kunihiro Ishiguro + + * ospf_ia.h (OSPF_EXAMINE_SUMMARIES_ALL): Remove old macros. + +2001-05-28 Kunihiro Ishiguro + + * ospf_snmp.c (ospfIfEntry): Fix interface lookup bug to avoid + crush. + (ospfIfMetricEntry): Likewise. + +2001-03-18 Kunihiro Ishiguro + + * ospf_packet.c (ospf_read): Fix typo. Reported by: "Jen B + Lin'Kova" . + +2001-03-15 Gleb Natapov + + * ospf_interface.c (ip_ospf_network): Set interface parameter. + (interface_config_write): Add check for OSPF_IFTYPE_LOOPBACK. + + * ospf_zebra.c (ospf_interface_add): Set interface parameter. + +2001-02-21 Kunihiro Ishiguro + + * ospf_packet.c (ospf_recv_packet): Solaris also need to add + (iph.ip_hl << 2) to iph.ip_len. + +2001-02-09 Kunihiro Ishiguro + + * ospfd.h (OSPF_LS_REFRESH_TIME): Fix OSPF_LS_REFRESH_TIME value. + Suggested by: David Watson . + + * ospf_zebra.c (zebra_init): Remove zebra node. + + * ospfd.c (ospf_area_range_set): Function name is changed from + ospf_ara_range_cmd. + (ospf_area_range_unset): New function which separated from DEFUN. + New commands are added: + "no area A.B.C.D range A.B.C.D/M advertise" + "no area <0-4294967295> range A.B.C.D/M advertise" + "no area A.B.C.D range A.B.C.D/M not-advertise" + "no area <0-4294967295> range A.B.C.D/M not-advertise" + + * ospf_lsa.c (ospf_lsa_more_recent): Fix previous change. + +2001-02-08 Matthew Grant + + * ospf_network.c (ospf_if_add_allspfrouters): Use + setsockopt_multicast_ipv4. + (ospf_if_drop_allspfrouters): Likewise. + + * ospf_lsa.c (ospf_router_lsa_install): Add rt_recalc flag. + (ospf_network_lsa_install): Likewise. + (ospf_summary_lsa_install): Likewise. + (ospf_summary_asbr_lsa_install): Likewise. + (ospf_external_lsa_install): Likewise. + (ospf_lsa_install): Call ospf_lsa_different to check this LSA is + new one or not. + +2001-02-08 Kunihiro Ishiguro + + * ospf_zebra.c (ospf_interface_delete): Do not free interface + structure when ospfd receive interface delete message to support + pseudo interface. + +2001-02-01 Dick Glasspool + + * ospfd.c (area_range_notadvertise): Change area range "suppress" + command to "not-advertise". + + * ospfd.h (OSPF_LS_REFRESH_TIME): Change OSPF_LS_REFRESH_TIME from + 1800 to 60. + + * ospf_abr.c (ospf_abr_update_aggregate): When update_aggregate is + updating the area-range, the lowest cost is now saved. + + * ospf_lsa.c (ospf_lsa_more_recent): Routing to compare sequence + numbers rather than creating overflow during calculation. + +2001-02-01 Kunihiro Ishiguro + + * zebra-0.91 is released. + +2001-01-31 Kunihiro Ishiguro + + * ospf_packet.c (ospf_db_desc_proc): Do not continue process when + NSM_SeqNumberMismatch is scheduled. + (ospf_ls_req): Free ls_upd when return from this function. + (ospf_ls_upd_timer): When update list is empty do not call + ospf_ls_upd_send(). Suggested by: endo@suri.co.jp (Masahiko + Endo). + +2001-01-26 Kunihiro Ishiguro + + * ospf_lsa.c (ospf_maxage_flood): Flood LSA when it reaches + MaxAge. RFC2328 Section 14. + (ospf_maxage_lsa_remover): Call above function during removing + MaxAge LSA. + +2001-01-26 Dick Glasspool + + * ospf_flood.c (ospf_flood_through_as): Function is updated for + NSSA Translations now done at ospf_abr.c with no change in P-bit. + + * ospf_lsa.c (ospf_get_nssa_ip): Get 1st IP connection for Forward + Addr. + (ospf_install_flood_nssa): Leave Type-7 LSA at Lock Count = 2. + + * ospf_ase.c (ospf_ase_calculate_route): Add debug codes. + + * ospf_abr.c (ospf_abr_translate_nssa): Recalculate LSA checksum. + + * ospf_packet.h (OSPF_SEND_PACKET_LOOP): Added for test packet. + + * ospf_dump.c (ospf_lsa_type_msg): Add OSPF_GROUP_MEMBER_LSA and + OSPF_AS_NSSA_LSA. + + * ospfd.c (data_injection): Function to inject LSA. This is + debugging command. + +2001-01-11 Kunihiro Ishiguro + + * ospf_route.c (ospf_route_match_same): Remove function. + (ospf_route_match_same_new): Renamed to ospf_route_match_same. + + * ospf_zebra.c (ospf_interface_address_delete): Add check for + oi->address. Suggested by Matthew Grant + . + (ospf_zebra_add): Remove function. + (ospf_zebra_add_multipath): Rename to ospf_zebra_add. + + * ospf_interface.c: Remove HAVE_IF_PSEUDO part. + + * ospf_zebra.c: Likewise. + +2001-01-10 Kunihiro Ishiguro + + * ospf_ase.c: Remove OLD_RIB part. + + * ospf_route.c: Likewise. + + * zebra-0.90 is released. + + * ospf_packet.c (ospf_recv_packet): Use ip_len adjestment code to + NetBSD. + +2001-01-09 Kunihiro Ishiguro + + * ospf_route.c (ospf_route_delete): Use + ospf_zebra_delete_multipath. + +2001-01-09 Matthew Grant + + * ospf_interface.c (ospf_if_cleanup): Function name is renamed + from ospf_if_free(). Rewrite whole procudure to support primary + address deletion. + + * ospf_zebra.c (ospf_interface_address_delete): Add primary + address deletion process. + +2001-01-09 Kunihiro Ishiguro + + * ospf_packet.c (ospf_recv_packet): OpenBSD has same ip_len + treatment like FreeBSD. + +2001-01-09 endo@suri.co.jp (Masahiko Endo) + + * ospf_packet.c (ospf_recv_packet): FreeBSD kernel network code + strips IP header size from receiving IP Packet. So we adjust + ip_len to whole IP packet size by adding IP header size. + +2001-01-08 endo@suri.co.jp (Masahiko Endo) + + * ospf_network.c (ospf_serv_sock): When socket() is failed return + immediately. + (ospf_serv_sock): Close socket when it is not used. + + * ospf_packet.c (ospf_write): Set sin_len when HAVE_SIN_LEN is + defined. + (ospf_write): When bind is fined, close sock. + +2001-01-07 Gleb Natapov + + * ospf_zebra.c (ospf_interface_state_up): Fixes coredump that + appears when you try to configure bandwidth on the ppp interface + that is not yet configured in ospfd. + +2001-01-07 Michael Rozhavsky + + * ospf_route.c (show_ip_ospf_route_external): "show ip ospf route" + will print nexthops for AS-external routes. + + * ospf_ase.c (ospf_ase_route_match_same): New function to compare + ASE route under multipath environment. + (ospf_ase_compare_tables): Likewise. + +2001-01-01 Kunihiro Ishiguro + + * ospfd.h (OSPF_VTYSH_PATH): Change "/tmp/ospfd" to "/tmp/.ospfd". + +2000-12-28 Kunihiro Ishiguro + + * ospf_route.c (ospf_route_install): Install multipath information + to zebra daemon. + + * ospf_zebra.c (ospf_zebra_add_multipath): Function for passing + multipath information to zebra daemon. + +2000-12-25 Dick Glasspool + + * ospf_packet.c (ospf_write): Call ospf_packet_delete when sendto + fail. + (DISCARD_LSA): Add argument N for logging point of DISCARD_LSA is + called. + + * ospf_lsa.c (ospf_external_lsa_refresh): NSSA install_flood will + leave Type-7 LSA at Lock Count = 2. + + * ospf_flood.c (ospf_flood_through): Flood_though_as updated for + NSSA no P-bit off during Area flooding, but P-bit is turned off + for mulitple NSSA AS flooding. + + * ospf_ase.c (ospf_ase_calculate_timer): Added calculations for + Type-7 LSDB. + + * ospf_abr.c (ospf_abr_translate_nssa): Removed one unlock call. + (ospf_abr_announce_nssa_defaults): Corrected Debug from EVENT to + NSSA. + +2000-12-25 Michael Rozhavsky + + * ospf_zebra.c (ospf_zebra_read_ipv4): Checking the age of the + found LSA and if the LSA is MAXAGE we should call refresh instead + of originate. + +2000-12-18 Dick Glasspool + + * ospf_abr.c: Removed redundant "...flood" in + announce_network_to_area(). Repaired nssa Unlock by using + discard. + + * ospf_packet.c: Removed old NSSA translate during mk_ls_update. + + * ospfd.c: Free up all data bases including NSSA. + + * ospf_lsa.c: Now allow removal of XLATE LSA's Check in + discard_callback. Added routine to get ip addr from within the + ifp. + + * ospf_flood.c: Now set Forward Address for outgoing Type-7. + + * ospf_lsa.h: Added prototype for the below. struct in_addr + ospf_get_ip_from_ifp (struct interface *ifp). + +2000-12-14 Gleb Natapov + + * ospf_packet.c (ospf_recv_packet): New OSPF pakcet read method. + Now maximum packet length may be 65535 bytes (maximum IP packet + length). + + * ospf_interface.c (ospf_if_stream_set): Don't make input buffer. + + * ospfd.c (config_write_network_area): Remove unnecessary area + lookup code. + +2000-12-13 Kunihiro Ishiguro + + * ospf_packet.c (ospf_read): Accept packet bigger than MTU value. + +2000-12-13 Gleb Natapov + + * ospfd.c (config_write_network_area): Fix bug in + config_write_network_area function. + +2000-12-12 Gleb Natapov + + * ospf_abr.c (ospf_abr_announce_network_to_area): Make Summary + LSA's origination and refreshment as same as other type of LSA. + + * ospf_lsa.c (ospf_summary_lsa_refresh): Return struct ospf_lsa *. + + * ospf_lsa.c (ospf_summary_asbr_lsa_refresh): Likewise. + +2000-12-08 Dick Glasspool + + The bulk of NSSA changes are contained herein; This version will + require manual setting of "always" for NSSA Translator, and will + not perform aggregation yet. + + * ospf_dump.c: "debug ospf nssa" is added. + + * ospf_dump.h: Likewise. + + * ospf_packet.c (ospf_hello): Display router ID on Bad NSSA Hello. + + * ospfd.c: Discard_LSA to stay away from LOCAL_XLT Process NSSA + 'never, candidate, always'. Change "suppress" to "not-advertise". + + * ospfd.h: Add TranslatorRole to struct ospf_area. Add anyNSSA to + struct ospf. + + * ospf_ase.c (ospf_ase_calculate_route): External to stay away + from LOCAL_XLT + + * ospf_nsm.c (ospf_db_summary_add): External to stay away from + LOCAL_XLT + + * ospf_abr.c: Major logic added for abr_nssa_task(). If ABR, and + NSSA translator, then do it. Approve the global list, and flush + any unapproved. + + * ospf_lsa.h: New LSA flag OSPF_LSA_LOCAL_XLT to indicate that the + Type-5 resulted from a Local Type-7 translation; not used for + flooding, but used for flushing. + + * ospf_flood.c: New NSSA flooding. + +2000-12-08 Michael Rozhavsky + + * ospfd.c (ospf_find_vl_data): New function for looking up virtual + link data. + (ospf_vl_set_security): Virtual link configuration with + authentication. + (ospf_vl_set_timers): Set timers for virtual link. + + * New commands are added. + "area A.B.C.D virtual-link A.B.C.D" + "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535>" + "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535> authentication-key AUTH_KEY" + "area A.B.C.D virtual-link A.B.C.D authentication-key AUTH_KEY" + "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535> message-digest-key <1-255> md5 KEY" + "area A.B.C.D virtual-link A.B.C.D message-digest-key <1-255> md5 KEY" + + * ospf_packet.c (ospf_check_md5_digest): Add neighbor's + cryptographic sequence number treatment. + (ospf_check_auth): OSPF input buffer is added to argument. + (ospf_read): Save neighbor's cryptographic sequence number. + + * ospf_nsm.c (nsm_change_status): Clear cryptographic sequence + number when neighbor status is changed to NSM down. + + * ospf_neighbor.c (ospf_nbr_new): Set zero to crypt_seqnum. + + * ospf_neighbor.h (struct ospf_neighbor): Add cryptographic + sequence number to neighbor structure. + +2000-11-29 Kunihiro Ishiguro + + * ospf_snmp.c (ospfIfLookup): OSPF MIB updates. + (ospfExtLsdbEntry): Add OspfExtLsdbTable treatment. + +2000-11-28 Michael Rozhavsky + + * ospfd.c (ospf_interface_down): Clear a ls_upd_queue queue of the + interface. + (ospf_ls_upd_queue_empty): New function to empty ls update queue + of the OSPF interface. + (no_router_ospf): 'no router ospf' unregister redistribution + requests from zebra. + +2000-11-28 Kunihiro Ishiguro + + * ospf_ism.c (ism_change_status): Increment status change number. + + * ospf_interface.h (struct ospf_interface): Add new member for + status change statistics. + + * Makefile.am: Update dependencies. + + * ospf_zebra.c (ospf_interface_add): OSPF SNMP interface update. + (ospf_interface_delete): OSPF SNMP interface delete. + + * ospf_snmp.h: New file is added. + +2000-11-23 Dick Glasspool + + * ospfd.h: Add new ospf_area structure member for + NSSATranslatorRole and NSSATranslator state. + + * ospfd.c: Provided for eventual commands to specify NSSA + elections for "translator- ALWAYS/NEVER/CANDIDATE". Provided for + decimal integer version of area-suppress. + + * ospf_flood.c: Flood Type-7's only into NSSA (not AS). + + * ospf_lsa.c: Undo some previous changes for NSSA. If NSSA + translator, advertise Nt bit. + + * ospf_route.c: 1st version of "sh ip os border-routers". + +2000-11-23 Michael Rozhavsky + + * ospfd.c (area_vlink): Virtual link can not configured in stub + area. + +2000-11-23 Gleb Natapov + + * ospf_packet.c (ospf_db_desc): In states Loading and Full the + slave must resend its last Database Description packet in response + to duplicate Database Description packets received from the + master. For this reason the slave must wait RouterDeadInterval + seconds before freeing the last Database Description packet. + Reception of a Database Description packet from the master after + this interval will generate a SeqNumberMismatch neighbor + event. RFC2328 Section 10.8 + (ospf_make_db_desc): DD Master flag treatment. + + * ospf_nsm.c (nsm_twoway_received): Move DD related procedure to + nsm_change_status(). + (nsm_bad_ls_req): Likewise. + (nsm_adj_ok): Likewise. + (nsm_seq_number_mismatch): Likewise. + (nsm_oneway_received): Likewise. + + * ospf_neighbor.h (struct ospf_neighbor): New structure member + last_send_ts for timestemp when last Database Description packet + was sent. + + * ospf_nsm.c (ospf_db_desc_timer): Make it sure nbr->last_send is + there. Call ospf_db_desc_resend() in any case. + +2000-11-16 Michael Rozhavsky + + * ospf_lsa.c (lsa_link_broadcast_set): When there is no DR on + network (suppose you have only one router with interface priority + 0). It's router LSA does not contain the link information about + this network. + + * ospf_nsm.c (nsm_timer_set): When you change a priority of + interface from/to 0 ISM_NeighborChange event should be scheduled + in order to elect new DR/BDR on the network. + + * ospf_interface.c (ip_ospf_priority): Likewise. + + * ospf_flood.c (ospf_ls_retransmit_add): When we add some LSA into + retransmit list we need to check whether the present old LSA in + retransmit list is not more recent than the new + one. + +2000-11-09 Dick Glasspool + + * ospf_packet.c: Allows for NSSA Type-7 LSA's throughout the NSSA + area. Any that exit the NSSA area are translated to type-5 LSA's. + The instantiated image is restored after translation. + (ospf_ls_upd_send_list): Renamed to ospf_ls_upd_queu_send(). + (ospf_ls_upd_send): Old function which enclosed by #ifdef 0 is + removed. + (ospf_ls_ack_send): Likewise. + + * ospf_flood.c: NSSA-LSA's without P-bit will be restricted to + local area. Otherwise they are allowed out the area to be + translated by ospf_packet.c. + + * ospf_lsa.c: Undo some previous changes for NSSA. + + * ospf_lsdb.h: New access for type 7. + +2000-11-07 Kunihiro Ishiguro + + * ospf_route.c (ospf_path_exist): New function to check nexthop + and interface are in current OSPF path or not. + (ospf_route_copy_nexthops_from_vertex): Add nexthop to OSPF path + when it is not there. Reported by Michael Rozhavsky + + +2000-11-06 Kunihiro Ishiguro + + * ospf_dump.c (config_write_debug): Add seventh string "detail" is + added for flag is OSPF_DEBUG_SEND | OSPF_DEBUG_RECV | + OSPF_DEBUG_DETAIL. + +2000-11-06 Michael Rozhavsky + + * ospf_lsa.c (router_lsa_flags): ASBR can't exit in stub area. + +2000-11-06 Kunihiro Ishiguro + + * ospf_lsa.c (ospf_router_lsa_originate): Reduce unconditional + logging. + +2000-11-06 Dick Glasspool + + * ospfd.h: Add ait_ntoa function prototype. + + * ospfd.c (ait_ntoa): New function for displaying area ID and + Stub/NSSA status. + (show_ip_ospf_interface_sub): Use ait_ntoa. + (show_ip_ospf_nbr_static_detail_sub): Likewise. + (show_ip_ospf_neighbor_detail_sub): Likewise. + + * ospf_route.c (ospf_intra_route_add): Set external routing type + to ospf route. + (ospf_intra_add_router): Likewise. + (ospf_intra_add_transit): Likewise. + (ospf_intra_add_stub): Likewise. + (ospf_add_discard_route): Likewise. + (show_ip_ospf_route_network): Use ait_ntoa. + (show_ip_ospf_route_network): Likewise. + (show_ip_ospf_route_router): Likewise. + + * ospf_lsa.c (show_lsa_detail): Use ait_ntoa. + (show_lsa_detail_adv_router): Likewise. + (show_ip_ospf_database_summary): Likewise. + + * ospf_route.h (struct route_standard): Add new member + external_routing. + + * ospf_ia.c (process_summary_lsa): Set external routing tyep to ospf + route. + (ospf_update_network_route): Likewise. + (ospf_update_router_route): Likewise. + +2000-11-04 Kunihiro Ishiguro + + * ospf_flood.c (ospf_process_self_originated_lsa): Enclose + OSPF_AS_NSSA_LSA treatment with #ifdef HAVE_NSSA. + +2000-11-03 Kunihiro Ishiguro + + * Unconditional logging is enclosed with if (IS_DEBUG_OSPF_EVENT). + Please specify "debug ospf event" for enable logging. + + * ospf_ism.c: Do not extern debug flag varible. It is done by + ospf_debug.h + * ospf_asbr.c: Likewise. + * ospf_lsa.c: Likewise. + * ospf_nsm.c: Likewise. + * ospf_zebra.c: Likewise. + + * ospf_dump.c (debug_ospf_event): New command "debug ospf event" + is added. + + * ospfd.c (router_ospf): Change logging from vty_out() to + zlog_info(). + (ospf_area_stub_cmd): Likewise. + + * ospf_dump.h: Extern term_debug flags. + (OSPF_DEBUG_EVENT): Add new flag. + (IS_DEBUG_OSPF_EVENT): Add new macro. + +2000-11-03 Dick Glasspool + + * ospf_flood.c (ospf_process_self_originated_lsa): + OSPF_AS_NSSA_LSA is treated as same as OSPF_AS_EXTERNAL_LSA. + (ospf_flood): Type-5's have no change. Type-7's can be received, + and will Flood the AS as Type-5's They will also flood the local + NSSA Area as Type-7's. The LSDB will be updated as Type-5's, and + during re-fresh will be converted back to Type-7's (if within an + NSSA). + (ospf_flood_through): Incoming Type-7's were allowed here if our + neighbor was an NSSA. So Flood our area with the Type-7 and also + if we are an ABR, flood thru AS as Type-5. + + * ospf_lsa.c (ospf_external_lsa_refresh): Flood NSSA both NSSA + area and other area. + + * ospf_packet.c (ospf_db_desc_proc): When AS External LSA is + exists in DD packet, make it sure that this area is not stub. + (ospf_ls_upd_list_lsa): When LSA type is NSSA then set lsa's area + to NULL. + (ospf_ls_upd): If the LSA is AS External LSA and the area is stub + then discard the lsa. If the LSA is NSSA LSA and the area is not + NSSA then discard the lsa. + +2000-11-03 Kunihiro Ishiguro + + * ospfd.c (ospf_interface_run): Fix bug of Hello packet's option + is not properly set when interface comes up. + +2000-11-02 Kunihiro Ishiguro + + * ospfd.h (OSPF_OPTION_O): Add new hello header option. + +2000-11-01 Dick Glasspool + + * ospf_lsa.h: Define OSPF_MAX_LSA to 8 when HAVE_NSSA is enabled. + (OSPF_GROUP_MEMBER_LSA): Define OSPF_GROUP_MEMBER_LSA. + + * ospf_lsa.c (show_database_desc): Add "Group Membership LSA" + string. + +2000-10-31 Dick Glasspool + + * ospf_lsa.h (OSPF_AS_NSSA_LSA): Define OSPF_AS_NSSA_LSA. + + * ospf_lsa.c (show_ip_ospf_database): NSSA database display + function is added. ALIASES which have "show ip ospf database + nssa-external" is added. + (show_ip_ospf_border_routers): New command "show ip ospf + border-routers" is added. + +2000-10-30 Dick Glasspool + + * ospfd.c (router_ospf): NSSA Enabled message is added for + testing. + (ospf_area_type_set): Are type set for NSSA area. + (ospf_area_stub_cmd): Special translation of no_summary into NSSA + and summary information. If NSSA is enabled pass the information + to ospf_area_type_set(). + (area_nssa): New commands are added: + "area A.B.C.D nssa" + "area <0-4294967295> nssa" + "area A.B.C.D nssa no-summary" + "area <0-4294967295> nssa no-summary" + (ospf_no_area_stub_cmd): Special translation of no_summary into + NSSA and summary information. If external_routing is + OSPF_AREA_NSSA unset area with ospf_area_type_set (area, + OSPF_AREA_DEFAULT). + (show_ip_ospf_area): Display NSSA status. + (config_write_ospf_area): Show NSSA configuration. + + * ospf_packet.c (ospf_hello): For NSSA support, ensure that NP is + on and E is off. + +2000-10-26 Gleb Natapov + + * ospf_lsa.c (ospf_network_lsa_body_set): The network-LSA lists + those routers that are fully adjacent to the Designated Router; + each fully adjacent router is identified by its OSPF Router ID. + The Designated Router includes itself in this list. RFC2328, + Section 12.4.2. + +2000-10-23 Jochen Friedrich + + * ospf_snmp.c: ospf_oid and ospfd_oid are used in smux_open after + it is registered. So those variables must be static. + +2000-10-18 K N Sridhar + + * ospfd.c: Add area_default_cost_decimal_cmd and + no_area_default_cost_decimal_cmd alias. + +2000-10-05 Gleb Natapov + + * ospfd.c (ospf_network_new): Fix setting area format. + (no_router_ospf): Check area existance when calling + ospf_interface_down(). + + * ospf_flood.c (ospf_external_info_check): Fix bug of refreshing + default route. + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 is released. + +2000-09-29 Kunihiro Ishiguro + + * ospf_snmp.c (ospfHostEntry): OSPF Host MIB is implemented. + + * ospfd.c (ospf_nbr_static_cmp): OSPF neighbor is sorted by it's + address. + +2000-09-28 Michael Rozhavsky + + * ospf_interface.c (ospf_if_free): Fix deleting self neighbor twice. + +2000-09-27 Kunihiro Ishiguro + + * ospf_packet.c (ospf_read): Solaris on x86 has ip_len with host + byte order. + +2000-09-25 Toshiaki Takada + + * ospfd.c (ospf_compatible_rfc1583), (no_ospf_compatible_rfc1583): + Add CISCO compatible command. + +2000-09-25 Kunihiro Ishiguro + + * ospf_abr.c (ospf_area_range_lookup): New function is added for + area range lookup in OSPF-MIB. + (ospf_area_range_lookup_next): Likewise. + +2000-09-22 Kunihiro Ishiguro + + * ospfd.c (no_router_ospf): Delete virtual link before deleting + area structure. + + * ospf_lsa.c (ospf_external_lsa_refresh_type): Check + EXTERNAL_INFO(type). + + * ospfd.c (no_router_ospf): Call ospf_vl_delete() instead of + ospf_vl_data_free(). + + * ospf_interface.c (ospf_vl_shutdown): Execute ISM_InterfaceDown + when ospf_vl_shutdown is called. + (ospf_vl_delete): Call ospf_vl_shutdown() to delete virtual link + interface's thread. + +2000-09-21 Gleb Natapov + + * ospf_lsa.c: New implementation of OSPF refresh. + +2000-09-20 Kunihiro Ishiguro + + * ospf_snmp.c (ospfLsdbLookup): Add LSDB MIB implementation. + +2000-09-18 Kunihiro Ishiguro + + * ospf_snmp.c (ospfStubAreaEntry): Add OSPF stub area MIB. + +2000-09-18 Gleb Natapov + + * ospf_route.h (route_standard): Change member from `struct area' + to area_id. + + * ospf_abr.c (ospf_abr_announce_network), (ospf_abr_should_announce), + (ospf_abr_process_network_rt), (ospf_abr_announce_rtr), + (ospf_abr_process_router_rt): + * ospf_ase.c (ospf_find_asbr_route), + (ospf_find_asbr_router_through_area), + * ospf_ia.c (ospf_find_abr_route), (ospf_ia_router_route), + (process_summary_lsa), (ospf_update_network_route), + (ospf_update_router_route): + * ospf_route.c (ospf_intra_route_add), (ospf_intra_add_router), + (ospf_intra_add_transit), (ospf_intra_add_stub), + (ospf_route_table_dump), (show_ip_ospf_route_network), + (show_ip_ospf_route_router), (ospf_asbr_route_cmp), + (ospf_prune_unreachable_routers): + * ospf_spf.c (ospf_rtrs_print): + * ospfd.c (ospf_rtrs_free): Fix the struct change above. + +2000-09-14 Kunihiro Ishiguro + + * ospf_network.c (ospf_serv_sock_init): Enclose SO_BINDTODEVICE + with ifdef. + +2000-09-13 Gleb Natapov + + * ospf_ism.c (ospf_elect_dr), (ospf_elect_bdr): Fix DR election. + + * ospf_network.c (ospf_serv_sock_init): Add socket option + SO_BINDTODEVICE on read socket. + + * ospf_packet.c (ospf_hello): Ignore Hello packet if E-bit does + not match. + + * ospfd.c (ospf_area_check_free), (ospf_area_get), + (ospf_area_add_if): New function added. + +2000-09-13 Kunihiro Ishiguro + + * ospf_route.c (ospf_intra_add_router): Update ABR and ASBR router + count. + + * ospf_spf.c (ospf_spf_init): Rest ABR and ASBR router count + starting SPF calculation. + + * ospfd.h (struct ospf_area): Add ABR and ASBR router count. + +2000-09-12 Kunihiro Ishiguro + + * ospfd.c (ospf_area_id_cmp): New area structure is sorted by area + ID. + + * ospf_lsa.c (ospf_router_lsa_originate): For OSPF MIB update + lsa_originate_count. + (ospf_network_lsa_originate): Likewise. + (ospf_summary_lsa_originate): Likewise. + (ospf_summary_asbr_lsa_originate): Likewise. + (ospf_external_lsa_originate): Likewise. + +2000-09-11 Kunihiro Ishiguro + + * ospf_snmp.c (ospf_variables): ospfRouterID's type RouterID + syntax is IpAddress. + (ospf_admin_stat): New function for OSPF administrative status + check. + +2000-09-10 Jochen Friedrich + + * ospf_snmp.c: Implement OSPF MIB skeleton. + +2000-09-08 Kunihiro Ishiguro + + * ospf_snmp.c: New file is added. + +2000-09-07 David Lipovkov + + * ospf_zebra.c (ospf_interface_delete): Add pseudo interface + treatment. + + * ospf_interface.c (interface_config_write): Likewise. + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 is released. + +2000-08-17 Michael Rozhavsky + + * ospfd.c (ospf_area_free): Remove virtual link configuration only + when Area is removed. + +2000-08-17 Kunihiro Ishiguro + + * ospfd.c (network_area): Revert check for EXTERNAL_INFO + (ZEBRA_ROUTE_CONNECT). + (no_network_area): Likewise. + +2000-08-16 Kunihiro Ishiguro + + * ospfd.h (struct ospf): Add distance_table and + distance_{all,intra,inter,external}. + + * ospf_zebra.c: Add OSPF distance related functions. + +2000-08-15 Gleb Natapov + + * ospf_asbr.c (ospf_external_info_find_lsa): New function added. + + * ospf_lsa.c (ospf_default_external_info), + (ospf_default_originate_timer), (ospf_external_lsa_refresh_default): + New function added. + + * ospf_zebra.c + (ospf_default_information_originate_metric_type_routemap), + (ospf_default_information_originate_always_metric_type_routemap): + Change name and add route-map function. + (ospf_default_information_originate_metric_routemap), + (ospf_default_information_originate_routemap), + (ospf_default_information_originate_type_metric_routemap): + New DEFUN added. + +2000-08-14 Kunihiro Ishiguro + + * ospf_zebra.c (zebra_interface_if_set_value): Change ifindex + restore size from two octet to four. + +2000-08-14 Michael Rozhavsky + + * ospf_ase.c (ospf_ase_incremental_update): Implement incremental + AS-external-LSA in 16.6 of RFC2328. + +2000-08-14 Matthew Grant + + * ospf_interface.c (ospf_if_get_output_cost): Change cost + calculation algorithm. + + * ospf_packet (ospf_ls_upd): Fix problem of LSA retransmitting. + +2000-08-11 Michael Rozhavsky + + * ospf_lsa.c (ospf_maxage_lsa_remover): Fix maxage remover for + AS-external-LSAs. + +2000-08-10 Toshiaki Takada + + * ospfd.c (auto_cost_reference_bandwidth): New DEFUN added. + `auto-cost reference-bandwidth' OSPF router command added. + +2000-08-08 Gleb Natapov + + * ospf_routemap.c (ospf_route_map_update): New function added. + Add route-map event hook. + +2000-08-08 Toshiaki Takada + + * ospf_zebra.c (ospf_distribute_check_connected): If redistribute + prefix is connected route on OSPF enabled interface, suppress to + announce it. + +2000-08-08 Matthew Grant + + * ospf_interface.c (ospf_if_get_output_cost): + New function added. Handle bandwidth parameter for cost + calculation. + +2000-08-08 Michael Rozhavsky + + * ospf_interface.c (interface_config_write): Show interface + configuration regardless interface is down. + + * ospf_ase.c (ospf_ase_caocluate_route): Whole rewritten external + route calculate function. + +2000-08-08 Gleb Natapov + + * ospf_routemap.c: New file added. + + * ospf_asbr.c (ospf_reset_route_map_set_values), + (ospf_route_map_set_compare): New function added. + + * ospf_lsa.c (ospf_external_lsa_body_set): Set routemap metric + with AS-external-LSA. + +2000-08-05 Kunihiro Ishiguro + + * ospf_ase.c (ospf_ase_calculate_route_add): Pass new->cost to + ospf_zebra_add as metric. + (ospf_ase_calculate_route_add): Likewise. + + * ospf_route.c (ospf_route_install): Pass or->cost to + ospf_zebra_add as metric. + + * ospf_zebra.c (ospf_zebra_add): Add metric arguemnt. + (ospf_zebra_delete): Likewise. + +2000-08-03 Matthew Grant + + * ospf_flood.c (ospf_flood_delayed_lsa_ack): New function added. + Dispatch delayed-ACK with flooding AS-external-LSA across virtual + link. + +2000-07-31 Matthew Grant + + * ospfd.c (show_ip_ospf_area): Fix lack of VTY_NEWLINE when + `show ip ospf'. + + * ospf_interface.c (ospf_if_free): Fix bug of crash with + Point-to-Point interface. + +2000-07-27 Michael Rozhavsky + + * ospf_flood.c (ospf_process_self_originated_lsa): + Make sure to clear LSA->param (redistributed external information) + before refreshment. + +2000-07-27 Gleb Natapov + + * ospfd.c (refresh_group_limit), (refresh_per_slice), + (refresh_age_diff): New defun added. Refresher related parameter + can be configurable. + +2000-07-27 Akihiro Mizutani + + * ospf_interface.c (interface_config_write): Print `description' + config directive to work. + +2000-07-24 Akihiro Mizutani + + * ospf_interface.c (ospf_if_init): Use install_default for + INTERFACE_NODE. + +2000-07-24 Gleb Natapov + + * ospf_packet.c (ospf_ls_upd_send_list), (ospf_ls_upd_send_event), + (ospf_ls_ack_send_list), (ospf_ls_ack_send_event): New function added. + This make sending always as many LS update/Ack combined in one ospf + packet. + +2000-07-24 Gleb Natapov + + * ospf_packet.c (ospf_ls_upd_list_lsa): Set NULL to lsa->area if + LSA is AS-external-LSA. + + * ospf_nsm.c (nsm_reset_nbr): Do not cancel Inactivity timer. + +2000-07-21 Toshiaki Takada + + * ospf_zebra.c (ospf_default_originate_timer): Set timer for + `default-information originate'. Fix some default originate + related functions. + +2000-07-12 Toshiaki Takada + + * ospf_lsa.c (stream_put_ospf_metric): New function added. + +2000-07-12 Toshiaki Takada + + * ospf_lsa.c (show_ip_ospf_database_router), + (show_ip_ospf_database_network), (show_ip_ospf_database_summary), + (show_ip_ospf_database_summary_asbr), (show_ip_ospf_database_externel), + (show_router_lsa), (show_any_lsa), (show_router_lsa_self), + (show_any_lsa_self): Functions removed. + + (show_lsa_prefix_set), (show_lsa_detail_proc), (show_lsa_detail), + (show_lsa_detail_adv_router_proc), (show_lsa_detail_adv_router): + New functions added. Replace above functions. + + (show_ip_ospf_database_all), (show_ip_ospf_database_self_originated): + Functions removed. + (show_ip_ospf_database_summary): New functions added. Replace + above functions. + + (show_ip_ospf_database_cmd): DEFUN rearranged. + (show_ip_ospf_database_type_id_cmd), + (show_ip_ospf_database_type_id_adv_router_cmd), + (show_ip_ospf_database_type_is_self_cmd): New ALIASes added. + (show_ip_ospf_database_type_adv_rotuer_cmd): New DEFUN added. + (show_ip_ospf_database_type_self_cmd): New ALIAS added. + +2000-07-11 Toshiaki Takada + + * ospf_asbr.c (ospf_external_info_new), + (ospf_external_info_free): New functions added. + + * ospf_lsa.h (ospf_lsa): Add new member `void *param' to set + origination parameter for external-LSA. + Remove member `redistribute'. + + * ospf_zebra.c (ospf_redistirbute_set): When `redistribute' + command executed, metric and metric-type values are overridden. + If one of those is changed refresh AS-external-LSAs for appropriate + type. + +2000-07-11 Michael Rozhavsky + + * ospf_lsa.c (ospf_summary_lsa_refresh), + (ospf_summary_asbr_lsa_refresh): Make sure to refresh summary-LSAs. + + * ospf_abr.c (set_metric): New function added. + +2000-07-07 Toshiaki Takada + + * ospf_zebra.c (ospf_default_information_originate_metric_type), + (ospf_default_information_originate_type_metric): New defun added. + Metic and Metric type can be set to default route. + (ospf_default_information_originate_always_metric_type): + (ospf_default_information_originate_always_type_metric): + New defun added. Metric and Metric type can be set to default + always route. + + * ospf_zebra.c (ospf_default_metric), (no_ospf_default_metric): + New defun added. + +2000-07-06 Gleb Natapov + + * ospf_flood.c (ospf_flood_through_area): Fix bug of considering + on the same interface the LSA was received from. + +2000-07-06 Michael Rozhavsky + + * ospfd.c (ospf_config_write): Fix bug of printing `area stub' + command with `write mem'. + + * ospfd.c (no_router_ospf): Remove installed routes from zebra. + + * ospf_zebra.c (ospf_interface_delete): Fix function to handle + zebra interface delete event. + +2000-07-06 Toshiaki Takada + + * ospf_zebra.c (ospf_default_information_originate), + (ospf_default_information_originate_always): New DEFUN added. + +2000-07-05 Michael Rozhavsky + + * ospf_route.c (ospf_terminate): Make sure to remove external route + when SIGINT received. + +2000-07-03 Gleb Natapov + + * ospf_flood.c, ospf_ism.c, ospf_lsa,c, ospfd.c: Make sure to free + many structure with `no router ospf'. + +2000-06-30 Gleb Natapov + + * ospf_neighbor.c (ospf_nbr_new), + ospf_nsm.c (nsm_timer_set): Start LS update timer only + when neighbor enters Exchange state. + +2000-06-29 Gleb Natapov + + * ospf_nsm.c (nsm_timer_set), (nsm_exchange_done), + ospf_packet.c (ospf_db_desc_proc): + Do not cancel DD retransmit timer when Master. + +2000-06-29 Gleb Natapov + + * ospf_abr.c (ospf_abr_announce_network_to_area), + (ospf_abr_announce_rtr_to_area) + ospf_ase.c (ospf_ase_rtrs_register_lsa), + ospf_flood.c (ospf_process_self_originated_lsa), + (ospf_flood_through_area), (ospf_ls_request_delete), + ospf_interface.c (ospf_if_free), + ospf_ism.c (ism_change_status), + ospf_lsa.c (ospf_router_lsa_update_timer), + (ospf_router_lsa_install), (ospf_network_lsa_install), + (ospf_lsa_maxage_delete), (ospf_lsa_action), + (ospf_schedule_lsa_flood_area), + ospf_nsm.c (nsm_change_status), + ospf_packet.c (ospf_make_ls_req_func), (ospf_make_ls_ack): + Use ospf_lsa_{lock,unlock} for all looking-up of LSA. + + * ospf_flood.c (ospf_ls_request_free): Function deleted. + + * ospf_lsa.c (ospf_discard_from_db): New function added. + +2000-06-26 Toshiaki Takada + + * ospfd.h (ospf): struct member `external_lsa' name changed to + `lsdb'. + +2000-06-26 Toshiaki Takada + + * ospf_lsa.c (ospf_lsa_install), (ospf_router_lsa_install), + (ospf_network_lsa_install), (ospf_summary_lsa_install), + (ospf_summary_asbr_lsa_install), (ospf_external_lsa_install): + Functions re-arranged. + + * ospf_lsa.c (IS_LSA_MAXAGE), (IS_LSA_SELF): Macro added. + +2000-06-20 Michael Rozhavsky + + * ospf_packet.c (ospf_ls_req), (ospf_ls_upd), (ospf_ls_ack): Add + verification of LS type. + +2000-06-20 Gleb Natapov + + * ospf_ase.c (ospf_ase_calculate_timer): Add more sanity check + whether rn->info is NULL. + +2000-06-20 Toshiaki Takada + + * ospfd.c (show_ip_ospf_interface_sub): Show Router-ID of both + DR and Backup correctly with `show ip ospf interface' command. + +2000-06-20 Toshiaki Takada + + * ospf_lsa.c (ospf_lsa_lock), (ospf_lsa_unlock), + (ospf_lsa_discard): These functions are used for avoiding + unexpected reference to freed LSAs. + +2000-06-13 Kunihiro Ishiguro + + * ospf_packet.c (ospf_ls_upd): Initialize lsa by NULL to avoid + warning. + +2000-06-12 Kunihiro Ishiguro + + * ospf_ase.h (ospf_ase_rtrs_register_lsa): Add prototype. + +2000-06-12 Toshiaki Takada + + * ospf_lsa.c (ospf_external_lsa_install): Make sure to register + LSA to rtrs_external when replacing AS-external-LSAs in LSDB. + Fix core dump. + +2000-06-10 Toshiaki Takada + + * ospf_lsdb.c (id_to_prefix), (ospf_lsdb_hash_key), + (ospf_lsdb_hash_cmp), (ospf_lsdb_new), (ospf_lsdb_iterator), + (lsdb_free), (ospf_lsdb_free), (ospf_lsdb_add), (ospf_lsdb_delete), + (find_lsa), (ospf_lsdb_lookup), (find_by_id), + (ospf_lsdb_lookup_by_id), (ospf_lsdb_lookup_by_header): Functinos + removed for migration to new_lsdb. + + * ospf_lsa.c (ospf_summary_lsa_install), + (ospf_summary_asbr_lsa_install), (ospf_maxage_lsa_remover), + (ospf_lsa_maxage_walker), (ospf_lsa_lookup), + (ospf_lsa_lookup_by_id): Use new_lsdb instead of ospf_lsdb. + (count_lsa), (ospf_lsa_count_table), (ospf_lsa_count), + (ospf_get_free_id_for_prefix): Funcitions removed. + +2000-06-09 Gleb Natapov + + * ospf_ism.c (ism_interface_down): Prevent some unneeded DR changes. + + * ospf_packet.c (ospf_db_desc_proc): Fix memory leak. + (ospf_hello): Always copy router-ID when hello is received. + +2000-06-08 Gleb Natapov + + * ospf_lsa.h (struct ospf_lsa): Add member of pointer to struct + ospf_area. + +2000-06-08 Michael Rozhavsky + + * ospf_ase.c (ospf_asbr_route_same): New function added. + This function makes sure external route calculation more + precisely. + +2000-06-07 Michael Rozhavsky + + * ospf_ism.c (ism_change_status): Use ospf_lsa_flush_area for + network-LSA deletion instead of using ospf_lsdb_delete. + Also cancel network-LSA origination timer. + +2000-06-07 Levi Harper + + * ospf_interface.c (ospf_if_down): Close read fd when an interface + goes down. + +2000-06-05 Kunihiro Ishiguro + + * ospf_asbr.c (ospf_external_info_lookup): Add explicit brace for + avoid ambiguous else. + + * ospf_flood.c (ospf_external_info_check): Likewise. + +2000-06-05 Toshiaki Takada + + * ospf_nsm.c (nsm_adj_ok): Fix bug of DR election. + +2000-06-04 Toshiaki Takada + + * ospf_zebra.c (ospf_default_information_originate), + (no_ospf_default_information_originate): New DEFUN added. + +2000-06-03 Toshiaki Takada + + * ospf_lsa.h, ospf_asbr.h (external_info): Struct moved from + ospf_lsa.h to ospf_asbr.h. + + * ospf_lsa.c, ospf_asbr.c (ospf_external_info_add), + (ospf_external_info_delete): Function moved from ospf_lsa.c + to ospf_asbr.c. + +2000-06-03 Toshiaki Takada + + * ospf_flood.c (ospf_external_info_check): New function added. + (ospf_process_self_orignated_lsa): Make sure to flush + self-originated AS-external-LSA, when router reboot and no longer + originate those AS-external-LSA. + +2000-06-02 Toshiaki Takada + + * ospf_network.c (ospf_serv_sock): Remove SO_DONTROUTE + socket option. + + * ospf_packet.c (ospf_write): Set MSG_DONTROUTE flag for + unicast destination packets. + +2000-06-02 Toshiaki Takada + + * ospf_lsdb.c (new_lsdb_delete): Delete entry from LSDB only when + specified LSA matches. + +2000-06-02 Gleb Natapov + + * ospf_network.c (ospf_serv_sock): Set SO_DONTROUTE + socket option. + +2000-06-01 Akihiro Mizutani + + * ospf_dump.c: Replace string `Debugging functions\n' with DEBUG_STR. + Replace string `OSPF information\n' with OSPF_STR. + +2000-06-01 Toshiaki Takada + + * ospf_lsdb.[ch]: Use new_lsdb struct for network-LSA instead of + ospf_lsdb. + +2000-06-01 Toshiaki Takada + + * ospf_dump.c (config_debug_ospf_packet), (config_debug_ospf_event), + (config_debug_ospf_ism), (config_debug_ospf_nsm), + (config_debug_ospf_lsa), (config_debug_ospf_zebra), + (term_debug_ospf_packet), (term_debug_ospf_event), + (term_debug_ospf_ism), (term_debug_ospf_nsm), + (term_debug_ospf_lsa), (term_debug_ospf_zebra): Repalce debug_ospf_* + variable to use for debug option flags. + + (debug_ospf_packet), (debug_ospf_ism), (debug_ospf_nsm), + (debug_ospf_lsa), (debug_ospf_zebra): Set {config,term}_debug_* + flags when vty->node is CONFIG_NODE, otherwise set only term_debug_* + flags. + + * ospf_dump.h (CONF_DEBUG_PACKET_ON), (CONF_DEBUG_PACKET_OFF), + (TERM_DEBUG_PACKET_ON), (TERM_DEBUG_PACKET_OFF), + (CONF_DEBUG_ON), (CONF_DEBUG_OFF), (IS_CONF_DEBUG_OSPF_PACKET), + (IS_CONF_DEBUG_OSPF): New Macro added. + +2000-05-31 Toshiaki Takada + + * ospfd.c (clear_ip_ospf_neighbor): New DEFUN added. + Currently this command is used for only debugging. + + * ospf_nsm.c (nsm_change_status): Make sure thread cancellation + for network-LSA when DR has no full neighbors. + + * ospf_nsm.c (ospf_db_summary_clear): New function added. + +2000-05-30 Toshiaki Takada + + * ospf_lsdb.c (new_lsdb_insert): LSAs are always freed by + maxage_lsa_remover when LSA is replaced. + +2000-05-25 Gleb Natapov + + * ospf_flood.c (ospf_ls_retransmit_delete_nbr_all): Add argument + `struct ospf_area' to remove LSA from Link State retransmission list + of neighbor from only one Area. + +2000-05-24 Michael Rozhavsky + + * ospf_lsdb.c (ospf_lsdb_add): Preserve flags field when + overriting old LSA with new LSA. + +2000-05-24 Gleb Natapov + + * ospf_lsa.c (ospf_router_lsa_body_set): Fix bug of router-LSA + size calculation. + +2000-05-22 Michael Rozhavsky + + * ospf_route.c (ospf_intra_add_stub): + * ospf_spf.h (struct vertex): Use u_int32_t for distance (cost) + value instead of u_int16_t. + +2000-05-22 Axel Gerlach + + * ospf_ia.c (ospf_ia_network_route): Fix bug of Inter-area route + equal cost path calculation. + +2000-05-21 Toshiaki Takada + + * ospf_ase.c (ospf_ase_calculate_route_delete): New function added. + Make sure, when rotuer route is deleted, related external routes + are also deleted. + +2000-05-20 Toshiaki Takada + + * ospfd.c (ospf_interface_down): Make sure interface flag is disable + and set fd to -1. + +2000-05-16 Toshiaki Takada + + * ospf_asbr.c (ospf_asbr_should_announce), (ospf_asbr_route_remove): + Functions removed. + + * ospfd.h (EXTERNAL_INFO): Macro added. + Substitute `ospf_top->external_info[type]' with it. + +2000-05-16 Toshiaki Takada + + * ospf_lsa.c (ospf_rtrs_external_remove): New function added. + +2000-05-14 Gleb Natapov + + * ospf_flood.c (ospf_ls_retransmit_delete_nbr_all) + * ospf_lsdb.c (new_lsdb_insert) + * ospf_packet.c (ospf_ls_ack): Fix database synchonization problem. + +2000-05-14 Gleb Natapov + + * ospf_lsa.h (tv_adjust), (tv_ceil), (tv_floor), (int2tv), + (tv_add), (tv_sub), (tv_cmp): Prototype definition added. + + * ospf_nsm.h (ospf_db_summary_delete_all): Prototype definition added. + +2000-05-13 Toshiaki Takada + + * ospf_lsa.[ch] (ospf_lsa): struct timestamp type is changed from + time_t to struct timeval. + (tv_adjust), (tv_ceil), (tv_floor), (int2tv), (tv_add), + (tv_sub), (tv_cmp): timeval utillity functions added. + +2000-05-12 Toshiaki Takada + + * ospf_lsa.[ch] (ospf_schedule_update_router_lsas): Delete function. + Change to use macro OSPF_LSA_UPDATE_TIMER instead of using + this function. + router-LSA refresh timer related stuff is re-organized. + +2000-05-10 Gleb Natapov + + * ospf_interface.c (ospf_vl_set_params): + * ospf_packet.c (ospf_check_network_mask): + * ospf_spf.[ch] (ospf_spf_next): + Remove field address from `struct vertex', and search for peer + address of virtual link in function `ospf_vl_set_params' instead. + +2000-05-10 Gleb Natapov + + * ospf_packet.c (ospf_ls_upd): Fix some memory leak related LSA. + +2000-05-08 Thomas Molkenbur + + * ospf_packet.c (ospf_packet_dup): Replace ospf_steram_copy() + with ospf_stream_dup() to fix memory leak. + +2000-05-08 Michael Rozhavsky + + * ospf_flood.c (ospf_flood_through_area): Fix the problem of + LSA update without DROther. + +2000-05-04 Gleb Natapov + + * ospf_spf.c (ospf_vertex_free): Fix memory leak of SPF calculation. + +2000-05-03 Toshiaki Takada + + * ospf_neighbor.c (ospf_db_summary_add): Use new_lsdb struct + instead linked-list. + (ospf_db_summary_count), (ospf_db_summary_isempty): + New function added. + + * ospf_lsa.c (ospf_rotuer_lsa): Re-arrange and divide functions. + +2000-05-02 Gleb Natapov + + * ospf_lsdb.c (new_lsdb_cleanup): Fix memory leak. When LSDB are + not needed any more, then free them. + +2000-05-02 Toshiaki Takada + + * ospfd.c (timers_spf), (no_timers_spf): New defun added. + SPF calculation timers related stuff is rearranged. + + * ospf_spf.c (ospf_spf_calculate_timer_add): Function removed. + SPF timer is scheduled by SPF calculation delay and holdtime + configuration variable. + + * ospf_lsa.c (ospf_external_lsa_nexthop_get): Set AS-external-LSA's + forwarding address when nexthop learned by other protocols is + in the OSPF domain. + + * ospf_zebra.c (ospf_redistribute_source_metric_type), + (ospf_redistribute_source_type_metric): Re-arrange DEFUNs and + ALIASes. + +2000-05-01 Toshiaki Takada + + * ospf_flood.c (ospf_ls_retransmit_count), + (ospf_ls_retransmit_isempty): New function added. + + (ospf_ls_retransmit_add), (ospf_ls_retransmit_delete), + (ospf_ls_retransmit_clear), (ospf_ls_retransmit_lookup), + (ospf_ls_retransmit_delete_all), (ospf_ls_retransmit_delete_nbr_all), + (ospf_ls_retransmit_add_nbr_all): Replace these functions to use + new_lsdb. + +2000-04-29 Toshiaki Takada + + * ospfd.c (no_network_area): Add check Area-ID whether specified + Area-ID with prefix matches config. + +2000-04-27 Toshiaki Takada + + * ospf_lsa.c (ospf_maxage_lsa_remover): Fix problem of + remaining withdrawn routes on zebra. + +2000-04-25 Michael Rozhavsky + + * ospf_nsm.c (nsm_kill_nbr), (nsm_ll_down), (nsm_change_status), + (ospf_nsm_event): Fix network-LSA re-origination problem. + +2000-04-24 Toshiaki Takada + + * ospf_nsm.c (ospf_db_desc_timer): Fix bug of segmentation fault + with DD retransmission. + + * ospf_nsm.c (nsm_kill_nbr): Fix bug of re-origination when + a neighbor disappears. + +2000-04-23 Michael Rozhavsky + + * ospf_abr.c (ospf_abr_announce_network_to_area): Fix bug of + summary-LSAs reorigination. Correctly copy OSPF_LSA_APPROVED + flag to new LSA. when summary-LSA is reoriginatd. + + * ospf_flood.c (ospf_flood_through_area): Fix bug of flooding + procedure. Change the condition of interface selection. + +2000-04-21 Toshiaki Takada + + * ospf_lsa.c (ospf_refresher_register_lsa): Fix bug of refresh never + occurs. + + * ospfd.c (show_ip_ospf_neighbor_id): New defun added. + `show ip ospf neighbor' related commands are re-arranged. + +2000-04-20 Toshiaki Takada + + * ospf_dump.c (debug_ospf_zebra): New defun added. + Suppress zebra related debug information. + +2000-04-19 Toshiaki Takada + + * ospf_zebra.c (ospf_distribute_list_update_timer), + (ospf_distribute_list_update), (ospf_filter_update): + New function added. Re-organize `distribute-list' router ospf + command. + +2000-04-13 Michael Rozhavsky + + * ospf_packet.c (ospf_make_ls_upd): Add check for MAX_AGE. + +2000-04-14 Michael Rozhavsky + + * ospf_packet.c (ospf_make_ls_upd): Increment LS age by configured + interface transmit_delay. + +2000-04-14 Sira Panduranga Rao + + * ospf_interface.c (ip_ospf_cost), (no_ip_ospf_cost): + Add to schedule router_lsa origination when the interface cost changes. + +2000-04-12 Toshiaki Takada + + * ospf_lsa.c (ospf_refresher_register_lsa), + (ospf_refresher_unregister_lsa): Fix bug of core dumped. + + * ospfd.c (no_router_ospf): Fix bug of core dumped. + +2000-03-29 Toshiaki Takada + + * ospf_nsm.c (nsm_oneway_received): Fix bug of MS flag unset. + +2000-03-29 Michael Rozhavsky + + * ospf_lsa.c (ospf_network_lsa): + * ospf_nsm.c (ospf_nsm_event): Fix bug of Network-LSA originated + in stub network. + +2000-03-28 Toshiaki Takada + + * ospf_nsm.c (nsm_bad_ls_req), (nsm_seq_number_mismatch), + (nsm_oneway_received): Fix bug of NSM state flapping between + ExStart and Exchange. + +2000-03-28 Toshiaki Takada + + * ospf_packet.h (strcut ospf_header): Fix the size of ospf_header, + change u_int8_t to u_char. + +2000-03-27 Toshiaki Takada + + * ospf_lsa.c (ospf_lsa_checksum): Take care of BIGENDIAN architecture. + +2000-03-27 Toshiaki Takada + + * ospfd.c (ospf_interface_run): Make sure Address family matches. + +2000-03-26 Love + + * ospf_packet.c (ospf_write): Chack result of sendto(). + +2000-03-26 Sira Panduranga Rao + + * ospf_nsm.c (nsm_oneway_received): Fix bug of 1-WayReceived in NSM. + +2000-03-23 Libor Pechacek + + * ospf_lsa.c (ospf_network_lsa) + * ospf_lsdb.c (new_lsdb_insert): Fix bug of accessing to + unallocated memory. + +2000-03-23 Toshiaki Takada + + * ospfd.c (ospf_config_write): Fix bug of duplicate line for + `area A.B.C.D authentication'. + +2000-03-22 Toshiaki Takada + + * ospf_debug.c (debug_ospf_lsa), (no_debug_ospf_lsa): Defun added. + Suppress all zlog related to LSAs with this config option. + +2000-03-21 Kunihiro Ishiguro + + * ospf_nsm.c (ospf_nsm_event): Add check for NSM_InactivityTimer. + +2000-03-21 Toshiaki Takada + + * ospf_packet.c (ospf_ls_upd_timer), (ospf_ls_req): + Fix bug of memory leak about linklist. + + * ospf_flood.c (ospf_flood_through_area): Likewise. + +2000-03-18 Sira Panduranga Rao + + * ospf_flood.c (ospf_ls_retransmit_lookup): Add checksum comparison + to identify LSA uniquely. This fix routes lost. + +2000-03-18 Toshiaki Takada + + * ospf_ase.c (ospf_find_asbr_route): Add sanity check with router + routing table. + +2000-03-17 Alex Zinin + + * ospf_spf.[ch]: Bug fix. + The 2nd stage of Dijkstra could consider one vertex + more than once if there is more than one link + between the routers, thus adding extra CPU overhead + and extra next-hops. + Fixed. + +2000-03-15 Sira Panduranga Rao + + * ospf_nsm.c (nsm_inactivity_timer): Changed to call nsm_kill_nbr(). + +2000-03-14 Toshiaki Takada + + * ospf_route.c (ospf_route_copy_nexthops): Fix bug of memory leak of + ospf_path. Actually ignore merging ospf_route with completely same + paths. + +2000-03-12 Toshiaki Takada + + * ospf_lsa.c (show_as_external_lsa_detail): fix bug of + external route tag byte order. + +2000-03-11 Toshiaki Takada + + * ospf_lsdb.c (ospf_lsdb_insert): New function added. + +2000-03-09 Toshiaki Takada + + * ospf_lsa.c (ospf_external_lsa_install), + (ospf_lsa_lookup), (show_ip_ospf_database_all), + (show_ip_ospf_database_self_originate): Use struct new_lsdb for + LSDB of AS-external-LSAs instead of ospf_lsdb. + + * ospf_lsa.c (ospf_lsa_unique_id): New function added. + Use for assigning Unique Link State ID instead of + ospf_get_free_id_for_prefix(). + +2000-03-09 Toshiaki Takada + + * ospf_ase.c (ospf_ase_calculate_timer): Fix bug of segmentation + fault reported by George Bonser . + +2000-03-07 Libor Pechacek + + * ospfd.c (ospf_interface_down): Fix bug of segmentation fault. + +2000-03-06 Toshiaki Takada + + * ospf_route.c (ospf_route_cmp): Change meaning of return values. + +2000-03-02 Alex Zinin + * ospfd.h, ospf_ia.h + New Shortcut ABR code. Now area's flag can be configured + with Default, Enable, and Disable values. + More info will be in the new ver of I-D soon (see IETF web). + +2000-02-25 Toshiaki Takada + + * ospf_lsa.c (ospf_lsa_header_set), (ospf_external_lsa_body_set), + (osfp_external_lsa_originate), (ospf_external_lsa_queue), + (ospf_external_lsa_originate_from_queue): New function added. + (ospf_external_lsa): Function removed. + + * ospf_zebra.c (ospf_zebra_read_ipv4): Originate AS-external-LSA + when listen a route from Zebra, instead creating external route. + + * ospf_asbr.c (ospf_asbr_route_add_flood_lsa), + (ospf_asbr_route_add_queue_lsa), + (ospf_asbr_route_install_lsa), (ospf_asbr_route_add): + Functions removed. + + * ospf_ase.c (process_ase_lsa): Function will not be used. + (ospf_ase_calculate), (ospf_ase_calculate_route_add), + (ospf_ase_calculate_new_route), (ospf_ase_caluculate_asbr_route): + process_ase_lsa () is separated to these functions. + + OSPF AS-external-LSA origination is whole re-organized. + +2000-02-18 Toshiaki Takada + + * ospf_packet.c (ospf_ls_upd): Fix bug of OSPF LSA memory leak. + + * ospf_asbr.c (ospf_asbr_route_add_flood_lsa), + (ospf_asbr_route_add_queue_lsa): Fix bug of OSPF external route + memory leak. + +2000-02-12 Kunihiro Ishiguro + + * ospf_asbr.c (ospf_asbr_route_install_lsa): Re-calculate LSA + checksum after change Advertised Router field. + +2000-02-09 Toshiaki Takada + + * ospf_asbr.c (ospf_external_route_lookup): Add new function. + +2000-02-08 Toshiaki Takada + + * ospfd.c (ospf_router_id_get), (ospf_router_id_update), + (ospf_router_id_update_timer): Router ID decision algorithm is changed. + Router ID is chosen from all of eligible interface addresses even if + it is not enable to OSPF. + +2000-02-08 Toshiaki Takada + + * ospf_asbr.c (ospf_asbr_route_add): Function divided to + ospf_asbr_route_add_flood_lsa, ospf_asbr_route_add_queue_lsa and + ospf_asbr_route_install_lsa. If Router-ID is not set, then LSA is + waited to install to LSDB. + `0.0.0.0 adv_router' AS-external-LSA origination bug was fixed. + +2000-02-01 Sira Panduranga Rao + + * ospf_flood.c (ospf_ls_retransmit_lookup): Compare LS seqnum + in the ACK before deleting. + + * ospf_packet.c (ospf_hello): Reset the flags after a shutdown + and no shutdown of the interface. + +2000-01-31 Toshiaki Takada + + * ospf_packet.c (ospf_ls_req): Send multiple Link State Update + packets respond to a Link State Request packet. + + * ospfd.c (show_ip_ospf_neighbor_detail_sub): Show thread state. + + * ospf_interface.c (ospf_vl_new): Crash when backbone area + is not configured and set virtual-link to no-backbone area, + bug fixed. + +2000-01-30 Kunihiro Ishiguro + + * ospf_neighbor.h (struct ospf_neighbor): Add pointer to last send + LS Request LSA. + + * ospf_packet.c (ospf_ls_upd): Comment out LS request list + treatment. That should be done in OSPF flooding procedure. + + * ospf_flood.c (ospf_flood_through_area): Enclose + ospf_check_nbr_loding inside if-else close. + +2000-01-31 Toshiaki Takada + + * ospf_packet.c (ospf_make_ls_upd): Fix bug of #LSAs counting. + +2000-01-29 Toshiaki Takada + + * ospf_packet.c (ospf_make_md5_digest): Fix bug of md5 authentication. + +2000-01-28 Toshiaki Takada + + * ospfd.c (show_ip_ospf): Show Number of ASE-LSAs. + +2000-01-27 Kunihiro Ishiguro + + * ospf_packet.c (ospf_make_db_desc): Don't use rm_list for + removing LSA from nbr->db_summary. + +2000-01-27 Sira Panduranga Rao + + * ospf_packet.c (ospf_ls_upd_send): Set AllSPFRouters to + destination when the link is point-to-point. + (ospf_ls_ack_send_delayed): Likewise. + +2000-01-27 Kunihiro Ishiguro + + * ospf_flood.c (ospf_ls_request_delete_all): Fix bug of next + pointer lookup after the node is freed. + +2000-01-26 Kunihiro Ishiguro + + * ospf_asbr.c (ospf_asbr_route_add): Instead of scanning all AS + external route, use ospf_top->external_self. + +2000-01-27 Toshiaki Takada + + * ospf_lsa.c (ospf_forward_address_get): New function added. + + * ospf_asbr.c (ospf_asbr_check_lsas): Originate AS-external-LSA + only when it should be replaced. + +2000-01-25 Kunihiro Ishiguro + + * ospf_flood.c (ospf_ls_retransmit_clear): Delete list node. + + * ospf_lsa.c (ospf_lsa_free): Reduce logging message using + ospf_zlog value. + + * ospf_ism.c (ism_change_status): Fix bug of DR -> non DR status + change. Self originated LSA is freed but not deleted from lsdb. + +2000-01-24 Kunihiro Ishiguro + + * ospf_ism.c (ism_interface_down): Don't use router_id for + detecting self neighbor structure. Instead of that compare + pointer itself. + + * ospf_neighbor.c (ospf_nbr_free): Cancel all timer when neighbor + is deleted. + (ospf_nbr_free): Free last send packet. + + * ospf_neighbor.h (struct ospf_neighbor): Remove host strucutre. + Instead of that src is introduced. + + * ospf_nsm.h: Enclose macro defenition with do {} while (0). + +2000-01-17 Kunihiro Ishiguro + + * ospfd.c: Change part of passive interface implementation. For + passive interface just disabling sending/receiving Hello on the + interface. + +2000-01-16 Kai Bankett + + * ospf_interface.h (OSPF_IF_PASSIVE): Add passive flag. + * ospf_interface.c (ospf_if_lookup_by_name): Add new function. + * ospf_lsa.c (ospf_router_lsa): Skip passive interface. + * ospfd.c (passive_interface): New command passive-interface is + added. + (ospf_config_write): Print passive interface. + +2000-01-15 Toshiaki Takada + + * ospf_interface.h (crypt_key): New struct added to store + multiple cryptographic autheitication keys. + (ospf_interface): struct changed. + + * ospf_interface.c: ospf_crypt_key_new, ospf_crypt_key_add, + ospf_crypt_key_lookup, ospf_crypt_key_delete: new functions added. + + * ospf_packet.c (ip_ospf_message_digest_key): Changed to store + multiple cryptographic authentication keys. + +2000-01-14 Toshiaki Takada + + * ospf_interface.c: DEFUN (if_ospf_*) commands changed name to + ip_ospf_* (). + Old notation `ospf *' still remains backward compatibility. + +1999-12-29 Alex Zinin + * ospf_lsa.c: ospf_lsa_more_recent() bug fix + * ospf_nsm.c, ospf_packet.c: remove nbr data struct when + int goes down, also check DD flags correctly (bug fix) + +1999-12-28 Alex Zinin + * "redistribute metric-type (1|2) metric " added + +1999-12-23 Alex Zinin + * added RFC1583Compatibility flag + * added dynamic interface up/down functionality + +1999-11-19 Toshiaki Takada + + * ospf_neighbor.h (struct ospf_neighbor): Add member state_change + for NSM state change statistics. + +1999-11-19 Toshiaki Takada + + * ospfd.c (show_ip_ospf_neighbor_detail), + (show_ip_ospf_neighbor_int_detail): DEFUN Added. + +1999-11-14 Kunihiro Ishiguro + + * ospf_asbr.c (ospf_asbr_check_lsas): Add check of + lsa->refresh_list. + +1999-11-11 Toshiaki Takada + + * ospf_ia.[ch] (OSPF_EXAMINE_SUMMARIES_ALL): Macro added. + This macro is expanded to ospf_examine_summaries () + for SUMMARY_LSA and SUMMARY_LSA_ASBR. + (OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL): Macro added. + This macro is expanded to ospf_examine_transit_summaries () + for SUMMARY_LSA and SUMMARY_LSA_ASBR. + +1999-11-11 Toshiaki Takada + + * ospf_lsa.[ch] (ospf_find_self_summary_lsa_by_prefix): Changed to + macro OSPF_SUMMARY_LSA_SELF_FIND_BY_PREFIX. + (ospf_find_self_summary_asbr_lsa_by_prefix): Changed to + macro OSPF_SUMMARY_ASBR_LSA_SELF_FIND_BY_PREFIX. + (ospf_find_self_external_lsa_by_prefix): Changed to + macro OSPF_EXTERNAL_LSA_SELF_FIND_BY_PREFIX. + +1999-11-11 Toshiaki Takada + + * ospfd.c (ospf_abr_type): ospf_abr_type_cisco, ospf_abr_type_ibm, + ospf_abr_type_shortcut and ospf_abr_type_standard DEFUNs are + combined. + * ospfd.c (no_ospf_abr_type): no_ospf_abr_type_cisco, + no_ospf_abr_type_ibm and no_ospf_abr_type_shortcut DEFUNS are + combined. + +1999-11-10 Toshiaki Takada + + * ospf_route.c (ospf_lookup_int_by_prefix): Move function to + ospf_interface.c and change name to ospf_if_lookup_by_prefix (). + +1999-11-01 Alex Zinin + * ospf_packet.c + some correction to LSU processing + + * ospf_lsa.c ospfd.h + randomize initial LSA refreshment interval + and limit the size of LSA-group to 10 + to let randomization work more effectively. + +1999-10-31 Alex Zinin + * ospf_interface.c + cancel t_network_lsa_self + when freeing int structure + + * ospf_abr.c ospf_asbr.c ospf_flood.c ospf_lsa.c + ospf_lsa.h ospf_lsdb.h ospfd.c ospfd.h + + Summary and ASE LSA refreshment functions + added---LSA refreshment is paced to 70 LSAs + per sec to avoid link overflow. Refreshment events + are further randomized within a 10 sec interval + to avoid syncing. + + Also the sigfault of memcmp() in ospf_lsa_is_different() + is fixed. + +1999-10-30 Alex Zinin + * ospf_nsm.c + Fix the bug where MAX_AGE LSAs + are included into the DB summary. + + * ospf_interface.c + allocate 2*MTU input buffer instead of just MTU + for the cases when the other router mistakenly + sends larger packets thus causing fragmentation, etc. + + * ospf_nsm.c + in nsm_reset_nbr() lists should be freed + not when they are empty. + +1999-10-29 Kunihiro Ishiguro + + * ospf_zebra.c (ospf_acl_hook): Move OSPF_IS_ASBR and OSPF_IS_ABR + check inside of if (ospf_top). + +1999-10-29 Alex Zinin + * ospf_lsa.c ospf_lsdb.c : + add assertion in lsa and lsa->data alloc functions, + as well as in lsdb_add for new->data + + * ospf_lsdb.c: free hash table correctly + +1999-10-28 John Capo + + * ospf_packet.h (OSPF_PACKET_MAX): Correct MAX packet length + calculation + +1999-10-27 Kunihiro Ishiguro + + * OSPF-TRAP-MIB.txt: New file added. Edited version of RFC1850. + + * OSPF-MIB.txt: New file added. Edited version of RFC1850. + +1999-10-27 Alex Zinin + * ospfd, ospf_zebra, ospf_abr + "area import-list" command is added. + This command allows to filter the inter-area routes + injected into an area. Access list hook function + extended to invalidate area exp/imp lists. + +1999-10-25 Yoshinobu Inoue + + * ospfd.c (ospf_interface_run): Enable to detect P2P network + on an OSPF interface. + +1999-10-19 Jordan Mendelson + + * ospf_lsdb.c (ospf_lsdb_add): Fix bug of crash + in ospf_ls_retransmit_lookup (). + +1999-10-19 Vladimir B. Grebenschikov + + * ospf_route.c: Workaround about installation of OSPF routes into + the zebra daemon. Add checking of existance routes. Free + ospf_top->old_table if it exists. + +1999-10-15 Jordan Mendelson + + * Add support for MD5 authentication. + +1999-10-12 Alex Zinin + * ospfd.c, ospfd.h, ospf_abr.c: + a new command "area export-list" was added, it allows + the admin. to control which intra-area routes are + announced to other areas by the ABR + +1999-10-12 Alex Zinin + * ospf_asbr.c (ospf_asbr_check_lsas): Fix bug of coredump + when "no redistribute" is used after a distribute list + denying some networks was used + +1999-10-05 Toshiaki Takada + + * ospf_route.c (ospf_path_dup): New function added. + +1999-10-05 Toshiaki Takada + + * ospf_interface.[ch]: Some of VL related funciton name changed. + +1999-09-27 Alex Zinin + + * ospf_zebra.c: Distribute-list functionality added + +1999-09-27 Toshiaki Takada + + * ospfd.c (show_ip_ospf): Fix bug of segmentation fault when no ospf + instance exists. + +1999-09-25 Kunihiro Ishiguro + + * ospfd.c (ospf_interface_down): Fix bug of misusing nextnode() + instead of node->next. Reported by Hiroki Ishibashi + . + + * ospf_route.c (show_ip_ospf_route): Add check for ospf is enabled + or not. + +1999-09-23 Alex Zinin + + * stub area support added + +1999-09-23 Alex Zinin + + * fwd_addr in ASE-LSAs is now set correctly + * ASE routing changed to check the fwd_addr + and skip the route if the addr points to one + of our interfaces to avoid loops. + +1999-09-22 Alex Zinin + + * ospf_interface: + ospf_vls_in_area() added, it returns + the number of VLs configured through the area + + * ospf_interface.c ospf_lsa.c ospf_lsdb.c ospfd.c + honor correct mem alloc + +1999-09-22 Alex Zinin + + * memory.[ch]: + Some OSPF mem types added, + plus more info in "show mem" + +1999-09-21 Alex Zinin + + * ospfd.c: + "area range substitute" added. + It can be used on NAT-enabled (IP-masquarade) + routers to announce private networks + from an area as public ones into the outside + world (not in the RFC, btw :) + +1999-09-21 Alex Zinin + + * ospfd.c: + "area range suppress" added. + This command allows to instruct the router + to be silent about specific ranges, i.e., + it is a method of route filtering on area + borders + +1999-09-21 Alex Zinin + + * ospfd.c VLs removed when "no network area" executed + +1999-09-20 Alex Zinin + + * ospf_ase.c bug fix for not-zero fwd_addr + and directly connected routes. + +1999-09-20 Yon Uriarte + + * ospf_packet.c (ospf_make_ls_req): Introduce delta value for + checking the length of OSPF packet exceeds MTU or not. + + * ospf_lsa.c (ospf_lsa_different): Apply ntohs for checking + l1->data->length. + +1999-09-18 Alex Zinin + + * ospf_lsa.c bug fix for ospf_network_lsa() to + include itself into the RID list + +1999-09-10 Alex Zinin + + * Alternative ABR behaviors IBM/Cisco/Shortcut + implemented + +1999-09-10 Alex Zinin + + * router and network-LSA origination + changed to honor MinLSInterval + +1999-09-08 Alex Zinin + + * modified ABR behavior to honor VLs and transit + areas + +1999-09-07 Alex Zinin + + * completed VL functionality + +1999-09-06 Kunihiro Ishiguro + + * ospf_asbr.c: New file. + ospf_asbr.h: New file. + + * ospf_zebra.c (ospf_redistribute_connected): Add redistribute + related stuff. + +1999-09-05 Kunihiro Ishiguro + + * ospfd.h (OSPF_FLAG_VIRTUAL_LINK): Change OSPF_FLAG_VEND to + OSPF_FLAG_VIRTUAL_LINK for comprehensiveness. + +1999-09-03 Kunihiro Ishiguro + + * ospf_spf.c (ospf_spf_register): Change name from + ospf_spf_route_add() to ospf_spf_register(). + Include "ospfd/ospf_abr.h" for ospf_abr_task() prototype. + +1999-09-02 Kunihiro Ishiguro + + * ospf_lsa.c (ospf_external_lsa_install): Change to update + lsa->data rather than install new one, when same id lsa is already + installed. + +1999-09-01 Kunihiro Ishiguro + + * ospf_lsa.c (ospf_router_lsa_install): Return lsa value. + (ospf_network_lsa_install): Likewise. + (ospf_summary_lsa_install): Likewise. + (ospf_summary_asbr_lsa_install): Likewise. + (ospf_external_lsa_install): Likewise. + + * ospf_spf.c (ospf_spf_calculate): Comment out debug function + ospf_rtrs_print(). + +1999-08-31 Kunihiro Ishiguro + + * ospf_spf.c (ospf_rtrs_free): Add ospf_spf_calculate() for + freeing rtrs. + +1999-08-31 Toshiaki Takada + + * ospf_lsa.c (show_ip_ospf_database_summary), + (show_ip_ospf_database_summary_asbr), + (show_ip_ospf_database_external): New function added. + `show ip ospf database summary', + `show ip ospf database asbr-summary' + `show ip ospf database external' command can be used. + + * ospf_lsa.c (ospf_lsa_count_table): New function added. + (show_ip_ospf_database_all): show nothing if a type of LSA + does not exist. + +1999-08-31 Kunihiro Ishiguro + + * ospf_lsa.c (ospf_maxage_lsa_remover): Preserve next pointer when + the node is deleted. + +1999-08-31 Toshiaki Takada + + * ospf_flood.c (ospf_ls_retransmit_lookup): change to return + struct ospf_lsa *. + (ospf_ls_request_new), (ospf_ls_request_free), + (ospf_ls_request_add), (ospf_ls_request_delete), + (ospf_ls_request_delete_all), (ospf_ls_request_lookup): + New function added. + + * ospf_packet.c (ospf_ls_upd_send_lsa): New function added. + + * ospf_lsa.h (LS_AGE): Slightly change macro definition. + + * ospf_lsa.c (ospf_lsa_more_recent), (ospf_lsa_diffrent): + Use LS_AGE macro. + +1999-08-30 Alex Zinin + + * ospfd.c + fix a bug with area range config write + added "show ip ospf" command, it will be enhanced later on + +1999-08-30 Alex Zinin + + * ospf_lsa.c + updated ospf_router_lsa() to honor flags (B-bit) + +1999-08-30 Alex Zinin + + * ospf_abr.c + wrote major functions implementing ABR activity + +1999-08-30 Alex Zinin + + * ospf_ia.c ospf_route.c ospf_route.h + fixed the bug with ospf_route.origin field. + Now it holds pointer to lsa_header + +1999-08-30 Alex Zinin + + * ospf_flood.c ospf_flood.h: + transformed ospf_flood_if_select into ospf_flood_through_area() + added new ospf_flood_if_select() and ospf_flood_through_as() + +1999-08-30 Toshiaki Takada + + * ospf_flood.[ch]: New file added. + + * ospf_packet.c (ospf_lsa_flooding), + (ospf_lsa_flooding_select_if): functions move to ospf_flood.c + + * ospf_neighbor.c (ospf_put_lsa_on_retransm_list), + (ospf_remove_lsa_from_retransm_list), + (ospf_nbr_remove_all_lsas_from_retransm_list), + (ospf_lsa_remove_from_ls_retransmit): + (ospf_lsa_retransmit): functions move to + ospf_flood.c, and change function's name: + + ospf_put_lsa_on_retransm_list () + -> ospf_ls_retransmit_add () + ospf_remove_lsa_from_retransm_list () + -> ospf_ls_retransmit_delete () + ospf_nbr_remove_all_lsas_from_retransm_list () + -> ospf_ls_retransmit_clear () + ospf_lsa_remove_from_ls_retransmit () + -> ospf_ls_retransmit_delete_nbr_all () + ospf_lsa_retransmit () + -> ospf_ls_retransmit_add_nbr_all () + + * ospf_lsa.c (ospf_lsa_lookup_from_list): function move to + ospf_flood.c, and change name to ospf_ls_retransmit_lookup (). + +1999-08-30 Kunihiro Ishiguro + + * ospf_neighbor.c (ospf_nbr_lookup_by_addr): Use + route_node_lookup() instead of route_node_get(). + + * ospf_packet.c (ospf_ls_upd): Temporary comment out (6) check. + +1999-08-30 Kunihiro Ishiguro + + * ospf_route.c (ospf_lookup_int_by_prefix): Add check of + oi->address. + +1999-08-29 Alex Zinin + * ospf_lsa.c + MaxAge LSA deletion functions added. + +1999-08-29 Alex Zinin + * ospf_neighbor.c + ospf_nbr_lookup_by_addr(): added route_unlock_node() + when function returns NULL if (rn->info == NULL) + +1999-08-29 Alex Zinin + * ospfd.c + added a hack for area range deletion + +1999-08-29 Alex Zinin + * ospf_lsa.h + included lsdb field into struct ospf_lsa, to find + LSDB easier when removing MaxAge LSAs. + +1999-08-29 Alex Zinin + * ospf_lsa.c ospf_neighbor.c ospf_nsm.c + ospf_packet.c changed to honor new retransmit list + management functions + +1999-08-29 Alex Zinin + * ospf_neighbor.c , .h added new retransmit list functions. + +1999-08-29 Alex Zinin + * Makefile.in + added ospf_ase, ospf_abr, ospf_ia + +1999-08-29 Alex Zinin + * ospf_spf.c: + - changed ospf_next_hop_calculation() to include interface + and nexthop addr for directly connected routers---more informative + and solves problem with route installation into the kernel + - changed ospf_nexthop_out_if_addr() to support routers, not only + transit networks + - added ospf_process_stubs(); + +1999-08-29 Alex Zinin + * ospf_lsa.c: + - changed ospf_router_lsa() to provide correct links + for p-t-p interfaces; + - changed ospf_summary_lsa_install() to support table + of self-originated summary-LSAs; + - added ospf_summary_asbr_lsa_install() and ospf_external_lsa_install() + - changed ospf_lsa_install() accordingly + - changed show_ip_ospf_database_router_links() to support p-t-p + +1999-08-29 Kunihiro Ishiguro + + * ospf_packet.c (ospf_make_db_desc): Only master can clear more + flag. + +1999-08-29 Kunihiro Ishiguro + + * ospf_packet.c (ospf_read): Add check of IP src address. + +1999-08-28 Alex Zinin + * ospf_neighbor.h + added ospf_nbr_lookup_by_routerid() + +1999-08-28 Alex Zinin + * ospfd.h + added ABR/ASBR flag definitions and fields; + added iflist field to area structure; + summary_lsa_self and summary_lsa_asbr_self are changed + to be route tables; + added ranges field---configured area ranges; + A separate Routers RT added; + area range config commands and config write added + + +1999-08-28 Alex Zinin + * ospf_route.c : + ospf_route_free()--added code to free the list of paths; + The following functions added: + ospf_intra_add_router(); + ospf_intra_add_transit(); + ospf_intra_add_stub(); + the last function uses new ospf_int_lookup_by_prefix(); + show_ip_ospf_route_cmd()--changed to support new RT structure; + added ospf_cmp_routes()--general route comparision function; + added ospf_route_copy_nexthops() and ospf_route_copy_nexthops_from_vertex() + they are used in ASE and IA routing; + added ospf_subst_route() and ospf_add_route(); + +1999-08-28 Alex Zinin + * ospf_route.h : + changed struct ospf_path to include output interface, + changed struct ospf_route to support IA and ASE routing. + added prototypes of the function used in IA and ASE modules. + +1999-08-28 Alex Zinin + * ospf_lsa.h ospf_lsa.c : + added ospf_my_lsa(), an interface independent version of + ospf_lsa_is_self_originated(), it will be used in ASE and IA-routing. + +1999-08-27 Kunihiro Ishiguro + + * ospf_interface.c (interface_config_write): Add check for + oi->nbr_self. + +1999-08-25 Toshiaki Takada + + * ospf_lsa.c (ospf_lsa_dup): New function added. + + * ospf_packet.c (ospf_write), (ospf_read): Print send/recv + interface in debug message. + +1999-08-25 Toshiaki Takada + + * ospf_packet.c (ospf_ls_ack_send): The name is changed from + `ospf_ls_ack_send'. + (ospf_ls_ack_send_delayed) (ospf_ls_ack_timer): New function added. + Delayed Link State Acknowledgment is scheduled by timer. + +1999-08-25 Alex Zinin + + * ospf_lsa.c (ospf_router_lsa): Incorrectly included link to + a stub network instead of link to a transit network into + originated router-LSA, bug fixed. + +1999-08-24 Toshiaki Takada + + * ospfd.c (ospf_update_router_id): New function added. + + * ospf_network.c (ospf_write): Create new socket per transmission. + And select outgoing interface whether dst is unicast or multicast. + + * ospf_packet.c: LSA flooding will work. + +1999-08-24 VOP + + * ospf_route.c: Include "sockunion.h" + +1999-08-24 Kunihiro Ishiguro + + * ospf_network.c (ospf_serv_sock_init): Enclose + IPTOS_PREC_INTERNETCONTROL setting with #ifdef for OS which does + not have the definition. + +1999-08-23 Toshiaki Takada + + * ospf_packet.c: Fix bug of DD processing. + +1999-08-18 Toshiaki Takada + + * ospf_lsa.c (show_ip_ospf_database): Show actual `LS age'. + +1999-08-17 Toshiaki Takada + + * ospf_lsa.h (OSPF_MAX_LSA): The value of OSPF_MAX_LSA is + corrected. The bug of `mes_lookup' is fixed. + This had been reported by Poul-Henning Kamp . + + * ospf_lsa.c (ospf_router_lsa_install): The name is changed from + `ospf_add_router_lsa'. + (ospf_network_lsa_install): The name is changed from + `ospf_add_network_lsa'. + + * ospf_interface.h (ospf_interface): Add member `nbr_self'. + + * ospf_interface.c (ospf_if_is_enable): New function added. + +1999-08-16 Toshiaki Takada + + * ospf_lsa.h (struct lsa_header): The name is changed from + `struct ospf_lsa'. + (struct ospf_lsa): New struct added to control each LSA's aging + and timers. + + * ospf_lsa.c (ospf_lsa_data_free): The name is change from + `ospf_lsa_free'. + (ospf_lsa_data_new), (ospf_lsa_new), (ospf_lsa_free), + (ospf_lsa_different), (ospf_lsa_install): New function added. + + * ospf_packet.c (ospf_ls_upd_list_lsa): New function added. + +1999-08-12 Toshiaki Takada + + * ospf_nsm.c (nsm_reset_nbr): New function added. + KillNbr and LLDown neighbor event call this function. + +1999-08-10 Toshiaki Takada + + * ospf_packet.c (ospf_ls_retransmit) + (ospf_ls_upd_timer): New function added. + Set retransmission timer for Link State Update. + +1999-07-29 Toshiaki Takada + + * ospf_ism.c (ospf_dr_election): Fix bug of DR election. + +1999-07-28 Toshiaki Takada + + * ospf_network.c (ospf_serv_sock_init): Set IP precedence field + with IPTOS_PREC_INTERNET_CONTROL. + + * ospf_nsm.c (nsm_change_status): Schedule NeighborChange event + if NSM status change. + + * ospf_packet.c (ospf_make_hello): Never include a neighbor in + Hello packet, when the neighbor goes down. + +1999-07-26 Kunihiro Ishiguro + + * Makefile.am (noinst_HEADERS): Add ospf_route.h. + + * ospf_route.c (show_ip_ospf_route): Add `show ip ospf route' + command. + +1999-07-25 Toshiaki Takada + + * ospf_lsa.c (ospf_router_lsa): Fix bug of LS sequence number + assignement. + +1999-07-25 Kunihiro Ishiguro + + * ospf_route.c (ospf_route_table_free): New function added. + + * ospf_spf.c (ospf_spf_next): Free vertex w when cw's and w's + distance is same. + + * ospfd.h (struct ospf): Add old_table. + + * ospf_main.c (sighup): Call of log_rotate () removed. + + * ospf_lsa.c (ospf_lsa_is_self_originated): Fix bug of checking + area->lsa as self LSA. This should be area->lsa_self. + +1999-07-24 Kunihiro Ishiguro + + * ospf_zebra.c (ospf_zebra_add): ospf_zebra_add + (),ospf_zebra_delete () added. + + * ospf_spf.c (ospf_spf_calculate): Call ospf_intra_route_add (). + +1999-07-24 Toshiaki Takada + + * ospf_lsa.c: Change LS sequence number treatment. + (ospf_lsa_is_self_originated): New function added. + (show_ip_ospf_database_self_originated): New DEFUN added. + +1999-07-23 Kunihiro Ishiguro + + * ospf_interface.c (ospf_if_lookup_by_addr): Add loopback check. + +1999-07-22 Toshiaki Takada + + * ospf_spf.c (ospf_nexthop_new), (ospf_nexthop_free), + (ospf_nexthop_dup): function added. + (ospf_nexthop_calculation): function changed. + + * ospf_interface.c (ospf_if_lookup_by_addr): function added. + +1999-07-21 Toshiaki Takada + + * ospf_spf.c (ospf_spf_closest_vertex): function removed. + +1999-07-21 Kunihiro Ishiguro + + * ospf_spf.c (ospf_spf_next): Apply ntohs for fetching metric. + +1999-07-21 Toshiaki Takada + + * ospf_neighbor.c (ospf_nbr_lookup_by_router_id): fundtion removed. + + * ospf_lsa.c (show_ip_ospf_database_router): describe each + connected link. + +1999-07-21 Kunihiro Ishiguro + + * ospf_spf.c (ospf_spf_next): V is router LSA or network LSA so + change behavior according to LSA type. + (ospf_lsa_has_link): Link check function is added. + +1999-07-20 Kunihiro Ishiguro + + * ospf_spf.c (ospf_spf_calculate_schedule): Add new function for + SPF calcultion schedule addtition. + (ospf_spf_calculate_timer_add): Rough 30 sec interval SPF calc + timer is added. + (ospf_spf_next_router): Delete ospf_spf_next_network (). + + * ospf_lsa.c (show_ip_ospf_database_all): Network-LSA display + header typo correction. Display of router LSA's #link added. + +1999-07-19 Toshiaki Takada + + * ospf_packet.c (ospf_check_network_mask): Added new function for + receiving Raw IP packet on an appropriate interface. + +1999-07-16 Toshiaki Takada + + * ospfd.c (ospf_router_id): new DEFUN added. + +1999-07-15 Toshiaki Takada + + * ospf_spf.c (ospf_spf_init), (ospf_spf_free), + (ospf_spf_has_vertex), (ospf_vertex_lookup), + (ospf_spf_next_router), (ospf_spf_next_network), + (ospf_spf_closest_vertex), (ospf_spf_calculate): + function added. + +1999-07-13 Toshiaki Takada + + * ospf_ism.c: fix bug of DR Election. + + * ospf_nsm.c: fix bug of adjacency forming. + +1999-07-05 Kunihiro Ishiguro + + * ospfd.c (ospf_init): Change to use install_default. + +1999-07-01 Rick Payne + + * ospf_zebra.c (zebra_init): Install standard commands to + ZEBRA_NODE. + +1999-06-30 Toshiaki Takada + + * ospf_dump.c: Whole debug command is improved. + (ISM|NSM) (events|status|timers) debug option added. + (show_debugging_ospf): new DEFUN added. + +1999-06-30 Kunihiro Ishiguro + + * ospf_lsa.c (ospf_lsa_lookup_from_list): Change !IPV4_ADDR_CMP to + IPV4_ADDR_SAME. + +1999-06-29 Toshiaki Takada + + * ospf_dump.c (ospf_summary_lsa_dump): Add summary-LSA dump routine. + (ospf_as_external_lsa_dump): Add AS-external-LSA dump routine. + + * ospf_nsm.c (nsm_twoway_received): fix condtion of adjacnet. + + * ospf_ism.c (ospf_dr_election): fix DR Election. + + * ospf_dump.c (ospf_nbr_state_message): fix `show ip ospf neighbor' + command's state. + +1999-06-29 Kunihiro Ishiguro + + * ospf_dump.c (ospf_router_lsa_dump): Add router-LSA dump routine. + +1999-06-28 Toshiaki Takada + + * ospf_lsa.c (show_ip_ospf_database_network): fix bug of + `show ip ospf database network' command output. + + * ospf_nsm.c (nsm_inactivity_timer): Clear list of Link State + Retransmission, Database Summary and Link State Request. + + * ospf_packet.c (ospf_ls_req_timer): New function added. + Set Link State Request retransmission timer. + +1999-06-27 Kunihiro Ishiguro + + * ospf_main.c (main): Change default output from ZLOG_SYSLOG to + ZLOG_STDOUT. + + * ospfd.c (ospf_init): Register show_ip_ospf_interface_cmd and + show_ip_ospf_neighbor_cmd to VIEW_NODE. + + * ospf_lsa.c (ospf_lsa_init): Register show_ip_ospf_database_cmd + and show_ip_ospf_database_type_cmd to VIEW_NODE. + +1999-06-25 Toshiaki Takada + + * ospf_packet.c: fix bug of DD making. + fix bug of LS-Update reading. + +1999-06-23 Toshiaki Takada + + * ospf_packet.c: All type of packets are changed to use + fifo queue structure. + (ospf_fill_header) function added. + +1999-06-22 Toshiaki Takada + + * ospf_packet.c (ospf_packet_new): New function added to handle + sending ospf packet by fifo queue structure. + (ospf_packet_free), (ospf_fifo_new), (ospf_fifo_push), + (ospf_fifo_pop), (ospf_fifo_head), (ospf_fifo_flush), + (ospf_fifo_free): Likewise. + +1999-06-21 Toshiaki Takada + + * ospf_nsm.c (ospf_db_desc_timer): function added. + (nsm_timer_set) function added. + * ospf_dump.c (ospf_option_dump): function added. + * ospf_packet.c (ospf_ls_req) (ospf_make_ls_req): function added. + +1999-06-20 Toshiaki Takada + + * ospf_lsa.c (ospf_lsa_more_recent): function added. + * ospf_neighbor.h (struct ospf_neighbor): Change member ms_flag + to dd_flags. + +1999-06-19 Toshiaki Takada + + * ospf_lsa.c: DEFUN (show_ip_ospf_database) Added. + * ospf_interface.c (if_ospf_cost), (if_ospf_dead_interval), + (if_ospf_hello_interval), (if_ospf_priority), + (if_ospf_retransmit_interval), (if_ospf_transmit_delay) + argument changed from NUMBER to . + DEFUN (if_ospf_network_broadcast), + DEFUN (if_ospf_network_non_broadcast), + DEFUN (if_ospf_network_point_to_multipoint), + DEFUN (if_ospf_network_point_to_point) functions are combined to + DEFUN (if_ospf_network). + +1999-06-18 Toshiaki Takada + + * ospf_lsa.c: ospf_add_router_lsa (), ospf_add_network_lsa (), + ospf_lsa_lookup (), ospf_lsa_count () Added. + +1999-06-15 Toshiaki Takada + + * DEFUN (ospf_debug_ism), DEFUN (ospf_debug_nsm), + DEFUN (no_ospf_debug_ism), DEFUN (no_ospf_debug_nsm) Added. + `debug ospf ism' command shows debug message. + `debuf ospf nsm' command shows debug message. + +1999-06-14 Toshiaki Takada + + * ospf_lsa.c: ospf_network_lsa () Added. + ospf_lsa_checksum () Added. + * DEFUN (ospf_debug_packet), DEFUN (no_ospf_debug_packet) Added. + `debug ospf packet' command shows debug message. + +1999-06-13 Toshiaki Takada + + * ospf_packet.h: Remove struct ospf_ls_req {}, ospf_ls_upd {}, + ospf_ls_ack {}. + +1999-06-11 Toshiaki Takada + + * ospf_dump.c: fix IP packet length treatment. + +1999-06-10 Toshiaki Takada + + * ospf_ism.h: Add OSPF_ISM_EVENT_EXECUTE() Macro Added. + * ospf_nsm.h: Add OSPF_NSM_EVENT_EXECUTE() Macro Added. + + * ospf_packet.c: ospf_db_desc (), ospf_db_desc_send () Added. + ospf_make_hello (), ospf_make_db_desc () Added. + ospf_db_desc_proc () Added.n + + * Database Description packet can be processed. + +1999-06-08 Toshiaki Takada + + * ospf_lsa.c: New file. + +1999-06-07 Toshiaki Takada + + * ospf_neighbor.c: ospf_fully_adjacent_count () Added. + +1999-06-07 Kunihiro Ishiguro + + * ospf_spf.[ch]: New file. + +1999-05-30 Kunihiro Ishiguro + + * ospf_zebra.c: Changed to use lib/zclient.c routines. + + * ospf_zebra.h (zebra_start): Remove struct zebra. + +1999-05-29 Kunihiro Ishiguro + + * ospfd.c (ospf_config_write): Add cast (unsigned long int) to + ntohl for sprintf warning. + +1999-05-19 Toshiaki Takada + + * ospf_ism.c (ospf_dr_election): Join AllDRouters Multicast group + if interface state changes to DR or BDR. + +1999-05-14 Stephen R. van den Berg + + * ospf_main.c (signal_init): SIGTERM call sigint. + (sigint): Logging more better message. + +1999-05-12 Toshiaki Takada + + * ospfd.c: Fix bug of `no router ospf' statement, it will work. + +1999-05-11 Toshiaki Takada + + * ospf_neighbor.c: ospf_nbr_free () Added. + +1999-05-10 Toshiaki Takada + + * ospfd.h: struct ospf_area { }, struct ospf_network { } Changed. + * Fix bug of `no network' statement, it will work. + +1999-05-07 Toshiaki Takada + + * ospf_interface.c, ospf_zebra.c: Fix bug of last interface is not + updated by ospf_if_update (). + +1999-04-30 Kunihiro Ishiguro + + * Makefile.am (noinst_HEADERS): Add ospf_lsa.h for distribution. + +1999-04-25 Toshiaki Takada + + * ospf_interface.c: DEFUN (no_if_ospf_cost), + DEFUN (no_if_ospf_dead_interval), + DEFUN (no_if_ospf_hello_interval), + DEFUN (no_if_ospf_priority), + DEFUN (no_if_ospf_retransmit_interval), + DEFUN (no_if_ospf_transmit_delay) Added. + + interface_config_write () suppress showing interface + default values. + +1999-04-25 Kunihiro Ishiguro + + * ospf_dump.c (ospf_timer_dump): If thread is NULL return "inactive". + + * ospfd.c (ospf_if_update): Fix bug of using ospf_area { } instead + of ospf_network { }. So `router ospf' statement in ospfd.conf + works again. + (ospf_if_update): Call ospf_get_router_id for updating router ID. + +1999-04-25 Toshiaki Takada + + * ospf_interface.c: DEFUN (if_ospf_network) deleted. + DEFUN (if_ospf_network_broadcast), + DEFUN (if_ospf_network_non_broadcast), + DEFUN (if_ospf_network_point_to_multipoint), + DEFUN (if_ospf_network_point_to_point), + DEFUN (no_if_ospf_network) Added. + +1999-04-23 Toshiaki Takada + + * ospfd.h: struct area { } changed to struct ospf_network { }. + Add struct ospf_area { }. + * ospfd.c: Add ospf_area_lookup_by_area_id (), ospf_network_new (), + and ospf_network_free (). + DEFUN (area_authentication), DEFUN (no_area_authentication) Added. + +1999-04-22 Toshiaki Takada + + * ospf_lsa.h: New file. + * ospf_packet.h: LSA related struct definition are moved to + ospf_lsa.h. + * ospf_packet.c: ospf_verify_header () Added. + +1999-04-21 Toshiaki Takada + + * ospf_ism.c: ospf_elect_dr () and related function is changed. + DR Election bug fixed. + * ospf_dump.c: ospf_nbr_state_message (), ospf_timer_dump () Added. + * ospfd.c: DEFUN (show_ip_ospf_neighbor) Added. + +1999-04-19 Kunihiro Ishiguro + + * ospf_main.c (main): access_list_init () is added for vty + connection filtering. + +1999-04-16 Toshiaki Takada + + * ospfd.c: DEFUN (show_ip_ospf_interface) Added. + * ospf_neighbor.c: ospf_nbr_count () Added. + +1999-04-15 Toshiaki Takada + + * ospfd.h: struct ospf { } Changed. + * ospfd.c: ospf_lookup_by_process_id () Deleted. + * ospf_ism.c: ospf_wait_timer () Added. WaitTimer will work. + +1999-04-14 Toshiaki Takada + + * ospf_ism.c: ospf_elect_dr () Added. + * ospf_network.c: ospf_if_ipmulticast () Added. + +1999-04-11 Toshiaki Takada + + * ospf_interface.c: interface_config_write (), + DEFUN (if_ip_ospf_cost), + DEFUN (if_ip_ospf_dead_interval), + DEFUN (if_ip_ospf_hello_interval), + DEFUN (if_ip_ospf_priority), + DEFUN (if_ip_ospf_retransmit_interval) and + DEFUN (if_ip_ospf_transmit_delay) Added. + +1999-04-08 Toshiaki Takada + + * ospf_dump.c: ospf_packet_db_desc_dump () Added. + * ospf_neighbor.c: ospf_nbr_bidirectional () Added. + * ospf_nsm.c: nsm_twoway_received () Added. + +1999-04-02 Toshiaki Takada + + * ospf_neighbor.c: New file. + * ospf_neighbor.h: New file. + * ospf_nsm.c: New file. + * ospf_nsm.h: New file. + * ospf_packet.c: Add ospf_make_header (), ospf_hello () and + ospf_hello_send (). Now OSPFd can receive Hello and send Hello. + +1999-03-27 Kunihiro Ishiguro + + * ospf_packet.c: Add ospf_recv_packet (). Now OSPF Hello can receive. + +1999-03-19 Toshiaki Takada + + * ospf_packet.c: New file. + * ospf_packet.h: New file. + * ospf_network.c: New file. + * ospf_network.h: New file. + * ospfd.h: move OSPF message structure has moved to ospf_packet.h. + +1999-03-17 Kunihiro Ishiguro + + * ospf_zebra.c (ospf_zebra_get_interface): Fix for IPv6 interface + address. + + * Makefile.am (install-sysconfDATA): Overwrite install-sysconfDATA + for install ospfd.conf.sample as owner read only file. + + * ospf_main.c (usage): Change to use ZEBRA_BUG_ADDRESS. + +1999-03-15 Toshiaki Takada + + * ospf_ism.c: New file. + * ospf_ism.h: New file. + * ospf_dump.c: New file. + * ospf_dump.h: New file. + + * ospfd.h: Add (struct ospf), (struct config_network), + (struct message) structure. + + * ospf_interface.c: Add ospf_if_match_network (). + * ospf_interface.h (struct ospf_interface): Change struct members. + + * ospfd.c: ospf_lookup_by_process_id (), ospf_network_new (), + DEFUN (network_area): Added. + + * ospfd.conf.sample: Change sample configuration. + +1999-03-05 Toshiaki Takada + + * ospf_interface.c: New file. + * ospf_interface.h: New file. + * ospf_zebra.h: New file. + * ospf_zebra.c: Add interface function for zebra daemon. + * ospfd.c: New file. + +1999-02-23 Kunihiro Ishiguro + + * Move IPv6 codes and files to ospf6d directory. + +1999-02-18 Peter Galbavy + + * syslog support added + +1998-12-22 Toshiaki Takada + + * ospfd.h: New file. + * ospf_lsa.h: New file. + +1998-12-15 Kunihiro Ishiguro + + * Makefile.am: New file. + * ospf_main.c: New file. + diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am new file mode 100644 index 00000000..1ced11cc --- /dev/null +++ b/ospfd/Makefile.am @@ -0,0 +1,44 @@ +## Process this file with automake to produce Makefile.in. + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 + +noinst_LIBRARIES = libospf.a +sbin_PROGRAMS = ospfd + +libospf_a_SOURCES = \ + ospfd.c ospf_zebra.c ospf_interface.c ospf_ism.c ospf_neighbor.c \ + ospf_nsm.c ospf_dump.c ospf_network.c ospf_packet.c ospf_lsa.c \ + ospf_spf.c ospf_route.c ospf_ase.c ospf_abr.c ospf_ia.c ospf_flood.c \ + ospf_lsdb.c ospf_asbr.c ospf_routemap.c ospf_snmp.c \ + ospf_opaque.c ospf_te.c ospf_vty.c + +noinst_HEADERS = \ + ospf_dump.h ospf_interface.h ospf_ism.h ospf_neighbor.h \ + ospf_network.h ospf_nsm.h ospf_packet.h ospf_zebra.h ospfd.h \ + ospf_lsa.h ospf_spf.h ospf_route.h ospf_ase.h ospf_abr.h ospf_ia.h \ + ospf_flood.h ospf_lsdb.h ospf_asbr.h ospf_snmp.h ospf_opaque.h \ + ospf_te.h ospf_vty.h + +ospfd_SOURCES = \ + ospf_main.c $(libospf_a_SOURCES) + +ospfd_LDADD = ../lib/libzebra.a + +sysconf_DATA = ospfd.conf.sample + +EXTRA_DIST = $(sysconf_DATA) OSPF-MIB.txt OSPF-TRAP-MIB.txt + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done diff --git a/ospfd/Makefile.in b/ospfd/Makefile.in new file mode 100644 index 00000000..8472535e --- /dev/null +++ b/ospfd/Makefile.in @@ -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 index 00000000..de7d03f5 --- /dev/null +++ b/ospfd/OSPF-MIB.txt @@ -0,0 +1,2723 @@ +OSPF-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, Counter32, Gauge32, + Integer32, IpAddress + FROM SNMPv2-SMI + TEXTUAL-CONVENTION, TruthValue, RowStatus + FROM SNMPv2-TC + MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF + mib-2 FROM RFC1213-MIB; + +-- This MIB module uses the extended OBJECT-TYPE macro as +-- defined in [9]. + +ospf MODULE-IDENTITY + LAST-UPDATED "9501201225Z" -- Fri Jan 20 12:25:50 PST 1995 + ORGANIZATION "IETF OSPF Working Group" + CONTACT-INFO + " Fred Baker + Postal: Cisco Systems + 519 Lado Drive + Santa Barbara, California 93111 + Tel: +1 805 681 0115 + E-Mail: fred@cisco.com + + Rob Coltun + Postal: RainbowBridge Communications + Tel: (301) 340-9416 + E-Mail: rcoltun@rainbow-bridge.com" + DESCRIPTION + "The MIB module to describe the OSPF Version 2 + Protocol" + ::= { mib-2 14 } + +-- The Area ID, in OSPF, has the same format as an IP Address, +-- but has the function of defining a summarization point for +-- Link State Advertisements + +AreaID ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "An OSPF Area Identifier." + SYNTAX IpAddress + + +-- The Router ID, in OSPF, has the same format as an IP Address, +-- but identifies the router independent of its IP Address. + +RouterID ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "A OSPF Router Identifier." + SYNTAX IpAddress + + +-- The OSPF Metric is defined as an unsigned value in the range + +Metric ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The OSPF Internal Metric." + SYNTAX Integer32 (0..'FFFF'h) + +BigMetric ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The OSPF External Metric." + SYNTAX Integer32 (0..'FFFFFF'h) + +-- Status Values + +Status ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The status of an interface: 'enabled' indicates that + it is willing to communicate with other OSPF Routers, + while 'disabled' indicates that it is not." + SYNTAX INTEGER { enabled (1), disabled (2) } + +-- Time Durations measured in seconds + +PositiveInteger ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "A positive integer. Values in excess are precluded as + unnecessary and prone to interoperability issues." + SYNTAX Integer32 (0..'7FFFFFFF'h) + +HelloRange ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The range of intervals on which hello messages are + exchanged." + SYNTAX Integer32 (1..'FFFF'h) + +UpToMaxAge ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The values that one might find or configure for + variables bounded by the maximum age of an LSA." + SYNTAX Integer32 (0..3600) + + +-- The range of ifIndex + +InterfaceIndex ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The range of ifIndex." + SYNTAX Integer32 + + +-- Potential Priorities for the Designated Router Election + +DesignatedRouterPriority ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The values defined for the priority of a system for + becoming the designated router." + SYNTAX Integer32 (0..'FF'h) + +TOSType ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Type of Service is defined as a mapping to the IP Type of + Service Flags as defined in the IP Forwarding Table MIB + + +-----+-----+-----+-----+-----+-----+-----+-----+ + | | | | + | PRECEDENCE | TYPE OF SERVICE | 0 | + | | | | + +-----+-----+-----+-----+-----+-----+-----+-----+ + + IP TOS IP TOS + Field Policy Field Policy + + Contents Code Contents Code + 0 0 0 0 ==> 0 0 0 0 1 ==> 2 + 0 0 1 0 ==> 4 0 0 1 1 ==> 6 + 0 1 0 0 ==> 8 0 1 0 1 ==> 10 + 0 1 1 0 ==> 12 0 1 1 1 ==> 14 + 1 0 0 0 ==> 16 1 0 0 1 ==> 18 + 1 0 1 0 ==> 20 1 0 1 1 ==> 22 + 1 1 0 0 ==> 24 1 1 0 1 ==> 26 + 1 1 1 0 ==> 28 1 1 1 1 ==> 30 + + The remaining values are left for future definition." + SYNTAX Integer32 (0..30) + + +-- OSPF General Variables + +-- These parameters apply globally to the Router's +-- OSPF Process. + +ospfGeneralGroup OBJECT IDENTIFIER ::= { ospf 1 } + + + ospfRouterId OBJECT-TYPE + SYNTAX RouterID + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "A 32-bit integer uniquely identifying the + router in the Autonomous System. + + By convention, to ensure uniqueness, this + should default to the value of one of the + router's IP interface addresses." + REFERENCE + "OSPF Version 2, C.1 Global parameters" + ::= { ospfGeneralGroup 1 } + + + ospfAdminStat OBJECT-TYPE + SYNTAX Status + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The administrative status of OSPF in the + router. The value 'enabled' denotes that the + OSPF Process is active on at least one inter- + face; 'disabled' disables it on all inter- + faces." + ::= { ospfGeneralGroup 2 } + + ospfVersionNumber OBJECT-TYPE + SYNTAX INTEGER { version2 (2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The current version number of the OSPF proto- + col is 2." + REFERENCE + "OSPF Version 2, Title" + ::= { ospfGeneralGroup 3 } + + + ospfAreaBdrRtrStatus OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A flag to note whether this router is an area + border router." + REFERENCE + "OSPF Version 2, Section 3 Splitting the AS into + Areas" + ::= { ospfGeneralGroup 4 } + + + ospfASBdrRtrStatus OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "A flag to note whether this router is config- + ured as an Autonomous System border router." + REFERENCE + "OSPF Version 2, Section 3.3 Classification of + routers" + ::= { ospfGeneralGroup 5 } + + ospfExternLsaCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of external (LS type 5) link-state + advertisements in the link-state database." + REFERENCE + "OSPF Version 2, Appendix A.4.5 AS external link + advertisements" + ::= { ospfGeneralGroup 6 } + + + ospfExternLsaCksumSum OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32-bit unsigned sum of the LS checksums of + the external link-state advertisements con- + tained in the link-state database. This sum + can be used to determine if there has been a + change in a router's link state database, and + to compare the link-state database of two + routers." + ::= { ospfGeneralGroup 7 } + + + ospfTOSSupport OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The router's support for type-of-service rout- + ing." + REFERENCE + "OSPF Version 2, Appendix F.1.2 Optional TOS + support" + ::= { ospfGeneralGroup 8 } + + ospfOriginateNewLsas OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of new link-state advertisements + that have been originated. This number is in- + cremented each time the router originates a new + LSA." + ::= { ospfGeneralGroup 9 } + + + ospfRxNewLsas OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of link-state advertisements re- + ceived determined to be new instantiations. + This number does not include newer instantia- + tions of self-originated link-state advertise- + ments." + ::= { ospfGeneralGroup 10 } + + ospfExtLsdbLimit OBJECT-TYPE + SYNTAX Integer32 (-1..'7FFFFFFF'h) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The maximum number of non-default AS- + external-LSAs entries that can be stored in the + link-state database. If the value is -1, then + there is no limit. + + When the number of non-default AS-external-LSAs + in a router's link-state database reaches + ospfExtLsdbLimit, the router enters Overflow- + State. The router never holds more than + ospfExtLsdbLimit non-default AS-external-LSAs + in its database. OspfExtLsdbLimit MUST be set + identically in all routers attached to the OSPF + backbone and/or any regular OSPF area. (i.e., + OSPF stub areas and NSSAs are excluded)." + DEFVAL { -1 } + ::= { ospfGeneralGroup 11 } + + ospfMulticastExtensions OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "A Bit Mask indicating whether the router is + forwarding IP multicast (Class D) datagrams + based on the algorithms defined in the Multi- + cast Extensions to OSPF. + + Bit 0, if set, indicates that the router can + forward IP multicast datagrams in the router's + directly attached areas (called intra-area mul- + ticast routing). + + Bit 1, if set, indicates that the router can + forward IP multicast datagrams between OSPF + areas (called inter-area multicast routing). + + Bit 2, if set, indicates that the router can + forward IP multicast datagrams between Auto- + nomous Systems (called inter-AS multicast rout- + ing). + + Only certain combinations of bit settings are + allowed, namely: 0 (no multicast forwarding is + enabled), 1 (intra-area multicasting only), 3 + (intra-area and inter-area multicasting), 5 + (intra-area and inter-AS multicasting) and 7 + (multicasting everywhere). By default, no mul- + ticast forwarding is enabled." + DEFVAL { 0 } + ::= { ospfGeneralGroup 12 } + + ospfExitOverflowInterval OBJECT-TYPE + SYNTAX PositiveInteger + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The number of seconds that, after entering + OverflowState, a router will attempt to leave + OverflowState. This allows the router to again + originate non-default AS-external-LSAs. When + set to 0, the router will not leave Overflow- + State until restarted." + DEFVAL { 0 } + ::= { ospfGeneralGroup 13 } + + + ospfDemandExtensions OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The router's support for demand routing." + REFERENCE + "OSPF Version 2, Appendix on Demand Routing" + ::= { ospfGeneralGroup 14 } + + +-- The OSPF Area Data Structure contains information +-- regarding the various areas. The interfaces and +-- virtual links are configured as part of these areas. +-- Area 0.0.0.0, by definition, is the Backbone Area + + + ospfAreaTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfAreaEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information describing the configured parame- + ters and cumulative statistics of the router's + attached areas." + REFERENCE + "OSPF Version 2, Section 6 The Area Data Struc- + ture" + ::= { ospf 2 } + + + ospfAreaEntry OBJECT-TYPE + SYNTAX OspfAreaEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information describing the configured parame- + ters and cumulative statistics of one of the + router's attached areas." + INDEX { ospfAreaId } + ::= { ospfAreaTable 1 } + +OspfAreaEntry ::= + SEQUENCE { + ospfAreaId + AreaID, + ospfAuthType + Integer32, + ospfImportAsExtern + INTEGER, + ospfSpfRuns + Counter32, + ospfAreaBdrRtrCount + Gauge32, + ospfAsBdrRtrCount + Gauge32, + ospfAreaLsaCount + Gauge32, + ospfAreaLsaCksumSum + Integer32, + ospfAreaSummary + INTEGER, + ospfAreaStatus + RowStatus + } + + ospfAreaId OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A 32-bit integer uniquely identifying an area. + Area ID 0.0.0.0 is used for the OSPF backbone." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaEntry 1 } + + + ospfAuthType OBJECT-TYPE + SYNTAX Integer32 + -- none (0), + -- simplePassword (1) + -- md5 (2) + -- reserved for specification by IANA (> 2) + MAX-ACCESS read-create + STATUS obsolete + DESCRIPTION + "The authentication type specified for an area. + Additional authentication types may be assigned + locally on a per Area basis." + REFERENCE + "OSPF Version 2, Appendix E Authentication" + DEFVAL { 0 } -- no authentication, by default + ::= { ospfAreaEntry 2 } + + ospfImportAsExtern OBJECT-TYPE + SYNTAX INTEGER { + importExternal (1), + importNoExternal (2), + importNssa (3) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The area's support for importing AS external + link- state advertisements." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + DEFVAL { importExternal } + ::= { ospfAreaEntry 3 } + + + ospfSpfRuns OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times that the intra-area route + table has been calculated using this area's + link-state database. This is typically done + using Dijkstra's algorithm." + ::= { ospfAreaEntry 4 } + + + ospfAreaBdrRtrCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of area border routers reach- + able within this area. This is initially zero, + and is calculated in each SPF Pass." + ::= { ospfAreaEntry 5 } + + ospfAsBdrRtrCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of Autonomous System border + routers reachable within this area. This is + initially zero, and is calculated in each SPF + Pass." + ::= { ospfAreaEntry 6 } + + + ospfAreaLsaCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of link-state advertisements + in this area's link-state database, excluding + AS External LSA's." + ::= { ospfAreaEntry 7 } + + + ospfAreaLsaCksumSum OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32-bit unsigned sum of the link-state ad- + vertisements' LS checksums contained in this + area's link-state database. This sum excludes + external (LS type 5) link-state advertisements. + The sum can be used to determine if there has + been a change in a router's link state data- + base, and to compare the link-state database of + two routers." + DEFVAL { 0 } + ::= { ospfAreaEntry 8 } + + ospfAreaSummary OBJECT-TYPE + SYNTAX INTEGER { + noAreaSummary (1), + sendAreaSummary (2) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The variable ospfAreaSummary controls the im- + port of summary LSAs into stub areas. It has + no effect on other areas. + + If it is noAreaSummary, the router will neither + originate nor propagate summary LSAs into the + stub area. It will rely entirely on its de- + fault route. + + If it is sendAreaSummary, the router will both + summarize and propagate summary LSAs." + DEFVAL { noAreaSummary } + ::= { ospfAreaEntry 9 } + + + ospfAreaStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfAreaEntry 10 } + + +-- OSPF Area Default Metric Table + +-- The OSPF Area Default Metric Table describes the metrics +-- that a default Area Border Router will advertise into a +-- Stub area. + + + ospfStubAreaTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfStubAreaEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The set of metrics that will be advertised by + a default Area Border Router into a stub area." + REFERENCE + "OSPF Version 2, Appendix C.2, Area Parameters" + ::= { ospf 3 } + + + ospfStubAreaEntry OBJECT-TYPE + SYNTAX OspfStubAreaEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The metric for a given Type of Service that + will be advertised by a default Area Border + Router into a stub area." + REFERENCE + "OSPF Version 2, Appendix C.2, Area Parameters" + INDEX { ospfStubAreaId, ospfStubTOS } + ::= { ospfStubAreaTable 1 } + +OspfStubAreaEntry ::= + SEQUENCE { + ospfStubAreaId + AreaID, + ospfStubTOS + TOSType, + ospfStubMetric + BigMetric, + ospfStubStatus + RowStatus, + ospfStubMetricType + INTEGER + } + + ospfStubAreaId OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32 bit identifier for the Stub Area. On + creation, this can be derived from the in- + stance." + ::= { ospfStubAreaEntry 1 } + + + ospfStubTOS OBJECT-TYPE + SYNTAX TOSType + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Type of Service associated with the + metric. On creation, this can be derived from + the instance." + ::= { ospfStubAreaEntry 2 } + + + ospfStubMetric OBJECT-TYPE + SYNTAX BigMetric + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The metric value applied at the indicated type + of service. By default, this equals the least + metric at the type of service among the inter- + faces to other areas." + ::= { ospfStubAreaEntry 3 } + + + ospfStubStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfStubAreaEntry 4 } + + ospfStubMetricType OBJECT-TYPE + SYNTAX INTEGER { + ospfMetric (1), -- OSPF Metric + comparableCost (2), -- external type 1 + nonComparable (3) -- external type 2 + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the type of metric ad- + vertised as a default route." + DEFVAL { ospfMetric } + ::= { ospfStubAreaEntry 5 } + +-- OSPF Link State Database + +-- The Link State Database contains the Link State +-- Advertisements from throughout the areas that the +-- device is attached to. + + + ospfLsdbTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The OSPF Process's Link State Database." + REFERENCE + "OSPF Version 2, Section 12 Link State Adver- + tisements" + ::= { ospf 4 } + + + ospfLsdbEntry OBJECT-TYPE + SYNTAX OspfLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A single Link State Advertisement." + INDEX { ospfLsdbAreaId, ospfLsdbType, + ospfLsdbLsid, ospfLsdbRouterId } + ::= { ospfLsdbTable 1 } + +OspfLsdbEntry ::= + SEQUENCE { + ospfLsdbAreaId + AreaID, + ospfLsdbType + INTEGER, + ospfLsdbLsid + IpAddress, + ospfLsdbRouterId + RouterID, + ospfLsdbSequence + Integer32, + ospfLsdbAge + Integer32, + ospfLsdbChecksum + Integer32, + ospfLsdbAdvertisement + OCTET STRING + } + ospfLsdbAreaId OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32 bit identifier of the Area from which + the LSA was received." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfLsdbEntry 1 } + +-- External Link State Advertisements are permitted +-- for backward compatibility, but should be displayed in +-- the ospfExtLsdbTable rather than here. + + ospfLsdbType OBJECT-TYPE + SYNTAX INTEGER { + routerLink (1), + networkLink (2), + summaryLink (3), + asSummaryLink (4), + asExternalLink (5), -- but see ospfExtLsdbTable + multicastLink (6), + nssaExternalLink (7) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The type of the link state advertisement. + Each link state type has a separate advertise- + ment format." + REFERENCE + "OSPF Version 2, Appendix A.4.1 The Link State + Advertisement header" + ::= { ospfLsdbEntry 2 } + + ospfLsdbLsid OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Link State ID is an LS Type Specific field + containing either a Router ID or an IP Address; + it identifies the piece of the routing domain + that is being described by the advertisement." + REFERENCE + "OSPF Version 2, Section 12.1.4 Link State ID" + ::= { ospfLsdbEntry 3 } + ospfLsdbRouterId OBJECT-TYPE + SYNTAX RouterID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32 bit number that uniquely identifies the + originating router in the Autonomous System." + REFERENCE + "OSPF Version 2, Appendix C.1 Global parameters" + ::= { ospfLsdbEntry 4 } + +-- Note that the OSPF Sequence Number is a 32 bit signed +-- integer. It starts with the value '80000001'h, +-- or -'7FFFFFFF'h, and increments until '7FFFFFFF'h +-- Thus, a typical sequence number will be very negative. + + ospfLsdbSequence OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The sequence number field is a signed 32-bit + integer. It is used to detect old and dupli- + cate link state advertisements. The space of + sequence numbers is linearly ordered. The + larger the sequence number the more recent the + advertisement." + REFERENCE + "OSPF Version 2, Section 12.1.6 LS sequence + number" + ::= { ospfLsdbEntry 5 } + + + ospfLsdbAge OBJECT-TYPE + SYNTAX Integer32 -- Should be 0..MaxAge + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the age of the link state adver- + tisement in seconds." + REFERENCE + "OSPF Version 2, Section 12.1.1 LS age" + ::= { ospfLsdbEntry 6 } + + ospfLsdbChecksum OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the checksum of the complete + contents of the advertisement, excepting the + age field. The age field is excepted so that + an advertisement's age can be incremented + without updating the checksum. The checksum + used is the same that is used for ISO connec- + tionless datagrams; it is commonly referred to + as the Fletcher checksum." + REFERENCE + "OSPF Version 2, Section 12.1.7 LS checksum" + ::= { ospfLsdbEntry 7 } + + + ospfLsdbAdvertisement OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (1..65535)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The entire Link State Advertisement, including + its header." + REFERENCE + "OSPF Version 2, Section 12 Link State Adver- + tisements" + ::= { ospfLsdbEntry 8 } + + +-- Address Range Table + +-- The Address Range Table acts as an adjunct to the Area +-- Table; It describes those Address Range Summaries that +-- are configured to be propagated from an Area to reduce +-- the amount of information about it which is known beyond +-- its borders. + + ospfAreaRangeTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfAreaRangeEntry + MAX-ACCESS not-accessible + STATUS obsolete + DESCRIPTION + "A range if IP addresses specified by an IP + address/IP network mask pair. For example, + class B address range of X.X.X.X with a network + mask of 255.255.0.0 includes all IP addresses + from X.X.0.0 to X.X.255.255" + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospf 5 } + ospfAreaRangeEntry OBJECT-TYPE + SYNTAX OspfAreaRangeEntry + MAX-ACCESS not-accessible + STATUS obsolete + DESCRIPTION + "A range if IP addresses specified by an IP + address/IP network mask pair. For example, + class B address range of X.X.X.X with a network + mask of 255.255.0.0 includes all IP addresses + from X.X.0.0 to X.X.255.255" + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + INDEX { ospfAreaRangeAreaId, ospfAreaRangeNet } + ::= { ospfAreaRangeTable 1 } + +OspfAreaRangeEntry ::= + SEQUENCE { + ospfAreaRangeAreaId + AreaID, + ospfAreaRangeNet + IpAddress, + ospfAreaRangeMask + IpAddress, + ospfAreaRangeStatus + RowStatus, + ospfAreaRangeEffect + INTEGER + } + + ospfAreaRangeAreaId OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The Area the Address Range is to be found + within." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaRangeEntry 1 } + + + ospfAreaRangeNet OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The IP Address of the Net or Subnet indicated + by the range." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaRangeEntry 2 } + + + ospfAreaRangeMask OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-create + STATUS obsolete + DESCRIPTION + "The Subnet Mask that pertains to the Net or + Subnet." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaRangeEntry 3 } + + ospfAreaRangeStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS obsolete + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfAreaRangeEntry 4 } + + + ospfAreaRangeEffect OBJECT-TYPE + SYNTAX INTEGER { + advertiseMatching (1), + doNotAdvertiseMatching (2) + } + MAX-ACCESS read-create + STATUS obsolete + DESCRIPTION + "Subnets subsumed by ranges either trigger the + advertisement of the indicated summary (adver- + tiseMatching), or result in the subnet's not + being advertised at all outside the area." + DEFVAL { advertiseMatching } + ::= { ospfAreaRangeEntry 5 } + + + +-- OSPF Host Table + +-- The Host/Metric Table indicates what hosts are directly +-- attached to the Router, and what metrics and types of +-- service should be advertised for them. + + ospfHostTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfHostEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The list of Hosts, and their metrics, that the + router will advertise as host routes." + REFERENCE + "OSPF Version 2, Appendix C.6 Host route param- + eters" + ::= { ospf 6 } + + + ospfHostEntry OBJECT-TYPE + SYNTAX OspfHostEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A metric to be advertised, for a given type of + service, when a given host is reachable." + INDEX { ospfHostIpAddress, ospfHostTOS } + ::= { ospfHostTable 1 } + +OspfHostEntry ::= + SEQUENCE { + ospfHostIpAddress + IpAddress, + ospfHostTOS + TOSType, + ospfHostMetric + Metric, + ospfHostStatus + RowStatus, + ospfHostAreaID + AreaID + } + + ospfHostIpAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of the Host." + REFERENCE + "OSPF Version 2, Appendix C.6 Host route parame- + ters" + ::= { ospfHostEntry 1 } + + + ospfHostTOS OBJECT-TYPE + SYNTAX TOSType + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Type of Service of the route being config- + ured." + REFERENCE + "OSPF Version 2, Appendix C.6 Host route parame- + ters" + ::= { ospfHostEntry 2 } + + + ospfHostMetric OBJECT-TYPE + SYNTAX Metric + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The Metric to be advertised." + REFERENCE + "OSPF Version 2, Appendix C.6 Host route parame- + ters" + ::= { ospfHostEntry 3 } + + ospfHostStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfHostEntry 4 } + + + ospfHostAreaID OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Area the Host Entry is to be found within. + By default, the area that a subsuming OSPF in- + terface is in, or 0.0.0.0" + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfHostEntry 5 } + + +-- OSPF Interface Table + +-- The OSPF Interface Table augments the ipAddrTable +-- with OSPF specific information. + + ospfIfTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfIfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The OSPF Interface Table describes the inter- + faces from the viewpoint of OSPF." + REFERENCE + "OSPF Version 2, Appendix C.3 Router interface + parameters" + ::= { ospf 7 } + + + ospfIfEntry OBJECT-TYPE + SYNTAX OspfIfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The OSPF Interface Entry describes one inter- + face from the viewpoint of OSPF." + INDEX { ospfIfIpAddress, ospfAddressLessIf } + ::= { ospfIfTable 1 } + +OspfIfEntry ::= + SEQUENCE { + ospfIfIpAddress + IpAddress, + ospfAddressLessIf + Integer32, + ospfIfAreaId + AreaID, + ospfIfType + INTEGER, + ospfIfAdminStat + Status, + ospfIfRtrPriority + DesignatedRouterPriority, + ospfIfTransitDelay + UpToMaxAge, + ospfIfRetransInterval + UpToMaxAge, + ospfIfHelloInterval + HelloRange, + ospfIfRtrDeadInterval + PositiveInteger, + ospfIfPollInterval + PositiveInteger, + ospfIfState + INTEGER, + ospfIfDesignatedRouter + IpAddress, + ospfIfBackupDesignatedRouter + IpAddress, + ospfIfEvents + Counter32, + ospfIfAuthType + INTEGER, + ospfIfAuthKey + OCTET STRING, + ospfIfStatus + RowStatus, + ospfIfMulticastForwarding + INTEGER, + ospfIfDemand + TruthValue + } + + ospfIfIpAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address of this OSPF interface." + ::= { ospfIfEntry 1 } + + ospfAddressLessIf OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "For the purpose of easing the instancing of + addressed and addressless interfaces; This + variable takes the value 0 on interfaces with + IP Addresses, and the corresponding value of + ifIndex for interfaces having no IP Address." + ::= { ospfIfEntry 2 } + ospfIfAreaId OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "A 32-bit integer uniquely identifying the area + to which the interface connects. Area ID + 0.0.0.0 is used for the OSPF backbone." + DEFVAL { '00000000'H } -- 0.0.0.0 + ::= { ospfIfEntry 3 } + + ospfIfType OBJECT-TYPE + SYNTAX INTEGER { + broadcast (1), + nbma (2), + pointToPoint (3), + pointToMultipoint (5) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The OSPF interface type. + + By way of a default, this field may be intuited + from the corresponding value of ifType. Broad- + cast LANs, such as Ethernet and IEEE 802.5, + take the value 'broadcast', X.25 and similar + technologies take the value 'nbma', and links + that are definitively point to point take the + value 'pointToPoint'." + ::= { ospfIfEntry 4 } + + + ospfIfAdminStat OBJECT-TYPE + SYNTAX Status + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The OSPF interface's administrative status. + The value formed on the interface, and the in- + terface will be advertised as an internal route + to some area. The value 'disabled' denotes + that the interface is external to OSPF." + DEFVAL { enabled } + ::= { ospfIfEntry 5 } + + ospfIfRtrPriority OBJECT-TYPE + SYNTAX DesignatedRouterPriority + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The priority of this interface. Used in + multi-access networks, this field is used in + the designated router election algorithm. The + value 0 signifies that the router is not eligi- + ble to become the designated router on this + particular network. In the event of a tie in + this value, routers will use their Router ID as + a tie breaker." + DEFVAL { 1 } + ::= { ospfIfEntry 6 } + + + ospfIfTransitDelay OBJECT-TYPE + SYNTAX UpToMaxAge + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The estimated number of seconds it takes to + transmit a link state update packet over this + interface." + DEFVAL { 1 } + ::= { ospfIfEntry 7 } + + + ospfIfRetransInterval OBJECT-TYPE + SYNTAX UpToMaxAge + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The number of seconds between link-state ad- + vertisement retransmissions, for adjacencies + belonging to this interface. This value is + also used when retransmitting database descrip- + tion and link-state request packets." + DEFVAL { 5 } + ::= { ospfIfEntry 8 } + + + ospfIfHelloInterval OBJECT-TYPE + SYNTAX HelloRange + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The length of time, in seconds, between the + Hello packets that the router sends on the in- + terface. This value must be the same for all + routers attached to a common network." + DEFVAL { 10 } + ::= { ospfIfEntry 9 } + + + ospfIfRtrDeadInterval OBJECT-TYPE + SYNTAX PositiveInteger + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The number of seconds that a router's Hello + packets have not been seen before it's neigh- + bors declare the router down. This should be + some multiple of the Hello interval. This + value must be the same for all routers attached + to a common network." + DEFVAL { 40 } + ::= { ospfIfEntry 10 } + + + ospfIfPollInterval OBJECT-TYPE + SYNTAX PositiveInteger + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The larger time interval, in seconds, between + the Hello packets sent to an inactive non- + broadcast multi- access neighbor." + DEFVAL { 120 } + ::= { ospfIfEntry 11 } + + + ospfIfState OBJECT-TYPE + SYNTAX INTEGER { + down (1), + loopback (2), + waiting (3), + pointToPoint (4), + designatedRouter (5), + backupDesignatedRouter (6), + otherDesignatedRouter (7) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The OSPF Interface State." + DEFVAL { down } + ::= { ospfIfEntry 12 } + + + ospfIfDesignatedRouter OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of the Designated Router." + DEFVAL { '00000000'H } -- 0.0.0.0 + ::= { ospfIfEntry 13 } + + + ospfIfBackupDesignatedRouter OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of the Backup Designated + Router." + DEFVAL { '00000000'H } -- 0.0.0.0 + ::= { ospfIfEntry 14 } + + ospfIfEvents OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times this OSPF interface has + changed its state, or an error has occurred." + ::= { ospfIfEntry 15 } + + + ospfIfAuthKey OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (0..256)) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The Authentication Key. If the Area's Author- + ization Type is simplePassword, and the key + length is shorter than 8 octets, the agent will + left adjust and zero fill to 8 octets. + + Note that unauthenticated interfaces need no + authentication key, and simple password authen- + tication cannot use a key of more than 8 oc- + tets. Larger keys are useful only with authen- + tication mechanisms not specified in this docu- + ment. + + When read, ospfIfAuthKey always returns an Oc- + tet String of length zero." + REFERENCE + "OSPF Version 2, Section 9 The Interface Data + Structure" + DEFVAL { '0000000000000000'H } -- 0.0.0.0.0.0.0.0 + ::= { ospfIfEntry 16 } + + ospfIfStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfIfEntry 17 } + + + ospfIfMulticastForwarding OBJECT-TYPE + SYNTAX INTEGER { + blocked (1), -- no multicast forwarding + multicast (2), -- using multicast address + unicast (3) -- to each OSPF neighbor + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The way multicasts should forwarded on this + interface; not forwarded, forwarded as data + link multicasts, or forwarded as data link uni- + casts. Data link multicasting is not meaning- + ful on point to point and NBMA interfaces, and + setting ospfMulticastForwarding to 0 effective- + ly disables all multicast forwarding." + DEFVAL { blocked } + ::= { ospfIfEntry 18 } + + + ospfIfDemand OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Indicates whether Demand OSPF procedures (hel- + lo supression to FULL neighbors and setting the + DoNotAge flag on proogated LSAs) should be per- + formed on this interface." + DEFVAL { false } + ::= { ospfIfEntry 19 } + + + ospfIfAuthType OBJECT-TYPE + SYNTAX INTEGER (0..255) + -- none (0), + -- simplePassword (1) + -- md5 (2) + -- reserved for specification by IANA (> 2) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The authentication type specified for an in- + terface. Additional authentication types may + be assigned locally." + REFERENCE + "OSPF Version 2, Appendix E Authentication" + DEFVAL { 0 } -- no authentication, by default + ::= { ospfIfEntry 20 } + + +-- OSPF Interface Metric Table + +-- The Metric Table describes the metrics to be advertised +-- for a specified interface at the various types of service. +-- As such, this table is an adjunct of the OSPF Interface +-- Table. + +-- Types of service, as defined by RFC 791, have the ability +-- to request low delay, high bandwidth, or reliable linkage. + +-- For the purposes of this specification, the measure of +-- bandwidth + +-- Metric = 10^8 / ifSpeed + +-- is the default value. For multiple link interfaces, note +-- that ifSpeed is the sum of the individual link speeds. +-- This yields a number having the following typical values: + +-- Network Type/bit rate Metric + +-- >= 100 MBPS 1 +-- Ethernet/802.3 10 +-- E1 48 +-- T1 (ESF) 65 +-- 64 KBPS 1562 +-- 56 KBPS 1785 +-- 19.2 KBPS 5208 +-- 9.6 KBPS 10416 + +-- Routes that are not specified use the default (TOS 0) metric + + ospfIfMetricTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfIfMetricEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The TOS metrics for a non-virtual interface + identified by the interface index." + REFERENCE + "OSPF Version 2, Appendix C.3 Router interface + parameters" + ::= { ospf 8 } + + ospfIfMetricEntry OBJECT-TYPE + SYNTAX OspfIfMetricEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A particular TOS metric for a non-virtual in- + terface identified by the interface index." + REFERENCE + "OSPF Version 2, Appendix C.3 Router interface + parameters" + INDEX { ospfIfMetricIpAddress, + ospfIfMetricAddressLessIf, + ospfIfMetricTOS } + ::= { ospfIfMetricTable 1 } + +OspfIfMetricEntry ::= + SEQUENCE { + ospfIfMetricIpAddress + IpAddress, + ospfIfMetricAddressLessIf + Integer32, + ospfIfMetricTOS + TOSType, + ospfIfMetricValue + Metric, + ospfIfMetricStatus + RowStatus + } + + ospfIfMetricIpAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address of this OSPF interface. On row + creation, this can be derived from the in- + stance." + ::= { ospfIfMetricEntry 1 } + + ospfIfMetricAddressLessIf OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "For the purpose of easing the instancing of + addressed and addressless interfaces; This + variable takes the value 0 on interfaces with + IP Addresses, and the value of ifIndex for in- + terfaces having no IP Address. On row crea- + tion, this can be derived from the instance." + ::= { ospfIfMetricEntry 2 } + + + ospfIfMetricTOS OBJECT-TYPE + SYNTAX TOSType + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The type of service metric being referenced. + On row creation, this can be derived from the + instance." + ::= { ospfIfMetricEntry 3 } + + + ospfIfMetricValue OBJECT-TYPE + SYNTAX Metric + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The metric of using this type of service on + this interface. The default value of the TOS 0 + Metric is 10^8 / ifSpeed." + ::= { ospfIfMetricEntry 4 } + + ospfIfMetricStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfIfMetricEntry 5 } + + +-- OSPF Virtual Interface Table + +-- The Virtual Interface Table describes the virtual +-- links that the OSPF Process is configured to +-- carry on. + + ospfVirtIfTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfVirtIfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information about this router's virtual inter- + faces." + REFERENCE + "OSPF Version 2, Appendix C.4 Virtual link + parameters" + ::= { ospf 9 } + + + ospfVirtIfEntry OBJECT-TYPE + SYNTAX OspfVirtIfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information about a single Virtual Interface." + INDEX { ospfVirtIfAreaId, ospfVirtIfNeighbor } + ::= { ospfVirtIfTable 1 } + +OspfVirtIfEntry ::= + SEQUENCE { + ospfVirtIfAreaId + AreaID, + ospfVirtIfNeighbor + RouterID, + ospfVirtIfTransitDelay + UpToMaxAge, + ospfVirtIfRetransInterval + UpToMaxAge, + ospfVirtIfHelloInterval + HelloRange, + ospfVirtIfRtrDeadInterval + PositiveInteger, + ospfVirtIfState + INTEGER, + ospfVirtIfEvents + Counter32, + ospfVirtIfAuthType + INTEGER, + ospfVirtIfAuthKey + OCTET STRING, + ospfVirtIfStatus + RowStatus + } + + ospfVirtIfAreaId OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Transit Area that the Virtual Link + traverses. By definition, this is not 0.0.0.0" + ::= { ospfVirtIfEntry 1 } + + + ospfVirtIfNeighbor OBJECT-TYPE + SYNTAX RouterID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Router ID of the Virtual Neighbor." + ::= { ospfVirtIfEntry 2 } + + + ospfVirtIfTransitDelay OBJECT-TYPE + SYNTAX UpToMaxAge + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The estimated number of seconds it takes to + transmit a link- state update packet over this + interface." + DEFVAL { 1 } + ::= { ospfVirtIfEntry 3 } + + + ospfVirtIfRetransInterval OBJECT-TYPE + SYNTAX UpToMaxAge + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The number of seconds between link-state ad- + vertisement retransmissions, for adjacencies + belonging to this interface. This value is + also used when retransmitting database descrip- + tion and link-state request packets. This + value should be well over the expected round- + trip time." + DEFVAL { 5 } + ::= { ospfVirtIfEntry 4 } + + + ospfVirtIfHelloInterval OBJECT-TYPE + SYNTAX HelloRange + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The length of time, in seconds, between the + Hello packets that the router sends on the in- + terface. This value must be the same for the + virtual neighbor." + DEFVAL { 10 } + ::= { ospfVirtIfEntry 5 } + + + ospfVirtIfRtrDeadInterval OBJECT-TYPE + SYNTAX PositiveInteger + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The number of seconds that a router's Hello + packets have not been seen before it's neigh- + bors declare the router down. This should be + some multiple of the Hello interval. This + value must be the same for the virtual neigh- + bor." + DEFVAL { 60 } + ::= { ospfVirtIfEntry 6 } + + + ospfVirtIfState OBJECT-TYPE + SYNTAX INTEGER { + down (1), -- these use the same encoding + pointToPoint (4) -- as the ospfIfTable + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "OSPF virtual interface states." + DEFVAL { down } + ::= { ospfVirtIfEntry 7 } + + + ospfVirtIfEvents OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of state changes or error events on + this Virtual Link" + ::= { ospfVirtIfEntry 8 } + + + ospfVirtIfAuthKey OBJECT-TYPE + SYNTAX OCTET STRING (SIZE(0..256)) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "If Authentication Type is simplePassword, the + device will left adjust and zero fill to 8 oc- + tets. + + Note that unauthenticated interfaces need no + authentication key, and simple password authen- + tication cannot use a key of more than 8 oc- + tets. Larger keys are useful only with authen- + tication mechanisms not specified in this docu- + ment. + + When read, ospfVifAuthKey always returns a + string of length zero." + REFERENCE + "OSPF Version 2, Section 9 The Interface Data + Structure" + DEFVAL { '0000000000000000'H } -- 0.0.0.0.0.0.0.0 + ::= { ospfVirtIfEntry 9 } + + + ospfVirtIfStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfVirtIfEntry 10 } + + + ospfVirtIfAuthType OBJECT-TYPE + SYNTAX INTEGER (0..255) + -- none (0), + -- simplePassword (1) + -- md5 (2) + -- reserved for specification by IANA (> 2) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The authentication type specified for a virtu- + al interface. Additional authentication types + may be assigned locally." + REFERENCE + "OSPF Version 2, Appendix E Authentication" + DEFVAL { 0 } -- no authentication, by default + ::= { ospfVirtIfEntry 11 } + + +-- OSPF Neighbor Table + +-- The OSPF Neighbor Table describes all neighbors in +-- the locality of the subject router. + + ospfNbrTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfNbrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table of non-virtual neighbor information." + REFERENCE + "OSPF Version 2, Section 10 The Neighbor Data + Structure" + ::= { ospf 10 } + + + ospfNbrEntry OBJECT-TYPE + SYNTAX OspfNbrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The information regarding a single neighbor." + REFERENCE + "OSPF Version 2, Section 10 The Neighbor Data + Structure" + INDEX { ospfNbrIpAddr, ospfNbrAddressLessIndex } + ::= { ospfNbrTable 1 } + +OspfNbrEntry ::= + SEQUENCE { + ospfNbrIpAddr + IpAddress, + ospfNbrAddressLessIndex + InterfaceIndex, + ospfNbrRtrId + RouterID, + ospfNbrOptions + Integer32, + ospfNbrPriority + DesignatedRouterPriority, + ospfNbrState + INTEGER, + ospfNbrEvents + Counter32, + ospfNbrLsRetransQLen + Gauge32, + ospfNbmaNbrStatus + RowStatus, + ospfNbmaNbrPermanence + INTEGER, + ospfNbrHelloSuppressed + TruthValue + } + + ospfNbrIpAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address this neighbor is using in its + IP Source Address. Note that, on addressless + links, this will not be 0.0.0.0, but the ad- + dress of another of the neighbor's interfaces." + ::= { ospfNbrEntry 1 } + + + ospfNbrAddressLessIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "On an interface having an IP Address, zero. + On addressless interfaces, the corresponding + value of ifIndex in the Internet Standard MIB. + On row creation, this can be derived from the + instance." + ::= { ospfNbrEntry 2 } + + + ospfNbrRtrId OBJECT-TYPE + SYNTAX RouterID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A 32-bit integer (represented as a type IpAd- + dress) uniquely identifying the neighboring + router in the Autonomous System." + DEFVAL { '00000000'H } -- 0.0.0.0 + ::= { ospfNbrEntry 3 } + + + ospfNbrOptions OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A Bit Mask corresponding to the neighbor's op- + tions field. + + Bit 0, if set, indicates that the system will + operate on Type of Service metrics other than + TOS 0. If zero, the neighbor will ignore all + metrics except the TOS 0 metric. + + Bit 1, if set, indicates that the associated + area accepts and operates on external informa- + tion; if zero, it is a stub area. + + Bit 2, if set, indicates that the system is ca- + pable of routing IP Multicast datagrams; i.e., + that it implements the Multicast Extensions to + OSPF. + + Bit 3, if set, indicates that the associated + area is an NSSA. These areas are capable of + carrying type 7 external advertisements, which + are translated into type 5 external advertise- + ments at NSSA borders." + REFERENCE + "OSPF Version 2, Section 12.1.2 Options" + DEFVAL { 0 } + ::= { ospfNbrEntry 4 } + + + ospfNbrPriority OBJECT-TYPE + SYNTAX DesignatedRouterPriority + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The priority of this neighbor in the designat- + ed router election algorithm. The value 0 sig- + nifies that the neighbor is not eligible to be- + come the designated router on this particular + network." + DEFVAL { 1 } + ::= { ospfNbrEntry 5 } + + + ospfNbrState OBJECT-TYPE + SYNTAX INTEGER { + down (1), + attempt (2), + init (3), + twoWay (4), + exchangeStart (5), + exchange (6), + loading (7), + full (8) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The State of the relationship with this Neigh- + bor." + REFERENCE + "OSPF Version 2, Section 10.1 Neighbor States" + DEFVAL { down } + ::= { ospfNbrEntry 6 } + + + ospfNbrEvents OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times this neighbor relationship + has changed state, or an error has occurred." + ::= { ospfNbrEntry 7 } + + + ospfNbrLsRetransQLen OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The current length of the retransmission + queue." + ::= { ospfNbrEntry 8 } + + + ospfNbmaNbrStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfNbrEntry 9 } + + + ospfNbmaNbrPermanence OBJECT-TYPE + SYNTAX INTEGER { + dynamic (1), -- learned through protocol + permanent (2) -- configured address + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. 'dynamic' and 'permanent' refer to how + the neighbor became known." + DEFVAL { permanent } + ::= { ospfNbrEntry 10 } + + + ospfNbrHelloSuppressed OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Indicates whether Hellos are being suppressed + to the neighbor" + ::= { ospfNbrEntry 11 } + + +-- OSPF Virtual Neighbor Table + +-- This table describes all virtual neighbors. +-- Since Virtual Links are configured in the +-- virtual interface table, this table is read-only. + + ospfVirtNbrTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfVirtNbrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table of virtual neighbor information." + REFERENCE + "OSPF Version 2, Section 15 Virtual Links" + ::= { ospf 11 } + + + ospfVirtNbrEntry OBJECT-TYPE + SYNTAX OspfVirtNbrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Virtual neighbor information." + INDEX { ospfVirtNbrArea, ospfVirtNbrRtrId } + ::= { ospfVirtNbrTable 1 } + +OspfVirtNbrEntry ::= + SEQUENCE { + ospfVirtNbrArea + AreaID, + ospfVirtNbrRtrId + RouterID, + ospfVirtNbrIpAddr + IpAddress, + ospfVirtNbrOptions + Integer32, + ospfVirtNbrState + INTEGER, + ospfVirtNbrEvents + Counter32, + ospfVirtNbrLsRetransQLen + Gauge32, + ospfVirtNbrHelloSuppressed + TruthValue + } + + ospfVirtNbrArea OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Transit Area Identifier." + ::= { ospfVirtNbrEntry 1 } + + + ospfVirtNbrRtrId OBJECT-TYPE + SYNTAX RouterID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A 32-bit integer uniquely identifying the + neighboring router in the Autonomous System." + ::= { ospfVirtNbrEntry 2 } + + + ospfVirtNbrIpAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address this Virtual Neighbor is us- + ing." + ::= { ospfVirtNbrEntry 3 } + + + ospfVirtNbrOptions OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A Bit Mask corresponding to the neighbor's op- + tions field. + + Bit 1, if set, indicates that the system will + operate on Type of Service metrics other than + TOS 0. If zero, the neighbor will ignore all + metrics except the TOS 0 metric. + + Bit 2, if set, indicates that the system is + Network Multicast capable; ie, that it imple- + ments OSPF Multicast Routing." + ::= { ospfVirtNbrEntry 4 } + ospfVirtNbrState OBJECT-TYPE + SYNTAX INTEGER { + down (1), + attempt (2), + init (3), + twoWay (4), + exchangeStart (5), + exchange (6), + loading (7), + full (8) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The state of the Virtual Neighbor Relation- + ship." + ::= { ospfVirtNbrEntry 5 } + + + ospfVirtNbrEvents OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times this virtual link has + changed its state, or an error has occurred." + ::= { ospfVirtNbrEntry 6 } + + + ospfVirtNbrLsRetransQLen OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The current length of the retransmission + queue." + ::= { ospfVirtNbrEntry 7 } + + + ospfVirtNbrHelloSuppressed OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Indicates whether Hellos are being suppressed + to the neighbor" + ::= { ospfVirtNbrEntry 8 } + +-- OSPF Link State Database, External + +-- The Link State Database contains the Link State +-- Advertisements from throughout the areas that the +-- device is attached to. + +-- This table is identical to the OSPF LSDB Table in +-- format, but contains only External Link State +-- Advertisements. The purpose is to allow external +-- LSAs to be displayed once for the router rather +-- than once in each non-stub area. + + ospfExtLsdbTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfExtLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The OSPF Process's Links State Database." + REFERENCE + "OSPF Version 2, Section 12 Link State Adver- + tisements" + ::= { ospf 12 } + + + ospfExtLsdbEntry OBJECT-TYPE + SYNTAX OspfExtLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A single Link State Advertisement." + INDEX { ospfExtLsdbType, ospfExtLsdbLsid, ospfExtLsdbRouterId } + ::= { ospfExtLsdbTable 1 } + +OspfExtLsdbEntry ::= + SEQUENCE { + ospfExtLsdbType + INTEGER, + ospfExtLsdbLsid + IpAddress, + ospfExtLsdbRouterId + RouterID, + ospfExtLsdbSequence + Integer32, + ospfExtLsdbAge + Integer32, + ospfExtLsdbChecksum + Integer32, + ospfExtLsdbAdvertisement + OCTET STRING + } + + ospfExtLsdbType OBJECT-TYPE + SYNTAX INTEGER { + asExternalLink (5) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The type of the link state advertisement. + Each link state type has a separate advertise- + ment format." + REFERENCE + "OSPF Version 2, Appendix A.4.1 The Link State + Advertisement header" + ::= { ospfExtLsdbEntry 1 } + + + ospfExtLsdbLsid OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Link State ID is an LS Type Specific field + containing either a Router ID or an IP Address; + it identifies the piece of the routing domain + that is being described by the advertisement." + REFERENCE + "OSPF Version 2, Section 12.1.4 Link State ID" + ::= { ospfExtLsdbEntry 2 } + + + ospfExtLsdbRouterId OBJECT-TYPE + SYNTAX RouterID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32 bit number that uniquely identifies the + originating router in the Autonomous System." + REFERENCE + "OSPF Version 2, Appendix C.1 Global parameters" + ::= { ospfExtLsdbEntry 3 } + +-- Note that the OSPF Sequence Number is a 32 bit signed +-- integer. It starts with the value '80000001'h, +-- or -'7FFFFFFF'h, and increments until '7FFFFFFF'h +-- Thus, a typical sequence number will be very negative. + ospfExtLsdbSequence OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The sequence number field is a signed 32-bit + integer. It is used to detect old and dupli- + cate link state advertisements. The space of + sequence numbers is linearly ordered. The + larger the sequence number the more recent the + advertisement." + REFERENCE + "OSPF Version 2, Section 12.1.6 LS sequence + number" + ::= { ospfExtLsdbEntry 4 } + + + ospfExtLsdbAge OBJECT-TYPE + SYNTAX Integer32 -- Should be 0..MaxAge + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the age of the link state adver- + tisement in seconds." + REFERENCE + "OSPF Version 2, Section 12.1.1 LS age" + ::= { ospfExtLsdbEntry 5 } + + + ospfExtLsdbChecksum OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the checksum of the complete + contents of the advertisement, excepting the + age field. The age field is excepted so that + an advertisement's age can be incremented + without updating the checksum. The checksum + used is the same that is used for ISO connec- + tionless datagrams; it is commonly referred to + as the Fletcher checksum." + REFERENCE + "OSPF Version 2, Section 12.1.7 LS checksum" + ::= { ospfExtLsdbEntry 6 } + + + ospfExtLsdbAdvertisement OBJECT-TYPE + SYNTAX OCTET STRING (SIZE(36)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The entire Link State Advertisement, including + its header." + REFERENCE + "OSPF Version 2, Section 12 Link State Adver- + tisements" + ::= { ospfExtLsdbEntry 7 } + + +-- OSPF Use of the CIDR Route Table + +ospfRouteGroup OBJECT IDENTIFIER ::= { ospf 13 } + +-- The IP Forwarding Table defines a number of objects for use by +-- the routing protocol to externalize its information. Most of +-- the variables (ipForwardDest, ipForwardMask, ipForwardPolicy, +-- ipForwardNextHop, ipForwardIfIndex, ipForwardType, +-- ipForwardProto, ipForwardAge, and ipForwardNextHopAS) are +-- defined there. + +-- Those that leave some discretion are defined here. + +-- ipCidrRouteProto is, of course, ospf (13). + +-- ipCidrRouteAge is the time since the route was first calculated, +-- as opposed to the time since the last SPF run. + +-- ipCidrRouteInfo is an OBJECT IDENTIFIER for use by the routing +-- protocol. The following values shall be found there depending +-- on the way the route was calculated. + +ospfIntraArea OBJECT IDENTIFIER ::= { ospfRouteGroup 1 } +ospfInterArea OBJECT IDENTIFIER ::= { ospfRouteGroup 2 } +ospfExternalType1 OBJECT IDENTIFIER ::= { ospfRouteGroup 3 } +ospfExternalType2 OBJECT IDENTIFIER ::= { ospfRouteGroup 4 } + +-- ipCidrRouteMetric1 is, by definition, the primary routing +-- metric. Therefore, it should be the metric that route +-- selection is based on. For intra-area and inter-area routes, +-- it is an OSPF metric. For External Type 1 (comparable value) +-- routes, it is an OSPF metric plus the External Metric. For +-- external Type 2 (non-comparable value) routes, it is the +-- external metric. + +-- ipCidrRouteMetric2 is, by definition, a secondary routing +-- metric. Therefore, it should be the metric that breaks a tie +-- among routes having equal metric1 values and the same +-- calculation rule. For intra-area, inter-area routes, and +-- External Type 1 (comparable value) routes, it is unused. For +-- external Type 2 (non-comparable value) routes, it is the metric +-- to the AS border router. + +-- ipCidrRouteMetric3, ipCidrRouteMetric4, and ipCidrRouteMetric5 are +-- unused. + +-- +-- The OSPF Area Aggregate Table +-- +-- This table replaces the OSPF Area Summary Table, being an +-- extension of that for CIDR routers. + + ospfAreaAggregateTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfAreaAggregateEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A range of IP addresses specified by an IP + address/IP network mask pair. For example, + class B address range of X.X.X.X with a network + mask of 255.255.0.0 includes all IP addresses + from X.X.0.0 to X.X.255.255. Note that if + ranges are configured such that one range sub- + sumes another range (e.g., 10.0.0.0 mask + 255.0.0.0 and 10.1.0.0 mask 255.255.0.0), the + most specific match is the preferred one." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospf 14 } + + + ospfAreaAggregateEntry OBJECT-TYPE + SYNTAX OspfAreaAggregateEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A range of IP addresses specified by an IP + address/IP network mask pair. For example, + class B address range of X.X.X.X with a network + mask of 255.255.0.0 includes all IP addresses + from X.X.0.0 to X.X.255.255. Note that if + ranges are range configured such that one range + subsumes another range (e.g., 10.0.0.0 mask + 255.0.0.0 and 10.1.0.0 mask 255.255.0.0), the + most specific match is the preferred one." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + INDEX { ospfAreaAggregateAreaID, ospfAreaAggregateLsdbType, + ospfAreaAggregateNet, ospfAreaAggregateMask } + ::= { ospfAreaAggregateTable 1 } + + +OspfAreaAggregateEntry ::= + SEQUENCE { + ospfAreaAggregateAreaID + AreaID, + ospfAreaAggregateLsdbType + INTEGER, + ospfAreaAggregateNet + IpAddress, + ospfAreaAggregateMask + IpAddress, + ospfAreaAggregateStatus + RowStatus, + ospfAreaAggregateEffect + INTEGER + } + + ospfAreaAggregateAreaID OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Area the Address Aggregate is to be found + within." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaAggregateEntry 1 } + + + ospfAreaAggregateLsdbType OBJECT-TYPE + SYNTAX INTEGER { + summaryLink (3), + nssaExternalLink (7) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The type of the Address Aggregate. This field + specifies the Lsdb type that this Address Ag- + gregate applies to." + REFERENCE + "OSPF Version 2, Appendix A.4.1 The Link State + Advertisement header" + ::= { ospfAreaAggregateEntry 2 } + + + ospfAreaAggregateNet OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of the Net or Subnet indicated + by the range." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaAggregateEntry 3 } + + + ospfAreaAggregateMask OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Subnet Mask that pertains to the Net or + Subnet." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaAggregateEntry 4 } + + + ospfAreaAggregateStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfAreaAggregateEntry 5 } + + + ospfAreaAggregateEffect OBJECT-TYPE + SYNTAX INTEGER { + advertiseMatching (1), + doNotAdvertiseMatching (2) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Subnets subsumed by ranges either trigger the + advertisement of the indicated aggregate (ad- + vertiseMatching), or result in the subnet's not + being advertised at all outside the area." + DEFVAL { advertiseMatching } + ::= { ospfAreaAggregateEntry 6 } + + +-- conformance information + +ospfConformance OBJECT IDENTIFIER ::= { ospf 15 } + +ospfGroups OBJECT IDENTIFIER ::= { ospfConformance 1 } +ospfCompliances OBJECT IDENTIFIER ::= { ospfConformance 2 } + +-- compliance statements + + ospfCompliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement " + MODULE -- this module + MANDATORY-GROUPS { + ospfBasicGroup, + ospfAreaGroup, + ospfStubAreaGroup, + ospfIfGroup, + ospfIfMetricGroup, + ospfVirtIfGroup, + ospfNbrGroup, + ospfVirtNbrGroup, + ospfAreaAggregateGroup + } + ::= { ospfCompliances 1 } + + +-- units of conformance + + ospfBasicGroup OBJECT-GROUP + OBJECTS { + ospfRouterId, + ospfAdminStat, + ospfVersionNumber, + ospfAreaBdrRtrStatus, + ospfASBdrRtrStatus, + ospfExternLsaCount, + ospfExternLsaCksumSum, + ospfTOSSupport, + ospfOriginateNewLsas, + ospfRxNewLsas, + ospfExtLsdbLimit, + ospfMulticastExtensions, + ospfExitOverflowInterval, + ospfDemandExtensions + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 1 } + + + ospfAreaGroup OBJECT-GROUP + OBJECTS { + ospfAreaId, + ospfImportAsExtern, + ospfSpfRuns, + ospfAreaBdrRtrCount, + ospfAsBdrRtrCount, + ospfAreaLsaCount, + ospfAreaLsaCksumSum, + ospfAreaSummary, + ospfAreaStatus + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems + supporting areas." + ::= { ospfGroups 2 } + + + ospfStubAreaGroup OBJECT-GROUP + OBJECTS { + ospfStubAreaId, + ospfStubTOS, + ospfStubMetric, + ospfStubStatus, + ospfStubMetricType + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems + supporting stub areas." + ::= { ospfGroups 3 } + + + ospfLsdbGroup OBJECT-GROUP + OBJECTS { + ospfLsdbAreaId, + ospfLsdbType, + ospfLsdbLsid, + ospfLsdbRouterId, + ospfLsdbSequence, + ospfLsdbAge, + ospfLsdbChecksum, + ospfLsdbAdvertisement + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems + that display their link state database." + ::= { ospfGroups 4 } + + + ospfAreaRangeGroup OBJECT-GROUP + OBJECTS { + ospfAreaRangeAreaId, + ospfAreaRangeNet, + ospfAreaRangeMask, + ospfAreaRangeStatus, + ospfAreaRangeEffect + } + STATUS obsolete + DESCRIPTION + "These objects are required for non-CIDR OSPF + systems that support multiple areas." + ::= { ospfGroups 5 } + + + ospfHostGroup OBJECT-GROUP + OBJECTS { + ospfHostIpAddress, + ospfHostTOS, + ospfHostMetric, + ospfHostStatus, + ospfHostAreaID + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems + that support attached hosts." + ::= { ospfGroups 6 } + + + ospfIfGroup OBJECT-GROUP + OBJECTS { + ospfIfIpAddress, + ospfAddressLessIf, + ospfIfAreaId, + ospfIfType, + ospfIfAdminStat, + ospfIfRtrPriority, + ospfIfTransitDelay, + ospfIfRetransInterval, + ospfIfHelloInterval, + ospfIfRtrDeadInterval, + ospfIfPollInterval, + ospfIfState, + ospfIfDesignatedRouter, + ospfIfBackupDesignatedRouter, + ospfIfEvents, + ospfIfAuthType, + ospfIfAuthKey, + ospfIfStatus, + ospfIfMulticastForwarding, + ospfIfDemand + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 7 } + + + ospfIfMetricGroup OBJECT-GROUP + OBJECTS { + ospfIfMetricIpAddress, + ospfIfMetricAddressLessIf, + ospfIfMetricTOS, + ospfIfMetricValue, + ospfIfMetricStatus + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 8 } + + + ospfVirtIfGroup OBJECT-GROUP + OBJECTS { + ospfVirtIfAreaId, + ospfVirtIfNeighbor, + ospfVirtIfTransitDelay, + ospfVirtIfRetransInterval, + ospfVirtIfHelloInterval, + ospfVirtIfRtrDeadInterval, + ospfVirtIfState, + ospfVirtIfEvents, + ospfVirtIfAuthType, + ospfVirtIfAuthKey, + ospfVirtIfStatus + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 9 } + + + ospfNbrGroup OBJECT-GROUP + OBJECTS { + ospfNbrIpAddr, + ospfNbrAddressLessIndex, + ospfNbrRtrId, + ospfNbrOptions, + ospfNbrPriority, + ospfNbrState, + ospfNbrEvents, + ospfNbrLsRetransQLen, + ospfNbmaNbrStatus, + ospfNbmaNbrPermanence, + ospfNbrHelloSuppressed + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 10 } + + + ospfVirtNbrGroup OBJECT-GROUP + OBJECTS { + ospfVirtNbrArea, + ospfVirtNbrRtrId, + ospfVirtNbrIpAddr, + ospfVirtNbrOptions, + ospfVirtNbrState, + ospfVirtNbrEvents, + ospfVirtNbrLsRetransQLen, + ospfVirtNbrHelloSuppressed + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 11 } + + + ospfExtLsdbGroup OBJECT-GROUP + OBJECTS { + ospfExtLsdbType, + ospfExtLsdbLsid, + ospfExtLsdbRouterId, + ospfExtLsdbSequence, + ospfExtLsdbAge, + ospfExtLsdbChecksum, + ospfExtLsdbAdvertisement + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems + that display their link state database." + ::= { ospfGroups 12 } + + + ospfAreaAggregateGroup OBJECT-GROUP + OBJECTS { + ospfAreaAggregateAreaID, + ospfAreaAggregateLsdbType, + ospfAreaAggregateNet, + ospfAreaAggregateMask, + ospfAreaAggregateStatus, + ospfAreaAggregateEffect + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 13 } + +END diff --git a/ospfd/OSPF-TRAP-MIB.txt b/ospfd/OSPF-TRAP-MIB.txt new file mode 100644 index 00000000..8a3ab990 --- /dev/null +++ b/ospfd/OSPF-TRAP-MIB.txt @@ -0,0 +1,443 @@ +OSPF-TRAP-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE, IpAddress + FROM SNMPv2-SMI + MODULE-COMPLIANCE, OBJECT-GROUP + FROM SNMPv2-CONF + ospfRouterId, ospfIfIpAddress, ospfAddressLessIf, ospfIfState, + ospfVirtIfAreaId, ospfVirtIfNeighbor, ospfVirtIfState, + ospfNbrIpAddr, ospfNbrAddressLessIndex, ospfNbrRtrId, + ospfNbrState, ospfVirtNbrArea, ospfVirtNbrRtrId, ospfVirtNbrState, + ospfLsdbType, ospfLsdbLsid, ospfLsdbRouterId, ospfLsdbAreaId, + ospfExtLsdbLimit, ospf + FROM OSPF-MIB; + + ospfTrap MODULE-IDENTITY + LAST-UPDATED "9501201225Z" -- Fri Jan 20 12:25:50 PST 1995 + ORGANIZATION "IETF OSPF Working Group" + CONTACT-INFO + " Fred Baker + Postal: Cisco Systems + 519 Lado Drive + Santa Barbara, California 93111 + Tel: +1 805 681 0115 + E-Mail: fred@cisco.com + + Rob Coltun + Postal: RainbowBridge Communications + Tel: (301) 340-9416 + E-Mail: rcoltun@rainbow-bridge.com" + DESCRIPTION + "The MIB module to describe traps for the OSPF + Version 2 Protocol." + ::= { ospf 16 } + +-- Trap Support Objects + +-- The following are support objects for the OSPF traps. + +ospfTrapControl OBJECT IDENTIFIER ::= { ospfTrap 1 } +ospfTraps OBJECT IDENTIFIER ::= { ospfTrap 2 } + + ospfSetTrap OBJECT-TYPE + SYNTAX OCTET STRING (SIZE(4)) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "A four-octet string serving as a bit map for + the trap events defined by the OSPF traps. This + object is used to enable and disable specific + OSPF traps where a 1 in the bit field + represents enabled. The right-most bit (least + significant) represents trap 0." + ::= { ospfTrapControl 1 } + + + ospfConfigErrorType OBJECT-TYPE + SYNTAX INTEGER { + badVersion (1), + areaMismatch (2), + unknownNbmaNbr (3), -- Router is Dr eligible + unknownVirtualNbr (4), + authTypeMismatch(5), + authFailure (6), + netMaskMismatch (7), + helloIntervalMismatch (8), + deadIntervalMismatch (9), + optionMismatch (10) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Potential types of configuration conflicts. + Used by the ospfConfigError and ospfConfigVir- + tError traps." + ::= { ospfTrapControl 2 } + + + ospfPacketType OBJECT-TYPE + SYNTAX INTEGER { + hello (1), + dbDescript (2), + lsReq (3), + lsUpdate (4), + lsAck (5) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "OSPF packet types." + ::= { ospfTrapControl 3 } + + + ospfPacketSrc OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address of an inbound packet that can- + not be identified by a neighbor instance." + ::= { ospfTrapControl 4 } + + +-- Traps + + + ospfIfStateChange NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfIfIpAddress, + ospfAddressLessIf, + ospfIfState -- The new state + } + STATUS current + DESCRIPTION + "An ospfIfStateChange trap signifies that there + has been a change in the state of a non-virtual + OSPF interface. This trap should be generated + when the interface state regresses (e.g., goes + from Dr to Down) or progresses to a terminal + state (i.e., Point-to-Point, DR Other, Dr, or + Backup)." + ::= { ospfTraps 16 } + + + ospfVirtIfStateChange NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfVirtIfAreaId, + ospfVirtIfNeighbor, + ospfVirtIfState -- The new state + } + STATUS current + DESCRIPTION + "An ospfIfStateChange trap signifies that there + has been a change in the state of an OSPF vir- + tual interface. + This trap should be generated when the inter- + face state regresses (e.g., goes from Point- + to-Point to Down) or progresses to a terminal + state (i.e., Point-to-Point)." + ::= { ospfTraps 1 } + + + ospfNbrStateChange NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfNbrIpAddr, + ospfNbrAddressLessIndex, + ospfNbrRtrId, + ospfNbrState -- The new state + } + STATUS current + DESCRIPTION + "An ospfNbrStateChange trap signifies that + there has been a change in the state of a non- + virtual OSPF neighbor. This trap should be + generated when the neighbor state regresses + (e.g., goes from Attempt or Full to 1-Way or + Down) or progresses to a terminal state (e.g., + 2-Way or Full). When an neighbor transitions + from or to Full on non-broadcast multi-access + and broadcast networks, the trap should be gen- + erated by the designated router. A designated + router transitioning to Down will be noted by + ospfIfStateChange." + ::= { ospfTraps 2 } + + + ospfVirtNbrStateChange NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfVirtNbrArea, + ospfVirtNbrRtrId, + ospfVirtNbrState -- The new state + } + STATUS current + DESCRIPTION + "An ospfIfStateChange trap signifies that there + has been a change in the state of an OSPF vir- + tual neighbor. This trap should be generated + when the neighbor state regresses (e.g., goes + from Attempt or Full to 1-Way or Down) or + progresses to a terminal state (e.g., Full)." + ::= { ospfTraps 3 } + ospfIfConfigError NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfIfIpAddress, + ospfAddressLessIf, + ospfPacketSrc, -- The source IP address + ospfConfigErrorType, -- Type of error + ospfPacketType + } + STATUS current + DESCRIPTION + "An ospfIfConfigError trap signifies that a + packet has been received on a non-virtual in- + terface from a router whose configuration + parameters conflict with this router's confi- + guration parameters. Note that the event op- + tionMismatch should cause a trap only if it + prevents an adjacency from forming." + ::= { ospfTraps 4 } + + + ospfVirtIfConfigError NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfVirtIfAreaId, + ospfVirtIfNeighbor, + ospfConfigErrorType, -- Type of error + ospfPacketType + } + STATUS current + DESCRIPTION + "An ospfConfigError trap signifies that a pack- + et has been received on a virtual interface + from a router whose configuration parameters + conflict with this router's configuration + parameters. Note that the event optionMismatch + should cause a trap only if it prevents an ad- + jacency from forming." + ::= { ospfTraps 5 } + + + ospfIfAuthFailure NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfIfIpAddress, + ospfAddressLessIf, + ospfPacketSrc, -- The source IP address + ospfConfigErrorType, -- authTypeMismatch or + -- authFailure + ospfPacketType + } + STATUS current + DESCRIPTION + "An ospfIfAuthFailure trap signifies that a + packet has been received on a non-virtual in- + terface from a router whose authentication key + or authentication type conflicts with this + router's authentication key or authentication + type." + ::= { ospfTraps 6 } + + + ospfVirtIfAuthFailure NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfVirtIfAreaId, + ospfVirtIfNeighbor, + ospfConfigErrorType, -- authTypeMismatch or + -- authFailure + ospfPacketType + } + STATUS current + DESCRIPTION + "An ospfVirtIfAuthFailure trap signifies that a + packet has been received on a virtual interface + from a router whose authentication key or au- + thentication type conflicts with this router's + authentication key or authentication type." + ::= { ospfTraps 7 } + + + ospfIfRxBadPacket NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfIfIpAddress, + ospfAddressLessIf, + ospfPacketSrc, -- The source IP address + ospfPacketType + } + STATUS current + DESCRIPTION + "An ospfIfRxBadPacket trap signifies that an + OSPF packet has been received on a non-virtual + interface that cannot be parsed." + ::= { ospfTraps 8 } + + ospfVirtIfRxBadPacket NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfVirtIfAreaId, + ospfVirtIfNeighbor, + ospfPacketType + } + STATUS current + DESCRIPTION + "An ospfRxBadPacket trap signifies that an OSPF + packet has been received on a virtual interface + that cannot be parsed." + ::= { ospfTraps 9 } + + + ospfTxRetransmit NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfIfIpAddress, + ospfAddressLessIf, + ospfNbrRtrId, -- Destination + ospfPacketType, + ospfLsdbType, + ospfLsdbLsid, + ospfLsdbRouterId + } + STATUS current + DESCRIPTION + "An ospfTxRetransmit trap signifies than an + OSPF packet has been retransmitted on a non- + virtual interface. All packets that may be re- + transmitted are associated with an LSDB entry. + The LS type, LS ID, and Router ID are used to + identify the LSDB entry." + ::= { ospfTraps 10 } + + + ospfVirtIfTxRetransmit NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfVirtIfAreaId, + ospfVirtIfNeighbor, + ospfPacketType, + ospfLsdbType, + ospfLsdbLsid, + ospfLsdbRouterId + } + STATUS current + DESCRIPTION + "An ospfTxRetransmit trap signifies than an + OSPF packet has been retransmitted on a virtual + interface. All packets that may be retransmit- + ted are associated with an LSDB entry. The LS + type, LS ID, and Router ID are used to identify + the LSDB entry." + ::= { ospfTraps 11 } + + + ospfOriginateLsa NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfLsdbAreaId, -- 0.0.0.0 for AS Externals + ospfLsdbType, + ospfLsdbLsid, + ospfLsdbRouterId + } + STATUS current + DESCRIPTION + "An ospfOriginateLsa trap signifies that a new + LSA has been originated by this router. This + trap should not be invoked for simple refreshes + of LSAs (which happesn every 30 minutes), but + instead will only be invoked when an LSA is + (re)originated due to a topology change. Addi- + tionally, this trap does not include LSAs that + are being flushed because they have reached + MaxAge." + ::= { ospfTraps 12 } + + + ospfMaxAgeLsa NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfLsdbAreaId, -- 0.0.0.0 for AS Externals + ospfLsdbType, + ospfLsdbLsid, + ospfLsdbRouterId + } + STATUS current + DESCRIPTION + "An ospfMaxAgeLsa trap signifies that one of + the LSA in the router's link-state database has + aged to MaxAge." + ::= { ospfTraps 13 } + + + ospfLsdbOverflow NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfExtLsdbLimit + } + STATUS current + DESCRIPTION + "An ospfLsdbOverflow trap signifies that the + number of LSAs in the router's link-state data- + base has exceeded ospfExtLsdbLimit." + ::= { ospfTraps 14 } + + + ospfLsdbApproachingOverflow NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfExtLsdbLimit + } + STATUS current + DESCRIPTION + "An ospfLsdbApproachingOverflow trap signifies + that the number of LSAs in the router's link- + state database has exceeded ninety percent of + ospfExtLsdbLimit." + ::= { ospfTraps 15 } + + +-- conformance information + +ospfTrapConformance OBJECT IDENTIFIER ::= { ospfTrap 3 } + +ospfTrapGroups OBJECT IDENTIFIER ::= { ospfTrapConformance 1 } +ospfTrapCompliances OBJECT IDENTIFIER ::= { ospfTrapConformance 2 } + +-- compliance statements + + ospfTrapCompliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement " + MODULE -- this module + MANDATORY-GROUPS { ospfTrapControlGroup } + + + GROUP ospfTrapControlGroup + DESCRIPTION + "This group is optional but recommended for all + OSPF systems" + ::= { ospfTrapCompliances 1 } + + +-- units of conformance + + ospfTrapControlGroup OBJECT-GROUP + OBJECTS { + ospfSetTrap, + ospfConfigErrorType, + ospfPacketType, + ospfPacketSrc + } + STATUS current + DESCRIPTION + "These objects are required to control traps + from OSPF systems." + ::= { ospfTrapGroups 1 } + + +END diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c new file mode 100644 index 00000000..ec3b153c --- /dev/null +++ b/ospfd/ospf_abr.c @@ -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 + +#include "thread.h" +#include "memory.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "vty.h" +#include "filter.h" +#include "plist.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ia.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_dump.h" + + +struct ospf_area_range * +ospf_area_range_new (struct prefix_ipv4 *p) +{ + struct ospf_area_range *range; + + range = XCALLOC (MTYPE_OSPF_AREA_RANGE, sizeof (struct ospf_area_range)); + range->addr = p->prefix; + range->masklen = p->prefixlen; + range->cost_config = OSPF_AREA_RANGE_COST_UNSPEC; + + return range; +} + +void +ospf_area_range_free (struct ospf_area_range *range) +{ + XFREE (MTYPE_OSPF_AREA_RANGE, range); +} + +void +ospf_area_range_add (struct ospf_area *area, struct ospf_area_range *range) +{ + struct route_node *rn; + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefixlen = range->masklen; + p.prefix = range->addr; + + rn = route_node_get (area->ranges, (struct prefix *)&p); + if (rn->info) + route_unlock_node (rn); + else + rn->info = range; +} + +void +ospf_area_range_delete (struct ospf_area *area, struct ospf_area_range *range) +{ + struct route_node *rn; + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefixlen = range->masklen; + p.prefix = range->addr; + + rn = route_node_lookup (area->ranges, (struct prefix *)&p); + if (rn) + { + ospf_area_range_free (rn->info); + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + } +} + +struct ospf_area_range * +ospf_area_range_lookup (struct ospf_area *area, struct prefix_ipv4 *p) +{ + struct route_node *rn; + + rn = route_node_lookup (area->ranges, (struct prefix *)p); + if (rn) + { + route_unlock_node (rn); + return rn->info; + } + return NULL; +} + +struct ospf_area_range * +ospf_area_range_lookup_next (struct ospf_area *area, struct in_addr *range_net, + int first) +{ + struct route_node *rn; + struct prefix_ipv4 p; + struct ospf_area_range *find; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.prefix = *range_net; + + if (first) + rn = route_top (area->ranges); + else + { + rn = route_node_get (area->ranges, (struct prefix *) &p); + rn = route_next (rn); + } + + for (; rn; rn = route_next (rn)) + if (rn->info) + break; + + if (rn && rn->info) + { + find = rn->info; + *range_net = rn->p.u.prefix4; + route_unlock_node (rn); + return find; + } + return NULL; +} + +struct ospf_area_range * +ospf_area_range_match (struct ospf_area *area, struct prefix_ipv4 *p) +{ + struct route_node *node; + + node = route_node_match (area->ranges, (struct prefix *) p); + if (node) + { + route_unlock_node (node); + return node->info; + } + return NULL; +} + +struct ospf_area_range * +ospf_area_range_match_any (struct ospf *ospf, struct prefix_ipv4 *p) +{ + struct ospf_area_range *range; + listnode node; + + for (node = listhead (ospf->areas); node; nextnode (node)) + if ((range = ospf_area_range_match (node->data, p))) + return range; + + return NULL; +} + +int +ospf_area_range_active (struct ospf_area_range *range) +{ + return range->specifics; +} + +int +ospf_area_actively_attached (struct ospf_area *area) +{ + return area->act_ints; +} + +int +ospf_area_range_set (struct ospf *ospf, struct in_addr area_id, + struct prefix_ipv4 *p, int advertise) +{ + struct ospf_area *area; + struct ospf_area_range *range; + int ret = OSPF_AREA_ID_FORMAT_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 index 00000000..3b385c32 --- /dev/null +++ b/ospfd/ospf_abr.h @@ -0,0 +1,84 @@ +/* + * OSPF ABR functions. + * Copyright (C) 1999 Alex Zinin + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_ABR_H +#define _ZEBRA_OSPF_ABR_H + +#define OSPF_ABR_TASK_DELAY 7 + +#define OSPF_AREA_RANGE_ADVERTISE (1 << 0) +#define OSPF_AREA_RANGE_SUBSTITUTE (1 << 1) + +/* Area range. */ +struct ospf_area_range +{ + /* Area range address. */ + struct in_addr addr; + + /* Area range masklen. */ + u_char masklen; + + /* Flags. */ + u_char flags; + + /* Number of more specific prefixes. */ + int specifics; + + /* Addr and masklen to substitute. */ + struct in_addr subst_addr; + u_char subst_masklen; + + /* Range cost. */ + u_int32_t cost; + + /* Configured range cost. */ + u_int32_t cost_config; +#define OSPF_AREA_RANGE_COST_UNSPEC -1 +}; + +/* Prototypes. */ +struct ospf_area_range *ospf_area_range_lookup (struct ospf_area *, + struct prefix_ipv4 *); +struct ospf_area_range *ospf_some_area_range_match (struct prefix_ipv4 *); +struct ospf_area_range *ospf_area_range_lookup_next (struct ospf_area *, + struct in_addr *, int); +int ospf_area_range_set (struct ospf *, struct in_addr, struct prefix_ipv4 *, + int); +int ospf_area_range_cost_set (struct ospf *, struct in_addr, + struct prefix_ipv4 *, u_int32_t); +int ospf_area_range_unset (struct ospf *, struct in_addr, + struct prefix_ipv4 *); +int ospf_area_range_substitute_set (struct ospf *, struct in_addr, + struct prefix_ipv4 *, + struct prefix_ipv4 *); +int ospf_area_range_substitute_unset (struct ospf *, struct in_addr, + struct prefix_ipv4 *); +struct ospf_area_range *ospf_area_range_match_any (struct ospf *, + struct prefix_ipv4 *); +int ospf_area_range_active (struct ospf_area_range *); +int ospf_act_bb_connection (); + +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 index 00000000..d13bbc43 --- /dev/null +++ b/ospfd/ospf_asbr.c @@ -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 + +#include "thread.h" +#include "memory.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "vty.h" +#include "filter.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_dump.h" + +/* Remove external route. */ +void +ospf_external_route_remove (struct 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; +} + + +/* 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; +} + + +/* 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 index 00000000..f368246d --- /dev/null +++ b/ospfd/ospf_asbr.h @@ -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 index 00000000..9194c566 --- /dev/null +++ b/ospfd/ospf_ase.c @@ -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 + +#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 index 00000000..f403e26d --- /dev/null +++ b/ospfd/ospf_ase.h @@ -0,0 +1,42 @@ +/* + * OSPF AS External route calculation. + * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_ASE_H +#define _ZEBRA_OSPF_ASE_H + + +struct ospf_route *ospf_find_asbr_route (struct 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 index 00000000..da2e0973 --- /dev/null +++ b/ospfd/ospf_dump.c @@ -0,0 +1,1673 @@ +/* + * OSPFd dump routine. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "linklist.h" +#include "thread.h" +#include "prefix.h" +#include "command.h" +#include "stream.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_network.h" + +struct message ospf_ism_state_msg[] = +{ + { ISM_DependUpon, "DependUpon" }, + { ISM_Down, "Down" }, + { ISM_Loopback, "Loopback" }, + { ISM_Waiting, "Waiting" }, + { ISM_PointToPoint, "Point-To-Point" }, + { ISM_DROther, "DROther" }, + { ISM_Backup, "Backup" }, + { ISM_DR, "DR" }, +}; +int ospf_ism_state_msg_max = OSPF_ISM_STATE_MAX; + +struct message ospf_nsm_state_msg[] = +{ + { NSM_DependUpon, "DependUpon" }, + { NSM_Down, "Down" }, + { NSM_Attempt, "Attempt" }, + { NSM_Init, "Init" }, + { NSM_TwoWay, "2-Way" }, + { NSM_ExStart, "ExStart" }, + { NSM_Exchange, "Exchange" }, + { NSM_Loading, "Loading" }, + { NSM_Full, "Full" }, +}; +int ospf_nsm_state_msg_max = OSPF_NSM_STATE_MAX; + +struct message ospf_lsa_type_msg[] = +{ + { OSPF_UNKNOWN_LSA, "unknown" }, + { OSPF_ROUTER_LSA, "router-LSA" }, + { OSPF_NETWORK_LSA, "network-LSA" }, + { OSPF_SUMMARY_LSA, "summary-LSA" }, + { OSPF_ASBR_SUMMARY_LSA, "summary-LSA" }, + { OSPF_AS_EXTERNAL_LSA, "AS-external-LSA" }, + { OSPF_GROUP_MEMBER_LSA, "GROUP MEMBER LSA" }, + { OSPF_AS_NSSA_LSA, "NSSA-LSA" }, + { 8, "Type-8 LSA" }, + { OSPF_OPAQUE_LINK_LSA, "Link-Local Opaque-LSA" }, + { OSPF_OPAQUE_AREA_LSA, "Area-Local Opaque-LSA" }, + { OSPF_OPAQUE_AS_LSA, "AS-external Opaque-LSA" }, +}; +int ospf_lsa_type_msg_max = OSPF_MAX_LSA; + +struct message ospf_link_state_id_type_msg[] = +{ + { OSPF_UNKNOWN_LSA, "(unknown)" }, + { OSPF_ROUTER_LSA, "" }, + { OSPF_NETWORK_LSA, "(address of Designated Router)" }, + { OSPF_SUMMARY_LSA, "(summary Network Number)" }, + { OSPF_ASBR_SUMMARY_LSA, "(AS Boundary Router address)" }, + { OSPF_AS_EXTERNAL_LSA, "(External Network Number)" }, + { OSPF_GROUP_MEMBER_LSA, "(Group membership information)" }, + { OSPF_AS_NSSA_LSA, "(External Network Number for NSSA)" }, + { 8, "(Type-8 LSID)" }, + { OSPF_OPAQUE_LINK_LSA, "(Link-Local Opaque-Type/ID)" }, + { OSPF_OPAQUE_AREA_LSA, "(Area-Local Opaque-Type/ID)" }, + { OSPF_OPAQUE_AS_LSA, "(AS-external Opaque-Type/ID)" }, +}; +int ospf_link_state_id_type_msg_max = OSPF_MAX_LSA; + +struct message ospf_redistributed_proto[] = +{ + { ZEBRA_ROUTE_SYSTEM, "System" }, + { ZEBRA_ROUTE_KERNEL, "Kernel" }, + { ZEBRA_ROUTE_CONNECT, "Connected" }, + { ZEBRA_ROUTE_STATIC, "Static" }, + { ZEBRA_ROUTE_RIP, "RIP" }, + { ZEBRA_ROUTE_RIPNG, "RIPng" }, + { ZEBRA_ROUTE_OSPF, "OSPF" }, + { ZEBRA_ROUTE_OSPF6, "OSPFv3" }, + { ZEBRA_ROUTE_BGP, "BGP" }, + { ZEBRA_ROUTE_MAX, "Default" }, +}; +int ospf_redistributed_proto_max = ZEBRA_ROUTE_MAX + 1; + +struct message ospf_network_type_msg[] = +{ + { OSPF_IFTYPE_NONE, "NONE" }, + { OSPF_IFTYPE_POINTOPOINT, "Point-to-Point" }, + { OSPF_IFTYPE_BROADCAST, "Broadcast" }, + { OSPF_IFTYPE_NBMA, "NBMA" }, + { OSPF_IFTYPE_POINTOMULTIPOINT, "Point-to-MultiPoint" }, + { OSPF_IFTYPE_VIRTUALLINK, "Virtual-Link" }, +}; +int ospf_network_type_msg_max = OSPF_IFTYPE_MAX; + +/* Configuration debug option variables. */ +unsigned long conf_debug_ospf_packet[5] = {0, 0, 0, 0, 0}; +unsigned long conf_debug_ospf_event = 0; +unsigned long conf_debug_ospf_ism = 0; +unsigned long conf_debug_ospf_nsm = 0; +unsigned long conf_debug_ospf_lsa = 0; +unsigned long conf_debug_ospf_zebra = 0; +unsigned long conf_debug_ospf_nssa = 0; + +/* Enable debug option variables -- valid only session. */ +unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0}; +unsigned long term_debug_ospf_event = 0; +unsigned long term_debug_ospf_ism = 0; +unsigned long term_debug_ospf_nsm = 0; +unsigned long term_debug_ospf_lsa = 0; +unsigned long term_debug_ospf_zebra = 0; +unsigned long term_debug_ospf_nssa = 0; + + +#define OSPF_AREA_STRING_MAXLEN 16 +char * +ospf_area_name_string (struct ospf_area *area) +{ + static char buf[OSPF_AREA_STRING_MAXLEN] = ""; + u_int32_t area_id; + + if (!area) + return "-"; + + area_id = ntohl (area->area_id.s_addr); + snprintf (buf, OSPF_AREA_STRING_MAXLEN, "%d.%d.%d.%d", + (area_id >> 24) & 0xff, (area_id >> 16) & 0xff, + (area_id >> 8) & 0xff, area_id & 0xff); + return buf; +} + +#define OSPF_AREA_DESC_STRING_MAXLEN 23 +char * +ospf_area_desc_string (struct ospf_area *area) +{ + static char buf[OSPF_AREA_DESC_STRING_MAXLEN] = ""; + u_char type; + + if (!area) + return "(incomplete)"; + + type = area->external_routing; + switch (type) + { + case OSPF_AREA_NSSA: + snprintf (buf, OSPF_AREA_DESC_STRING_MAXLEN, "%s [NSSA]", + ospf_area_name_string (area)); + break; + case OSPF_AREA_STUB: + snprintf (buf, OSPF_AREA_DESC_STRING_MAXLEN, "%s [Stub]", + ospf_area_name_string (area)); + break; + default: + return ospf_area_name_string (area); + break; + } + + return buf; +} + +#define OSPF_IF_STRING_MAXLEN 40 +char * +ospf_if_name_string (struct ospf_interface *oi) +{ + static char buf[OSPF_IF_STRING_MAXLEN] = ""; + u_int32_t ifaddr; + + if (!oi) + return "inactive"; + + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + return oi->ifp->name; + + ifaddr = ntohl (oi->address->u.prefix4.s_addr); + snprintf (buf, OSPF_IF_STRING_MAXLEN, + "%s:%d.%d.%d.%d", oi->ifp->name, + (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff, + (ifaddr >> 8) & 0xff, ifaddr & 0xff); + return buf; +} + + +void +ospf_nbr_state_message (struct ospf_neighbor *nbr, char *buf, size_t size) +{ + int state; + struct ospf_interface *oi = nbr->oi; + + if (IPV4_ADDR_SAME (&DR (oi), &nbr->address.u.prefix4)) + state = ISM_DR; + else if (IPV4_ADDR_SAME (&BDR (oi), &nbr->address.u.prefix4)) + state = ISM_Backup; + else + state = ISM_DROther; + + memset (buf, 0, size); + + snprintf (buf, size, "%s/%s", + LOOKUP (ospf_nsm_state_msg, nbr->state), + LOOKUP (ospf_ism_state_msg, state)); +} + +char * +ospf_timer_dump (struct thread *t, char *buf, size_t size) +{ + struct timeval now; + unsigned long h, m, s; + + if (!t) + return "inactive"; + + h = m = s = 0; + memset (buf, 0, size); + + gettimeofday (&now, NULL); + + s = t->u.sands.tv_sec - now.tv_sec; + if (s >= 3600) + { + h = s / 3600; + s -= h * 3600; + } + + if (s >= 60) + { + m = s / 60; + s -= m * 60; + } + + snprintf (buf, size, "%02ld:%02ld:%02ld", h, m, s); + + return buf; +} + +#define OSPF_OPTION_STR_MAXLEN 24 + +char * +ospf_options_dump (u_char options) +{ + static char buf[OSPF_OPTION_STR_MAXLEN]; + + snprintf (buf, OSPF_OPTION_STR_MAXLEN, "*|%s|%s|%s|%s|%s|%s|*", + (options & OSPF_OPTION_O) ? "O" : "-", + (options & OSPF_OPTION_DC) ? "DC" : "-", + (options & OSPF_OPTION_EA) ? "EA" : "-", + (options & OSPF_OPTION_NP) ? "N/P" : "-", + (options & OSPF_OPTION_MC) ? "MC" : "-", + (options & OSPF_OPTION_E) ? "E" : "-"); + + return buf; +} + +void +ospf_packet_hello_dump (struct stream *s, u_int16_t length) +{ + struct ospf_hello *hello; + int i; + + hello = (struct ospf_hello *) STREAM_PNT (s); + + zlog_info ("Hello"); + zlog_info (" NetworkMask %s", inet_ntoa (hello->network_mask)); + zlog_info (" HelloInterval %d", ntohs (hello->hello_interval)); + zlog_info (" Options %d (%s)", hello->options, + ospf_options_dump (hello->options)); + zlog_info (" RtrPriority %d", hello->priority); + zlog_info (" RtrDeadInterval %ld", (u_long)ntohl (hello->dead_interval)); + zlog_info (" DRouter %s", inet_ntoa (hello->d_router)); + zlog_info (" BDRouter %s", inet_ntoa (hello->bd_router)); + + length -= OSPF_HEADER_SIZE + OSPF_HELLO_MIN_SIZE; + zlog_info (" # Neighbors %d", length / 4); + for (i = 0; length > 0; i++, length -= sizeof (struct in_addr)) + zlog_info (" Neighbor %s", inet_ntoa (hello->neighbors[i])); +} + +char * +ospf_dd_flags_dump (u_char flags, char *buf, size_t size) +{ + memset (buf, 0, size); + + snprintf (buf, size, "%s|%s|%s", + (flags & OSPF_DD_FLAG_I) ? "I" : "-", + (flags & OSPF_DD_FLAG_M) ? "M" : "-", + (flags & OSPF_DD_FLAG_MS) ? "MS" : "-"); + + return buf; +} + +void +ospf_lsa_header_dump (struct lsa_header *lsah) +{ + zlog_info (" LSA Header"); + zlog_info (" LS age %d", ntohs (lsah->ls_age)); + zlog_info (" Options %d (%s)", lsah->options, + ospf_options_dump (lsah->options)); + zlog_info (" LS type %d (%s)", lsah->type, + LOOKUP (ospf_lsa_type_msg, lsah->type)); + zlog_info (" Link State ID %s", inet_ntoa (lsah->id)); + zlog_info (" Advertising Router %s", inet_ntoa (lsah->adv_router)); + zlog_info (" LS sequence number 0x%lx", (u_long)ntohl (lsah->ls_seqnum)); + zlog_info (" LS checksum 0x%x", ntohs (lsah->checksum)); + zlog_info (" length %d", ntohs (lsah->length)); +} + +char * +ospf_router_lsa_flags_dump (u_char flags, char *buf, size_t size) +{ + memset (buf, 0, size); + + snprintf (buf, size, "%s|%s|%s", + (flags & ROUTER_LSA_VIRTUAL) ? "V" : "-", + (flags & ROUTER_LSA_EXTERNAL) ? "E" : "-", + (flags & ROUTER_LSA_BORDER) ? "B" : "-"); + + return buf; +} + +void +ospf_router_lsa_dump (struct stream *s, u_int16_t length) +{ + char buf[BUFSIZ]; + struct router_lsa *rl; + int i, len; + + rl = (struct router_lsa *) STREAM_PNT (s); + + zlog_info (" Router-LSA"); + zlog_info (" flags %s", + ospf_router_lsa_flags_dump (rl->flags, buf, BUFSIZ)); + zlog_info (" # links %d", ntohs (rl->links)); + + len = ntohs (rl->header.length) - OSPF_LSA_HEADER_SIZE - 4; + for (i = 0; len > 0; i++) + { + zlog_info (" Link ID %s", inet_ntoa (rl->link[i].link_id)); + zlog_info (" Link Data %s", inet_ntoa (rl->link[i].link_data)); + zlog_info (" Type %d", (u_char) rl->link[i].type); + zlog_info (" TOS %d", (u_char) rl->link[i].tos); + zlog_info (" metric %d", ntohs (rl->link[i].metric)); + + len -= 12; + } +} + +void +ospf_network_lsa_dump (struct stream *s, u_int16_t length) +{ + struct network_lsa *nl; + int i, cnt; + + nl = (struct network_lsa *) STREAM_PNT (s); + cnt = (ntohs (nl->header.length) - (OSPF_LSA_HEADER_SIZE + 4)) / 4; + + zlog_info (" Network-LSA"); + /* + zlog_info ("LSA total size %d", ntohs (nl->header.length)); + zlog_info ("Network-LSA size %d", + ntohs (nl->header.length) - OSPF_LSA_HEADER_SIZE); + */ + zlog_info (" Network Mask %s", inet_ntoa (nl->mask)); + zlog_info (" # Attached Routers %d", cnt); + for (i = 0; i < cnt; i++) + zlog_info (" Attached Router %s", inet_ntoa (nl->routers[i])); +} + +void +ospf_summary_lsa_dump (struct stream *s, u_int16_t length) +{ + struct summary_lsa *sl; + int size; + int i; + + sl = (struct summary_lsa *) STREAM_PNT (s); + + zlog_info (" Summary-LSA"); + zlog_info (" Network Mask %s", inet_ntoa (sl->mask)); + + size = ntohs (sl->header.length) - OSPF_LSA_HEADER_SIZE - 4; + for (i = 0; size > 0; size -= 4, i++) + zlog_info (" TOS=%d metric %d", sl->tos, + GET_METRIC (sl->metric)); +} + +void +ospf_as_external_lsa_dump (struct stream *s, u_int16_t length) +{ + struct as_external_lsa *al; + int size; + int i; + + al = (struct as_external_lsa *) STREAM_PNT (s); + + zlog_info (" AS-external-LSA"); + zlog_info (" Network Mask %s", inet_ntoa (al->mask)); + + size = ntohs (al->header.length) - OSPF_LSA_HEADER_SIZE -4; + for (i = 0; size > 0; size -= 12, i++) + { + zlog_info (" bit %s TOS=%d metric %d", + IS_EXTERNAL_METRIC (al->e[i].tos) ? "E" : "-", + al->e[i].tos & 0x7f, GET_METRIC (al->e[i].metric)); + zlog_info (" Forwarding address %s", inet_ntoa (al->e[i].fwd_addr)); + zlog_info (" External Route Tag %d", al->e[i].route_tag); + } +} + +void +ospf_lsa_header_list_dump (struct stream *s, u_int16_t length) +{ + struct lsa_header *lsa; + + zlog_info (" # LSA Headers %d", length / OSPF_LSA_HEADER_SIZE); + + /* LSA Headers. */ + while (length > 0) + { + lsa = (struct lsa_header *) STREAM_PNT (s); + ospf_lsa_header_dump (lsa); + + stream_forward (s, OSPF_LSA_HEADER_SIZE); + length -= OSPF_LSA_HEADER_SIZE; + } +} + +void +ospf_packet_db_desc_dump (struct stream *s, u_int16_t length) +{ + struct ospf_db_desc *dd; + char dd_flags[8]; + + u_int32_t gp; + + gp = stream_get_getp (s); + dd = (struct ospf_db_desc *) STREAM_PNT (s); + + zlog_info ("Database Description"); + zlog_info (" Interface MTU %d", ntohs (dd->mtu)); + zlog_info (" Options %d (%s)", dd->options, + ospf_options_dump (dd->options)); + zlog_info (" Flags %d (%s)", dd->flags, + ospf_dd_flags_dump (dd->flags, dd_flags, sizeof dd_flags)); + zlog_info (" Sequence Number 0x%08lx", (u_long)ntohl (dd->dd_seqnum)); + + length -= OSPF_HEADER_SIZE + OSPF_DB_DESC_MIN_SIZE; + + stream_forward (s, OSPF_DB_DESC_MIN_SIZE); + + ospf_lsa_header_list_dump (s, length); + + stream_set_getp (s, gp); +} + +void +ospf_packet_ls_req_dump (struct stream *s, u_int16_t length) +{ + u_int32_t sp; + u_int32_t ls_type; + struct in_addr ls_id; + struct in_addr adv_router; + + sp = stream_get_getp (s); + + length -= OSPF_HEADER_SIZE; + + zlog_info ("Link State Request"); + zlog_info (" # Requests %d", length / 12); + + for (; length > 0; length -= 12) + { + ls_type = stream_getl (s); + ls_id.s_addr = stream_get_ipv4 (s); + adv_router.s_addr = stream_get_ipv4 (s); + + zlog_info (" LS type %d", ls_type); + zlog_info (" Link State ID %s", inet_ntoa (ls_id)); + zlog_info (" Advertising Router %s", + inet_ntoa (adv_router)); + } + + stream_set_getp (s, sp); +} + +void +ospf_packet_ls_upd_dump (struct stream *s, u_int16_t length) +{ + u_int32_t sp; + struct lsa_header *lsa; + int lsa_len; + u_int32_t count; + + length -= OSPF_HEADER_SIZE; + + sp = stream_get_getp (s); + + count = stream_getl (s); + length -= 4; + + zlog_info ("Link State Update"); + zlog_info (" # LSAs %d", count); + + while (length > 0 && count > 0) + { + if (length < OSPF_HEADER_SIZE || length % 4 != 0) + { + zlog_info (" Remaining %d bytes; Incorrect length.", length); + break; + } + + lsa = (struct lsa_header *) STREAM_PNT (s); + lsa_len = ntohs (lsa->length); + ospf_lsa_header_dump (lsa); + + switch (lsa->type) + { + case OSPF_ROUTER_LSA: + ospf_router_lsa_dump (s, length); + break; + case OSPF_NETWORK_LSA: + ospf_network_lsa_dump (s, length); + break; + case OSPF_SUMMARY_LSA: + case OSPF_ASBR_SUMMARY_LSA: + ospf_summary_lsa_dump (s, length); + break; + case OSPF_AS_EXTERNAL_LSA: + ospf_as_external_lsa_dump (s, length); + break; +#ifdef HAVE_NSSA + case OSPF_AS_NSSA_LSA: + /* XXX */ + break; +#endif /* HAVE_NSSA */ +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: + ospf_opaque_lsa_dump (s, length); + break; +#endif /* HAVE_OPAQUE_LSA */ + default: + break; + } + + stream_forward (s, lsa_len); + length -= lsa_len; + count--; + } + + stream_set_getp (s, sp); +} + +void +ospf_packet_ls_ack_dump (struct stream *s, u_int16_t length) +{ + u_int32_t sp; + + length -= OSPF_HEADER_SIZE; + sp = stream_get_getp (s); + + zlog_info ("Link State Acknowledgment"); + ospf_lsa_header_list_dump (s, length); + + stream_set_getp (s, sp); +} + +void +ospf_ip_header_dump (struct stream *s) +{ + u_int16_t length; + struct ip *iph; + + iph = (struct ip *) STREAM_PNT (s); + +#ifdef GNU_LINUX + length = ntohs (iph->ip_len); +#else /* GNU_LINUX */ + length = iph->ip_len; +#endif /* GNU_LINUX */ + + /* IP Header dump. */ + zlog_info ("ip_v %d", iph->ip_v); + zlog_info ("ip_hl %d", iph->ip_hl); + zlog_info ("ip_tos %d", iph->ip_tos); + zlog_info ("ip_len %d", length); + zlog_info ("ip_id %u", (u_int32_t) iph->ip_id); + zlog_info ("ip_off %u", (u_int32_t) iph->ip_off); + zlog_info ("ip_ttl %d", iph->ip_ttl); + zlog_info ("ip_p %d", iph->ip_p); + /* There is a report that Linux 2.0.37 does not have ip_sum. But + I'm not sure. Temporary commented out by kunihiro. */ + /* zlog_info ("ip_sum 0x%x", (u_int32_t) ntohs (iph->ip_sum)); */ + zlog_info ("ip_src %s", inet_ntoa (iph->ip_src)); + zlog_info ("ip_dst %s", inet_ntoa (iph->ip_dst)); +} + +void +ospf_header_dump (struct ospf_header *ospfh) +{ + char buf[9]; + + zlog_info ("Header"); + zlog_info (" Version %d", ospfh->version); + zlog_info (" Type %d (%s)", ospfh->type, + ospf_packet_type_str[ospfh->type]); + zlog_info (" Packet Len %d", ntohs (ospfh->length)); + zlog_info (" Router ID %s", inet_ntoa (ospfh->router_id)); + zlog_info (" Area ID %s", inet_ntoa (ospfh->area_id)); + zlog_info (" Checksum 0x%x", ntohs (ospfh->checksum)); + zlog_info (" AuType %d", ntohs (ospfh->auth_type)); + + switch (ntohs (ospfh->auth_type)) + { + case OSPF_AUTH_NULL: + break; + case OSPF_AUTH_SIMPLE: + memset (buf, 0, 9); + strncpy (buf, ospfh->u.auth_data, 8); + zlog_info (" Simple Password %s", buf); + break; + case OSPF_AUTH_CRYPTOGRAPHIC: + zlog_info (" Cryptographic Authentication"); + zlog_info (" Key ID %d", ospfh->u.crypt.key_id); + zlog_info (" Auth Data Len %d", ospfh->u.crypt.auth_data_len); + zlog_info (" Sequence number %ld", + (u_long)ntohl (ospfh->u.crypt.crypt_seqnum)); + break; + default: + zlog_info ("* This is not supported authentication type"); + break; + } + +} + +void +ospf_packet_dump (struct stream *s) +{ + struct ospf_header *ospfh; + unsigned long gp; + + /* Preserve pointer. */ + gp = stream_get_getp (s); + + /* OSPF Header dump. */ + ospfh = (struct ospf_header *) STREAM_PNT (s); + + /* Until detail flag is set, return. */ + if (!(term_debug_ospf_packet[ospfh->type - 1] & OSPF_DEBUG_DETAIL)) + return; + + /* Show OSPF header detail. */ + ospf_header_dump (ospfh); + stream_forward (s, OSPF_HEADER_SIZE); + + switch (ospfh->type) + { + case OSPF_MSG_HELLO: + ospf_packet_hello_dump (s, ntohs (ospfh->length)); + break; + case OSPF_MSG_DB_DESC: + ospf_packet_db_desc_dump (s, ntohs (ospfh->length)); + break; + case OSPF_MSG_LS_REQ: + ospf_packet_ls_req_dump (s, ntohs (ospfh->length)); + break; + case OSPF_MSG_LS_UPD: + ospf_packet_ls_upd_dump (s, ntohs (ospfh->length)); + break; + case OSPF_MSG_LS_ACK: + ospf_packet_ls_ack_dump (s, ntohs (ospfh->length)); + break; + default: + break; + } + + stream_set_getp (s, gp); +} + + +/* + [no] debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) + [send|recv [detail]] +*/ +DEFUN (debug_ospf_packet, + debug_ospf_packet_all_cmd, + "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)", + DEBUG_STR + OSPF_STR + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n") +{ + int type = 0; + int flag = 0; + int i; + + assert (argc > 0); + + /* Check packet type. */ + if (strncmp (argv[0], "h", 1) == 0) + type = OSPF_DEBUG_HELLO; + else if (strncmp (argv[0], "d", 1) == 0) + type = OSPF_DEBUG_DB_DESC; + else if (strncmp (argv[0], "ls-r", 4) == 0) + type = OSPF_DEBUG_LS_REQ; + else if (strncmp (argv[0], "ls-u", 4) == 0) + type = OSPF_DEBUG_LS_UPD; + else if (strncmp (argv[0], "ls-a", 4) == 0) + type = OSPF_DEBUG_LS_ACK; + else if (strncmp (argv[0], "a", 1) == 0) + type = OSPF_DEBUG_ALL; + + /* Default, both send and recv. */ + if (argc == 1) + flag = OSPF_DEBUG_SEND | OSPF_DEBUG_RECV; + + /* send or recv. */ + if (argc >= 2) + { + if (strncmp (argv[1], "s", 1) == 0) + flag = OSPF_DEBUG_SEND; + else if (strncmp (argv[1], "r", 1) == 0) + flag = OSPF_DEBUG_RECV; + else if (strncmp (argv[1], "d", 1) == 0) + flag = OSPF_DEBUG_SEND | OSPF_DEBUG_RECV | OSPF_DEBUG_DETAIL; + } + + /* detail. */ + if (argc == 3) + if (strncmp (argv[2], "d", 1) == 0) + flag |= OSPF_DEBUG_DETAIL; + + for (i = 0; i < 5; i++) + if (type & (0x01 << i)) + { + if (vty->node == CONFIG_NODE) + DEBUG_PACKET_ON (i, flag); + else + TERM_DEBUG_PACKET_ON (i, flag); + } + + return CMD_SUCCESS; +} + +ALIAS (debug_ospf_packet, + debug_ospf_packet_send_recv_cmd, + "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv|detail)", + "Debugging functions\n" + "OSPF information\n" + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n" + "Packet sent\n" + "Packet received\n" + "Detail information\n") + +ALIAS (debug_ospf_packet, + debug_ospf_packet_send_recv_detail_cmd, + "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) (detail|)", + "Debugging functions\n" + "OSPF information\n" + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n" + "Packet sent\n" + "Packet received\n" + "Detail Information\n") + + +DEFUN (no_debug_ospf_packet, + no_debug_ospf_packet_all_cmd, + "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n") +{ + int type = 0; + int flag = 0; + int i; + + assert (argc > 0); + + /* Check packet type. */ + if (strncmp (argv[0], "h", 1) == 0) + type = OSPF_DEBUG_HELLO; + else if (strncmp (argv[0], "d", 1) == 0) + type = OSPF_DEBUG_DB_DESC; + else if (strncmp (argv[0], "ls-r", 4) == 0) + type = OSPF_DEBUG_LS_REQ; + else if (strncmp (argv[0], "ls-u", 4) == 0) + type = OSPF_DEBUG_LS_UPD; + else if (strncmp (argv[0], "ls-a", 4) == 0) + type = OSPF_DEBUG_LS_ACK; + else if (strncmp (argv[0], "a", 1) == 0) + type = OSPF_DEBUG_ALL; + + /* Default, both send and recv. */ + if (argc == 1) + flag = OSPF_DEBUG_SEND | OSPF_DEBUG_RECV | OSPF_DEBUG_DETAIL ; + + /* send or recv. */ + if (argc == 2) + { + if (strncmp (argv[1], "s", 1) == 0) + flag = OSPF_DEBUG_SEND | OSPF_DEBUG_DETAIL; + else if (strncmp (argv[1], "r", 1) == 0) + flag = OSPF_DEBUG_RECV | OSPF_DEBUG_DETAIL; + else if (strncmp (argv[1], "d", 1) == 0) + flag = OSPF_DEBUG_DETAIL; + } + + /* detail. */ + if (argc == 3) + if (strncmp (argv[2], "d", 1) == 0) + flag = OSPF_DEBUG_DETAIL; + + for (i = 0; i < 5; i++) + if (type & (0x01 << i)) + { + if (vty->node == CONFIG_NODE) + DEBUG_PACKET_OFF (i, flag); + else + TERM_DEBUG_PACKET_OFF (i, flag); + } + +#ifdef DEBUG + for (i = 0; i < 5; i++) + zlog_info ("flag[%d] = %d", i, ospf_debug_packet[i]); +#endif /* DEBUG */ + + return CMD_SUCCESS; +} + +ALIAS (no_debug_ospf_packet, + no_debug_ospf_packet_send_recv_cmd, + "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv|detail)", + NO_STR + "Debugging functions\n" + "OSPF information\n" + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n" + "Packet sent\n" + "Packet received\n" + "Detail Information\n") + +ALIAS (no_debug_ospf_packet, + no_debug_ospf_packet_send_recv_detail_cmd, + "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) (detail|)", + NO_STR + "Debugging functions\n" + "OSPF information\n" + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n" + "Packet sent\n" + "Packet received\n" + "Detail Information\n") + + +DEFUN (debug_ospf_ism, + debug_ospf_ism_cmd, + "debug ospf ism", + DEBUG_STR + OSPF_STR + "OSPF Interface State Machine\n") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_ON (ism, ISM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + DEBUG_ON (ism, ISM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + DEBUG_ON (ism, ISM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + DEBUG_ON (ism, ISM_TIMERS); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_ON (ism, ISM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + TERM_DEBUG_ON (ism, ISM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + TERM_DEBUG_ON (ism, ISM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + TERM_DEBUG_ON (ism, ISM_TIMERS); + } + + return CMD_SUCCESS; +} + +ALIAS (debug_ospf_ism, + debug_ospf_ism_sub_cmd, + "debug ospf ism (status|events|timers)", + DEBUG_STR + OSPF_STR + "OSPF Interface State Machine\n" + "ISM Status Information\n" + "ISM Event Information\n" + "ISM TImer Information\n") + +DEFUN (no_debug_ospf_ism, + no_debug_ospf_ism_cmd, + "no debug ospf ism", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF Interface State Machine") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_OFF (ism, ISM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + DEBUG_OFF (ism, ISM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + DEBUG_OFF (ism, ISM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + DEBUG_OFF (ism, ISM_TIMERS); + } + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_OFF (ism, ISM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + TERM_DEBUG_OFF (ism, ISM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + TERM_DEBUG_OFF (ism, ISM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + TERM_DEBUG_OFF (ism, ISM_TIMERS); + } + + return CMD_SUCCESS; +} + +ALIAS (no_debug_ospf_ism, + no_debug_ospf_ism_sub_cmd, + "no debug ospf ism (status|events|timers)", + NO_STR + "Debugging functions\n" + "OSPF information\n" + "OSPF Interface State Machine\n" + "ISM Status Information\n" + "ISM Event Information\n" + "ISM Timer Information\n") + + +DEFUN (debug_ospf_nsm, + debug_ospf_nsm_cmd, + "debug ospf nsm", + DEBUG_STR + OSPF_STR + "OSPF Neighbor State Machine\n") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_ON (nsm, NSM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + DEBUG_ON (nsm, NSM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + DEBUG_ON (nsm, NSM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + DEBUG_ON (nsm, NSM_TIMERS); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_ON (nsm, NSM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + TERM_DEBUG_ON (nsm, NSM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + TERM_DEBUG_ON (nsm, NSM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + TERM_DEBUG_ON (nsm, NSM_TIMERS); + } + + return CMD_SUCCESS; +} + +ALIAS (debug_ospf_nsm, + debug_ospf_nsm_sub_cmd, + "debug ospf nsm (status|events|timers)", + DEBUG_STR + OSPF_STR + "OSPF Neighbor State Machine\n" + "NSM Status Information\n" + "NSM Event Information\n" + "NSM Timer Information\n") + +DEFUN (no_debug_ospf_nsm, + no_debug_ospf_nsm_cmd, + "no debug ospf nsm", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF Neighbor State Machine") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_OFF (nsm, NSM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + DEBUG_OFF (nsm, NSM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + DEBUG_OFF (nsm, NSM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + DEBUG_OFF (nsm, NSM_TIMERS); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_OFF (nsm, NSM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + TERM_DEBUG_OFF (nsm, NSM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + TERM_DEBUG_OFF (nsm, NSM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + TERM_DEBUG_OFF (nsm, NSM_TIMERS); + } + + return CMD_SUCCESS; +} + +ALIAS (no_debug_ospf_nsm, + no_debug_ospf_nsm_sub_cmd, + "no debug ospf nsm (status|events|timers)", + NO_STR + "Debugging functions\n" + "OSPF information\n" + "OSPF Interface State Machine\n" + "NSM Status Information\n" + "NSM Event Information\n" + "NSM Timer Information\n") + + +DEFUN (debug_ospf_lsa, + debug_ospf_lsa_cmd, + "debug ospf lsa", + DEBUG_STR + OSPF_STR + "OSPF Link State Advertisement\n") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_ON (lsa, LSA); + else if (argc == 1) + { + if (strncmp (argv[0], "g", 1) == 0) + DEBUG_ON (lsa, LSA_GENERATE); + else if (strncmp (argv[0], "f", 1) == 0) + DEBUG_ON (lsa, LSA_FLOODING); + else if (strncmp (argv[0], "i", 1) == 0) + DEBUG_ON (lsa, LSA_INSTALL); + else if (strncmp (argv[0], "r", 1) == 0) + DEBUG_ON (lsa, LSA_REFRESH); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_ON (lsa, LSA); + else if (argc == 1) + { + if (strncmp (argv[0], "g", 1) == 0) + TERM_DEBUG_ON (lsa, LSA_GENERATE); + else if (strncmp (argv[0], "f", 1) == 0) + TERM_DEBUG_ON (lsa, LSA_FLOODING); + else if (strncmp (argv[0], "i", 1) == 0) + TERM_DEBUG_ON (lsa, LSA_INSTALL); + else if (strncmp (argv[0], "r", 1) == 0) + TERM_DEBUG_ON (lsa, LSA_REFRESH); + } + + return CMD_SUCCESS; +} + +ALIAS (debug_ospf_lsa, + debug_ospf_lsa_sub_cmd, + "debug ospf lsa (generate|flooding|install|refresh)", + DEBUG_STR + OSPF_STR + "OSPF Link State Advertisement\n" + "LSA Generation\n" + "LSA Flooding\n" + "LSA Install/Delete\n" + "LSA Refresh\n") + +DEFUN (no_debug_ospf_lsa, + no_debug_ospf_lsa_cmd, + "no debug ospf lsa", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF Link State Advertisement\n") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_OFF (lsa, LSA); + else if (argc == 1) + { + if (strncmp (argv[0], "g", 1) == 0) + DEBUG_OFF (lsa, LSA_GENERATE); + else if (strncmp (argv[0], "f", 1) == 0) + DEBUG_OFF (lsa, LSA_FLOODING); + else if (strncmp (argv[0], "i", 1) == 0) + DEBUG_OFF (lsa, LSA_INSTALL); + else if (strncmp (argv[0], "r", 1) == 0) + DEBUG_OFF (lsa, LSA_REFRESH); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_OFF (lsa, LSA); + else if (argc == 1) + { + if (strncmp (argv[0], "g", 1) == 0) + TERM_DEBUG_OFF (lsa, LSA_GENERATE); + else if (strncmp (argv[0], "f", 1) == 0) + TERM_DEBUG_OFF (lsa, LSA_FLOODING); + else if (strncmp (argv[0], "i", 1) == 0) + TERM_DEBUG_OFF (lsa, LSA_INSTALL); + else if (strncmp (argv[0], "r", 1) == 0) + TERM_DEBUG_OFF (lsa, LSA_REFRESH); + } + + return CMD_SUCCESS; +} + +ALIAS (no_debug_ospf_lsa, + no_debug_ospf_lsa_sub_cmd, + "no debug ospf lsa (generate|flooding|install|refresh)", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF Link State Advertisement\n" + "LSA Generation\n" + "LSA Flooding\n" + "LSA Install/Delete\n" + "LSA Refres\n") + + +DEFUN (debug_ospf_zebra, + debug_ospf_zebra_cmd, + "debug ospf zebra", + DEBUG_STR + OSPF_STR + "OSPF Zebra information\n") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_ON (zebra, ZEBRA); + else if (argc == 1) + { + if (strncmp (argv[0], "i", 1) == 0) + DEBUG_ON (zebra, ZEBRA_INTERFACE); + else if (strncmp (argv[0], "r", 1) == 0) + DEBUG_ON (zebra, ZEBRA_REDISTRIBUTE); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_ON (zebra, ZEBRA); + else if (argc == 1) + { + if (strncmp (argv[0], "i", 1) == 0) + TERM_DEBUG_ON (zebra, ZEBRA_INTERFACE); + else if (strncmp (argv[0], "r", 1) == 0) + TERM_DEBUG_ON (zebra, ZEBRA_REDISTRIBUTE); + } + + return CMD_SUCCESS; +} + +ALIAS (debug_ospf_zebra, + debug_ospf_zebra_sub_cmd, + "debug ospf zebra (interface|redistribute)", + DEBUG_STR + OSPF_STR + "OSPF Zebra information\n" + "Zebra interface\n" + "Zebra redistribute\n") + +DEFUN (no_debug_ospf_zebra, + no_debug_ospf_zebra_cmd, + "no debug ospf zebra", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF Zebra information\n") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_OFF (zebra, ZEBRA); + else if (argc == 1) + { + if (strncmp (argv[0], "i", 1) == 0) + DEBUG_OFF (zebra, ZEBRA_INTERFACE); + else if (strncmp (argv[0], "r", 1) == 0) + DEBUG_OFF (zebra, ZEBRA_REDISTRIBUTE); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_OFF (zebra, ZEBRA); + else if (argc == 1) + { + if (strncmp (argv[0], "i", 1) == 0) + TERM_DEBUG_OFF (zebra, ZEBRA_INTERFACE); + else if (strncmp (argv[0], "r", 1) == 0) + TERM_DEBUG_OFF (zebra, ZEBRA_REDISTRIBUTE); + } + + return CMD_SUCCESS; +} + +ALIAS (no_debug_ospf_zebra, + no_debug_ospf_zebra_sub_cmd, + "no debug ospf zebra (interface|redistribute)", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF Zebra information\n" + "Zebra interface\n" + "Zebra redistribute\n") + +DEFUN (debug_ospf_event, + debug_ospf_event_cmd, + "debug ospf event", + DEBUG_STR + OSPF_STR + "OSPF event information\n") +{ + if (vty->node == CONFIG_NODE) + CONF_DEBUG_ON (event, EVENT); + TERM_DEBUG_ON (event, EVENT); + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf_event, + no_debug_ospf_event_cmd, + "no debug ospf event", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF event information\n") +{ + if (vty->node == CONFIG_NODE) + CONF_DEBUG_OFF (event, EVENT); + TERM_DEBUG_OFF (event, EVENT); + return CMD_SUCCESS; +} + +DEFUN (debug_ospf_nssa, + debug_ospf_nssa_cmd, + "debug ospf nssa", + DEBUG_STR + OSPF_STR + "OSPF nssa information\n") +{ + if (vty->node == CONFIG_NODE) + CONF_DEBUG_ON (nssa, NSSA); + TERM_DEBUG_ON (nssa, NSSA); + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf_nssa, + no_debug_ospf_nssa_cmd, + "no debug ospf nssa", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF nssa information\n") +{ + if (vty->node == CONFIG_NODE) + CONF_DEBUG_OFF (nssa, NSSA); + TERM_DEBUG_OFF (nssa, NSSA); + return CMD_SUCCESS; +} + + +DEFUN (show_debugging_ospf, + show_debugging_ospf_cmd, + "show debugging ospf", + SHOW_STR + DEBUG_STR + OSPF_STR) +{ + int i; + + vty_out (vty, "Zebra debugging status:%s", VTY_NEWLINE); + + /* Show debug status for ISM. */ + if (IS_DEBUG_OSPF (ism, ISM) == OSPF_DEBUG_ISM) + vty_out (vty, " OSPF ISM debugging is on%s", VTY_NEWLINE); + else + { + if (IS_DEBUG_OSPF (ism, ISM_STATUS)) + vty_out (vty, " OSPF ISM status debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (ism, ISM_EVENTS)) + vty_out (vty, " OSPF ISM event debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (ism, ISM_TIMERS)) + vty_out (vty, " OSPF ISM timer debugging is on%s", VTY_NEWLINE); + } + + /* Show debug status for NSM. */ + if (IS_DEBUG_OSPF (nsm, NSM) == OSPF_DEBUG_NSM) + vty_out (vty, " OSPF NSM debugging is on%s", VTY_NEWLINE); + else + { + if (IS_DEBUG_OSPF (nsm, NSM_STATUS)) + vty_out (vty, " OSPF NSM status debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (nsm, NSM_EVENTS)) + vty_out (vty, " OSPF NSM event debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (nsm, NSM_TIMERS)) + vty_out (vty, " OSPF NSM timer debugging is on%s", VTY_NEWLINE); + } + + /* Show debug status for OSPF Packets. */ + for (i = 0; i < 5; i++) + if (IS_DEBUG_OSPF_PACKET (i, SEND) && IS_DEBUG_OSPF_PACKET (i, RECV)) + { + vty_out (vty, " OSPF packet %s%s debugging is on%s", + ospf_packet_type_str[i + 1], + IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "", + VTY_NEWLINE); + } + else + { + if (IS_DEBUG_OSPF_PACKET (i, SEND)) + vty_out (vty, " OSPF packet %s send%s debugging is on%s", + ospf_packet_type_str[i + 1], + IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "", + VTY_NEWLINE); + if (IS_DEBUG_OSPF_PACKET (i, RECV)) + vty_out (vty, " OSPF packet %s receive%s debugging is on%s", + ospf_packet_type_str[i + 1], + IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "", + VTY_NEWLINE); + } + + /* Show debug status for OSPF LSAs. */ + if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) + vty_out (vty, " OSPF LSA debugging is on%s", VTY_NEWLINE); + else + { + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + vty_out (vty, " OSPF LSA generation debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + vty_out (vty, " OSPF LSA flooding debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) + vty_out (vty, " OSPF LSA install debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) + vty_out (vty, " OSPF LSA refresh debugging is on%s", VTY_NEWLINE); + } + + /* Show debug status for Zebra. */ + if (IS_DEBUG_OSPF (zebra, ZEBRA) == OSPF_DEBUG_ZEBRA) + vty_out (vty, " OSPF Zebra debugging is on%s", VTY_NEWLINE); + else + { + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + vty_out (vty, " OSPF Zebra interface debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + vty_out (vty, " OSPF Zebra redistribute debugging is on%s", VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +/* Debug node. */ +struct cmd_node debug_node = +{ + DEBUG_NODE, + "" +}; + +int +config_write_debug (struct vty *vty) +{ + int write = 0; + int i, r; + + char *type_str[] = {"hello", "dd", "ls-request", "ls-update", "ls-ack"}; + char *detail_str[] = {"", " send", " recv", "", " detail", + " send detail", " recv detail", " detail"}; + + /* debug ospf ism (status|events|timers). */ + if (IS_CONF_DEBUG_OSPF (ism, ISM) == OSPF_DEBUG_ISM) + vty_out (vty, "debug ospf ism%s", VTY_NEWLINE); + else + { + if (IS_CONF_DEBUG_OSPF (ism, ISM_STATUS)) + vty_out (vty, "debug ospf ism status%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (ism, ISM_EVENTS)) + vty_out (vty, "debug ospf ism event%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (ism, ISM_TIMERS)) + vty_out (vty, "debug ospf ism timer%s", VTY_NEWLINE); + } + + /* debug ospf nsm (status|events|timers). */ + if (IS_CONF_DEBUG_OSPF (nsm, NSM) == OSPF_DEBUG_NSM) + vty_out (vty, "debug ospf nsm%s", VTY_NEWLINE); + else + { + if (IS_CONF_DEBUG_OSPF (nsm, NSM_STATUS)) + vty_out (vty, "debug ospf ism status%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (nsm, NSM_EVENTS)) + vty_out (vty, "debug ospf nsm event%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (nsm, NSM_TIMERS)) + vty_out (vty, "debug ospf nsm timer%s", VTY_NEWLINE); + } + + /* debug ospf lsa (generate|flooding|install|refresh). */ + if (IS_CONF_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) + vty_out (vty, "debug ospf lsa%s", VTY_NEWLINE); + else + { + if (IS_CONF_DEBUG_OSPF (lsa, LSA_GENERATE)) + vty_out (vty, "debug ospf lsa generate%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (lsa, LSA_FLOODING)) + vty_out (vty, "debug ospf lsa flooding%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (lsa, LSA_INSTALL)) + vty_out (vty, "debug ospf lsa install%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (lsa, LSA_REFRESH)) + vty_out (vty, "debug ospf lsa refresh%s", VTY_NEWLINE); + + write = 1; + } + + /* debug ospf zebra (interface|redistribute). */ + if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA) == OSPF_DEBUG_ZEBRA) + vty_out (vty, "debug ospf zebra%s", VTY_NEWLINE); + else + { + if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + vty_out (vty, "debug ospf zebra interface%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + vty_out (vty, "debug ospf zebra redistribute%s", VTY_NEWLINE); + + write = 1; + } + + /* debug ospf event. */ + if (IS_CONF_DEBUG_OSPF (event, EVENT) == OSPF_DEBUG_EVENT) + { + vty_out (vty, "debug ospf event%s", VTY_NEWLINE); + write = 1; + } + + /* debug ospf nssa. */ + if (IS_CONF_DEBUG_OSPF (nssa, NSSA) == OSPF_DEBUG_NSSA) + { + vty_out (vty, "debug ospf nssa%s", VTY_NEWLINE); + write = 1; + } + + /* debug ospf packet all detail. */ + r = OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL; + for (i = 0; i < 5; i++) + r &= conf_debug_ospf_packet[i] & (OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL); + if (r == (OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL)) + { + vty_out (vty, "debug ospf packet all detail%s", VTY_NEWLINE); + return 1; + } + + /* debug ospf packet all. */ + r = OSPF_DEBUG_SEND_RECV; + for (i = 0; i < 5; i++) + r &= conf_debug_ospf_packet[i] & OSPF_DEBUG_SEND_RECV; + if (r == OSPF_DEBUG_SEND_RECV) + { + vty_out (vty, "debug ospf packet all%s", VTY_NEWLINE); + for (i = 0; i < 5; i++) + if (conf_debug_ospf_packet[i] & OSPF_DEBUG_DETAIL) + vty_out (vty, "debug ospf packet %s detail%s", + type_str[i], + VTY_NEWLINE); + return 1; + } + + /* debug ospf packet (hello|dd|ls-request|ls-update|ls-ack) + (send|recv) (detail). */ + for (i = 0; i < 5; i++) + { + if (conf_debug_ospf_packet[i] == 0) + continue; + + vty_out (vty, "debug ospf packet %s%s%s", + type_str[i], detail_str[conf_debug_ospf_packet[i]], + VTY_NEWLINE); + write = 1; + } + + return write; +} + +/* Initialize debug commands. */ +void +debug_init () +{ + install_node (&debug_node, config_write_debug); + + install_element (ENABLE_NODE, &show_debugging_ospf_cmd); + install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_detail_cmd); + install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_cmd); + install_element (ENABLE_NODE, &debug_ospf_packet_all_cmd); + install_element (ENABLE_NODE, &debug_ospf_ism_sub_cmd); + install_element (ENABLE_NODE, &debug_ospf_ism_cmd); + install_element (ENABLE_NODE, &debug_ospf_nsm_sub_cmd); + install_element (ENABLE_NODE, &debug_ospf_nsm_cmd); + install_element (ENABLE_NODE, &debug_ospf_lsa_sub_cmd); + install_element (ENABLE_NODE, &debug_ospf_lsa_cmd); + install_element (ENABLE_NODE, &debug_ospf_zebra_sub_cmd); + install_element (ENABLE_NODE, &debug_ospf_zebra_cmd); + install_element (ENABLE_NODE, &debug_ospf_event_cmd); +#ifdef HAVE_NSSA + install_element (ENABLE_NODE, &debug_ospf_nssa_cmd); +#endif /* HAVE_NSSA */ + install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_detail_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_packet_all_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_ism_sub_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_ism_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_nsm_sub_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_nsm_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_lsa_sub_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_lsa_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_zebra_sub_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_zebra_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_event_cmd); +#ifdef HAVE_NSSA + install_element (ENABLE_NODE, &no_debug_ospf_nssa_cmd); +#endif /* HAVE_NSSA */ + + install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_detail_cmd); + install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_cmd); + install_element (CONFIG_NODE, &debug_ospf_packet_all_cmd); + install_element (CONFIG_NODE, &debug_ospf_ism_sub_cmd); + install_element (CONFIG_NODE, &debug_ospf_ism_cmd); + install_element (CONFIG_NODE, &debug_ospf_nsm_sub_cmd); + install_element (CONFIG_NODE, &debug_ospf_nsm_cmd); + install_element (CONFIG_NODE, &debug_ospf_lsa_sub_cmd); + install_element (CONFIG_NODE, &debug_ospf_lsa_cmd); + install_element (CONFIG_NODE, &debug_ospf_zebra_sub_cmd); + install_element (CONFIG_NODE, &debug_ospf_zebra_cmd); + install_element (CONFIG_NODE, &debug_ospf_event_cmd); +#ifdef HAVE_NSSA + install_element (CONFIG_NODE, &debug_ospf_nssa_cmd); +#endif /* HAVE_NSSA */ + install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_detail_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_packet_all_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_ism_sub_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_ism_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_nsm_sub_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_nsm_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_lsa_sub_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_lsa_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_zebra_sub_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_zebra_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_event_cmd); +#ifdef HAVE_NSSA + install_element (CONFIG_NODE, &no_debug_ospf_nssa_cmd); +#endif /* HAVE_NSSA */ +} diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h new file mode 100644 index 00000000..804d5f70 --- /dev/null +++ b/ospfd/ospf_dump.h @@ -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 index 00000000..bd33c345 --- /dev/null +++ b/ospfd/ospf_flood.c @@ -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 + +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "command.h" +#include "table.h" +#include "thread.h" +#include "memory.h" +#include "log.h" +#include "zclient.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_dump.h" + +extern struct zclient *zclient; + +/* Do the LSA acking specified in table 19, Section 13.5, row 2 + * This get called from ospf_flood_out_interface. Declared inline + * for speed. */ +static void +ospf_flood_delayed_lsa_ack (struct ospf_neighbor *inbr, struct ospf_lsa *lsa) +{ + /* LSA is more recent than database copy, but was not + flooded back out receiving interface. Delayed + acknowledgment sent. If interface is in Backup state + delayed acknowledgment sent only if advertisement + received from Designated Router, otherwise do nothing See + RFC 2328 Section 13.5 */ + + /* Whether LSA is more recent or not, and whether this is in + response to the LSA being sent out recieving interface has been + worked out previously */ + + /* Deal with router as BDR */ + if (inbr->oi->state == ISM_Backup && ! NBR_IS_DR (inbr)) + return; + + /* Schedule a delayed LSA Ack to be sent */ + listnode_add (inbr->oi->ls_ack, ospf_lsa_lock (lsa)); +} + +/* Check LSA is related to external info. */ +struct external_info * +ospf_external_info_check (struct ospf_lsa *lsa) +{ + struct as_external_lsa *al; + struct prefix_ipv4 p; + struct route_node *rn; + int type; + + al = (struct as_external_lsa *) lsa->data; + + p.family = AF_INET; + p.prefix = lsa->data->id; + p.prefixlen = ip_masklen (al->mask); + + for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) + { + int redist_type = is_prefix_default (&p) ? DEFAULT_ROUTE : type; + if (ospf_is_type_redistributed (redist_type)) + if (EXTERNAL_INFO (type)) + { + rn = route_node_lookup (EXTERNAL_INFO (type), + (struct prefix *) &p); + if (rn) + { + route_unlock_node (rn); + if (rn->info != NULL) + return (struct external_info *) rn->info; + } + } + } + + return NULL; +} + +void +ospf_process_self_originated_lsa (struct ospf_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); +} + + + +/* Management functions for neighbor's Link State Request list. */ +void +ospf_ls_request_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + /* + * We cannot make use of the newly introduced callback function + * "lsdb->new_lsa_hook" to replace debug output below, just because + * it seems no simple and smart way to pass neighbor information to + * the common function "ospf_lsdb_add()" -- endo. + */ + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("RqstL(%lu)++, NBR(%s), LSA[%s]", + ospf_ls_request_count (nbr), + inet_ntoa (nbr->router_id), dump_lsa_key (lsa)); + + ospf_lsdb_add (&nbr->ls_req, lsa); +} + +unsigned long +ospf_ls_request_count (struct ospf_neighbor *nbr) +{ + return ospf_lsdb_count_all (&nbr->ls_req); +} + +int +ospf_ls_request_isempty (struct ospf_neighbor *nbr) +{ + return ospf_lsdb_isempty (&nbr->ls_req); +} + +/* Remove LSA from neighbor's ls-request list. */ +void +ospf_ls_request_delete (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + if (nbr->ls_req_last == lsa) + { + ospf_lsa_unlock (nbr->ls_req_last); + nbr->ls_req_last = NULL; + } + + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) /* -- endo. */ + zlog_info ("RqstL(%lu)--, NBR(%s), LSA[%s]", + ospf_ls_request_count (nbr), + inet_ntoa (nbr->router_id), dump_lsa_key (lsa)); + + ospf_lsdb_delete (&nbr->ls_req, lsa); +} + +/* Remove all LSA from neighbor's ls-requenst list. */ +void +ospf_ls_request_delete_all (struct ospf_neighbor *nbr) +{ + ospf_lsa_unlock (nbr->ls_req_last); + nbr->ls_req_last = NULL; + ospf_lsdb_delete_all (&nbr->ls_req); +} + +/* Lookup LSA from neighbor's ls-request list. */ +struct ospf_lsa * +ospf_ls_request_lookup (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + return ospf_lsdb_lookup (&nbr->ls_req, lsa); +} + +struct ospf_lsa * +ospf_ls_request_new (struct lsa_header *lsah) +{ + struct ospf_lsa *new; + + new = ospf_lsa_new (); + new->data = ospf_lsa_data_new (OSPF_LSA_HEADER_SIZE); + memcpy (new->data, lsah, OSPF_LSA_HEADER_SIZE); + + return new; +} + + +/* Management functions for neighbor's ls-retransmit list. */ +unsigned long +ospf_ls_retransmit_count (struct ospf_neighbor *nbr) +{ + return ospf_lsdb_count_all (&nbr->ls_rxmt); +} + +unsigned long +ospf_ls_retransmit_count_self (struct ospf_neighbor *nbr, int lsa_type) +{ + return ospf_lsdb_count_self (&nbr->ls_rxmt, lsa_type); +} + +int +ospf_ls_retransmit_isempty (struct ospf_neighbor *nbr) +{ + return ospf_lsdb_isempty (&nbr->ls_rxmt); +} + +/* Add LSA to be retransmitted to neighbor's ls-retransmit list. */ +void +ospf_ls_retransmit_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + struct ospf_lsa *old; + + old = ospf_ls_retransmit_lookup (nbr, lsa); + + if (ospf_lsa_more_recent (old, lsa) < 0) + { + if (old) + { + old->retransmit_counter--; + ospf_lsdb_delete (&nbr->ls_rxmt, old); + } + lsa->retransmit_counter++; + /* + * We cannot make use of the newly introduced callback function + * "lsdb->new_lsa_hook" to replace debug output below, just because + * it seems no simple and smart way to pass neighbor information to + * the common function "ospf_lsdb_add()" -- endo. + */ + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("RXmtL(%lu)++, NBR(%s), LSA[%s]", + ospf_ls_retransmit_count (nbr), + inet_ntoa (nbr->router_id), dump_lsa_key (lsa)); + ospf_lsdb_add (&nbr->ls_rxmt, lsa); + } +} + +/* Remove LSA from neibghbor's ls-retransmit list. */ +void +ospf_ls_retransmit_delete (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + if (ospf_ls_retransmit_lookup (nbr, lsa)) + { + lsa->retransmit_counter--; + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) /* -- endo. */ + zlog_info ("RXmtL(%lu)--, NBR(%s), LSA[%s]", + ospf_ls_retransmit_count (nbr), + inet_ntoa (nbr->router_id), dump_lsa_key (lsa)); + ospf_lsdb_delete (&nbr->ls_rxmt, lsa); + } +} + +/* Clear neighbor's ls-retransmit list. */ +void +ospf_ls_retransmit_clear (struct ospf_neighbor *nbr) +{ + struct ospf_lsdb *lsdb; + int i; + + lsdb = &nbr->ls_rxmt; + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + { + struct route_table *table = lsdb->type[i].db; + struct route_node *rn; + struct ospf_lsa *lsa; + + for (rn = route_top (table); rn; rn = route_next (rn)) + if ((lsa = rn->info) != NULL) + ospf_ls_retransmit_delete (nbr, lsa); + } + + ospf_lsa_unlock (nbr->ls_req_last); + nbr->ls_req_last = NULL; +} + +/* Lookup LSA from neighbor's ls-retransmit list. */ +struct ospf_lsa * +ospf_ls_retransmit_lookup (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + return ospf_lsdb_lookup (&nbr->ls_rxmt, lsa); +} + +/* 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); + } + } +} + + +/* 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 index 00000000..1a6ab979 --- /dev/null +++ b/ospfd/ospf_flood.h @@ -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 index 00000000..32c8d86b --- /dev/null +++ b/ospfd/ospf_ia.c @@ -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 + +#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); +} + + +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 index 00000000..afb2d4d5 --- /dev/null +++ b/ospfd/ospf_ia.h @@ -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 index 00000000..ddae9800 --- /dev/null +++ b/ospfd/ospf_interface.c @@ -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 + +#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 */ + + +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); +} + + +/* +* 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; +} + +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; + } + } +} + +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; +} + + +/* 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; +} + + +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 index 00000000..6dc01aea --- /dev/null +++ b/ospfd/ospf_interface.h @@ -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 index 00000000..b04865af --- /dev/null +++ b/ospfd/ospf_ism.h @@ -0,0 +1,88 @@ +/* + * OSPF version 2 Interface State Machine. + * From RFC2328 [OSPF Version 2] + * Copyright (C) 1999 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_ISM_H +#define _ZEBRA_OSPF_ISM_H + +/* OSPF Interface State Machine Status. */ +#define ISM_DependUpon 0 +#define ISM_Down 1 +#define ISM_Loopback 2 +#define ISM_Waiting 3 +#define ISM_PointToPoint 4 +#define ISM_DROther 5 +#define ISM_Backup 6 +#define ISM_DR 7 +#define OSPF_ISM_STATE_MAX 8 + +/* OSPF Interface State Machine Event. */ +#define ISM_NoEvent 0 +#define ISM_InterfaceUp 1 +#define ISM_WaitTimer 2 +#define ISM_BackupSeen 3 +#define ISM_NeighborChange 4 +#define ISM_LoopInd 5 +#define ISM_UnloopInd 6 +#define ISM_InterfaceDown 7 +#define OSPF_ISM_EVENT_MAX 8 + +#define OSPF_ISM_WRITE_ON() \ + 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 index 00000000..5b63a76d --- /dev/null +++ b/ospfd/ospf_lsa.c @@ -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 + +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "memory.h" +#include "stream.h" +#include "log.h" +#include "thread.h" +#include "hash.h" +#include "sockunion.h" /* for inet_aton() */ + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_zebra.h" + + +u_int32_t +get_metric (u_char *metric) +{ + u_int32_t m; + m = metric[0]; + m = (m << 8) + metric[1]; + m = (m << 8) + metric[2]; + return m; +} + + +struct timeval +tv_adjust (struct timeval a) +{ + while (a.tv_usec >= 1000000) + { + a.tv_usec -= 1000000; + a.tv_sec++; + } + + while (a.tv_usec < 0) + { + a.tv_usec += 1000000; + a.tv_sec--; + } + + return a; +} + +int +tv_ceil (struct timeval a) +{ + a = tv_adjust (a); + + return (a.tv_usec ? a.tv_sec + 1 : a.tv_sec); +} + +int +tv_floor (struct timeval a) +{ + a = tv_adjust (a); + + return a.tv_sec; +} + +struct timeval +int2tv (int a) +{ + struct timeval ret; + + ret.tv_sec = a; + ret.tv_usec = 0; + + return ret; +} + +struct timeval +tv_add (struct timeval a, struct timeval b) +{ + struct timeval ret; + + ret.tv_sec = a.tv_sec + b.tv_sec; + ret.tv_usec = a.tv_usec + b.tv_usec; + + return tv_adjust (ret); +} + +struct timeval +tv_sub (struct timeval a, struct timeval b) +{ + struct timeval ret; + + ret.tv_sec = a.tv_sec - b.tv_sec; + ret.tv_usec = a.tv_usec - b.tv_usec; + + return tv_adjust (ret); +} + +int +tv_cmp (struct timeval a, struct timeval b) +{ + return (a.tv_sec == b.tv_sec ? + a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec); +} + +int +ospf_lsa_refresh_delay (struct ospf_lsa *lsa) +{ + struct timeval delta, now; + int delay = 0; + + gettimeofday (&now, NULL); + delta = tv_sub (now, lsa->tv_orig); + + if (tv_cmp (delta, int2tv (OSPF_MIN_LS_INTERVAL)) < 0) + { + delay = tv_ceil (tv_sub (int2tv (OSPF_MIN_LS_INTERVAL), delta)); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type%d:%s]: Refresh timer delay %d seconds", + lsa->data->type, inet_ntoa (lsa->data->id), delay); + + assert (delay > 0); + } + + return delay; +} + + +int +get_age (struct ospf_lsa *lsa) +{ + int age; + struct timeval now; + + gettimeofday (&now, NULL); + age = ntohs (lsa->data->ls_age) + tv_floor (tv_sub (now, lsa->tv_recv)); + + return age; +} + + +/* Fletcher Checksum -- Refer to RFC1008. */ +#define MODX 4102 +#define LSA_CHECKSUM_OFFSET 15 + +u_int16_t +ospf_lsa_checksum (struct lsa_header *lsa) +{ + u_char *sp, *ep, *p, *q; + int c0 = 0, c1 = 0; + int x, y; + u_int16_t length; + + lsa->checksum = 0; + length = ntohs (lsa->length) - 2; + sp = (char *) &lsa->options; + + for (ep = sp + length; sp < ep; sp = q) + { + q = sp + MODX; + if (q > ep) + q = ep; + for (p = sp; p < q; p++) + { + c0 += *p; + c1 += c0; + } + c0 %= 255; + c1 %= 255; + } + + x = ((length - LSA_CHECKSUM_OFFSET) * c0 - c1) % 255; + if (x <= 0) + x += 255; + y = 510 - c0 - x; + if (y > 255) + y -= 255; + + /* take care endian issue. */ + lsa->checksum = htons ((x << 8) + y); + + return (lsa->checksum); +} + + + +/* Create OSPF LSA. */ +struct ospf_lsa * +ospf_lsa_new () +{ + struct ospf_lsa *new; + + new = XCALLOC (MTYPE_OSPF_LSA, sizeof (struct ospf_lsa)); + memset (new, 0, sizeof (struct ospf_lsa)); + + new->flags = 0; + new->lock = 1; + new->retransmit_counter = 0; + gettimeofday (&new->tv_recv, NULL); + new->tv_orig = new->tv_recv; + new->refresh_list = -1; + + return new; +} + +/* Duplicate OSPF LSA. */ +struct ospf_lsa * +ospf_lsa_dup (struct ospf_lsa *lsa) +{ + struct ospf_lsa *new; + + if (lsa == NULL) + return NULL; + + new = XCALLOC (MTYPE_OSPF_LSA, sizeof (struct ospf_lsa)); + + memcpy (new, lsa, sizeof (struct ospf_lsa)); + UNSET_FLAG (new->flags, OSPF_LSA_DISCARD); + new->lock = 1; + new->retransmit_counter = 0; + new->data = ospf_lsa_data_dup (lsa->data); + + return new; +} + +/* Free OSPF LSA. */ +void +ospf_lsa_free (struct ospf_lsa *lsa) +{ + assert (lsa->lock == 0); + + if (IS_DEBUG_OSPF (lsa, LSA)) + zlog_info ("LSA: freed %p", lsa); + + /* Delete LSA data. */ + if (lsa->data != NULL) + ospf_lsa_data_free (lsa->data); + + assert (lsa->refresh_list < 0); + + memset (lsa, 0, sizeof (struct ospf_lsa)); + XFREE (MTYPE_OSPF_LSA, lsa); +} + +/* Lock LSA. */ +struct ospf_lsa * +ospf_lsa_lock (struct ospf_lsa *lsa) +{ + lsa->lock++; + return lsa; +} + +/* Unlock LSA. */ +void +ospf_lsa_unlock (struct ospf_lsa *lsa) +{ + /* This is sanity check. */ + if (!lsa) + return; + + lsa->lock--; + + assert (lsa->lock >= 0); + + if (lsa->lock == 0) + { + assert (CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD)); + ospf_lsa_free (lsa); + } +} + +/* Check discard flag. */ +void +ospf_lsa_discard (struct ospf_lsa *lsa) +{ + if (!CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD)) + { + SET_FLAG (lsa->flags, OSPF_LSA_DISCARD); + ospf_lsa_unlock (lsa); + } +} + +/* Create LSA data. */ +struct lsa_header * +ospf_lsa_data_new (size_t size) +{ + struct lsa_header *new; + + new = (struct lsa_header *) XMALLOC (MTYPE_OSPF_LSA_DATA, size); + memset (new, 0, size); + + return new; +} + +/* Duplicate LSA data. */ +struct lsa_header * +ospf_lsa_data_dup (struct lsa_header *lsah) +{ + struct lsa_header *new; + + new = ospf_lsa_data_new (ntohs (lsah->length)); + memcpy (new, lsah, ntohs (lsah->length)); + + return new; +} + +/* Free LSA data. */ +void +ospf_lsa_data_free (struct lsa_header *lsah) +{ + if (IS_DEBUG_OSPF (lsa, LSA)) + zlog_info ("LSA[Type%d:%s]: data freed %p", + lsah->type, inet_ntoa (lsah->id), lsah); + + XFREE (MTYPE_OSPF_LSA_DATA, lsah); +} + + +/* LSA general functions. */ + +const char * +dump_lsa_key (struct ospf_lsa *lsa) +{ + static char buf[] = { + "Type255,id(255.255.255.255),ar(255.255.255.255)", + }; + struct lsa_header *lsah; + + if (lsa != NULL && (lsah = lsa->data) != NULL) + { + char id[INET_ADDRSTRLEN], ar[INET_ADDRSTRLEN]; + strcpy (id, inet_ntoa (lsah->id)); + strcpy (ar, inet_ntoa (lsah->adv_router)); + + sprintf (buf, "Type%d,id(%s),ar(%s)", lsah->type, id, ar); + } + else + strcpy (buf, "NULL"); + + return buf; +} + +u_int32_t +lsa_seqnum_increment (struct ospf_lsa *lsa) +{ + u_int32_t seqnum; + + seqnum = ntohl (lsa->data->ls_seqnum) + 1; + + return htonl (seqnum); +} + +void +lsa_header_set (struct stream *s, u_char options, + u_char type, struct in_addr id) +{ + struct 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); +} + +/* 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; +} + + +/* 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); +} + + +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; +} + + +/* 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 */ + +#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; +} + + +/* 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; +} + + +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; +} + + +#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; +} + + +#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); +} + + +/* 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 index 00000000..02fbe704 --- /dev/null +++ b/ospfd/ospf_lsa.h @@ -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 index 00000000..46d8d705 --- /dev/null +++ b/ospfd/ospf_lsdb.c @@ -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 + +#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" + +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 index 00000000..34344b3b --- /dev/null +++ b/ospfd/ospf_lsdb.h @@ -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 index 00000000..82960b24 --- /dev/null +++ b/ospfd/ospf_main.c @@ -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 + +#include "version.h" +#include "getopt.h" +#include "thread.h" +#include "prefix.h" +#include "linklist.h" +#include "if.h" +#include "vector.h" +#include "vty.h" +#include "command.h" +#include "filter.h" +#include "plist.h" +#include "stream.h" +#include "log.h" +#include "memory.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_vty.h" + +/* Configuration filename and directory. */ +char config_current[] = OSPF_DEFAULT_CONFIG; +char config_default[] = SYSCONFDIR OSPF_DEFAULT_CONFIG; + +/* OSPFd options. */ +struct option longopts[] = +{ + { "daemon", no_argument, NULL, 'd'}, + { "config_file", required_argument, NULL, 'f'}, + { "pid_file", required_argument, NULL, 'i'}, + { "log_mode", no_argument, NULL, 'l'}, + { "help", no_argument, NULL, 'h'}, + { "vty_addr", required_argument, NULL, 'A'}, + { "vty_port", required_argument, NULL, 'P'}, + { "version", no_argument, NULL, 'v'}, + { 0 } +}; + +/* OSPFd program name */ + +/* Master of threads. */ +struct thread_master *master; + +/* Process ID saved for use by init system */ +char *pid_file = PATH_OSPFD_PID; + +/* Help information display. */ +static void +usage (char *progname, int status) +{ + if (status != 0) + fprintf (stderr, "Try `%s --help' for more information.\n", progname); + else + { + printf ("Usage : %s [OPTION...]\n\ +Daemon which manages OSPF.\n\n\ +-d, --daemon Runs in daemon mode\n\ +-f, --config_file Set configuration file name\n\ +-i, --pid_file Set process identifier file name\n\ +-A, --vty_addr Set vty's bind address\n\ +-P, --vty_port Set vty's port number\n\ +-v, --version Print program version\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); + } + exit (status); +} + +/* SIGHUP handler. */ +void +sighup (int sig) +{ + zlog (NULL, LOG_INFO, "SIGHUP received"); +} + +/* SIGINT handler. */ +void +sigint (int sig) +{ + zlog (NULL, LOG_INFO, "Terminating on signal"); + + ospf_terminate (); + + exit (0); +} + +/* SIGUSR1 handler. */ +void +sigusr1 (int sig) +{ + zlog_rotate (NULL); +} + +/* Signal wrapper. */ +RETSIGTYPE * +signal_set (int signo, void (*func)(int)) +{ + int ret; + struct sigaction sig; + struct sigaction osig; + + sig.sa_handler = func; + sigemptyset (&sig.sa_mask); + sig.sa_flags = 0; +#ifdef SA_RESTART + sig.sa_flags |= SA_RESTART; +#endif /* SA_RESTART */ + + ret = sigaction (signo, &sig, &osig); + + if (ret < 0) + return (SIG_ERR); + else + return (osig.sa_handler); +} + +/* Initialization of signal handles. */ +void +signal_init () +{ + signal_set (SIGHUP, sighup); + signal_set (SIGINT, sigint); + signal_set (SIGTERM, sigint); + signal_set (SIGPIPE, SIG_IGN); +#ifdef SIGTSTP + signal_set (SIGTSTP, SIG_IGN); +#endif +#ifdef SIGTTIN + signal_set (SIGTTIN, SIG_IGN); +#endif +#ifdef SIGTTOU + signal_set (SIGTTOU, SIG_IGN); +#endif + signal_set (SIGUSR1, sigusr1); +} + +/* OSPFd main routine. */ +int +main (int argc, char **argv) +{ + char *p; + char *vty_addr = NULL; + int vty_port = 0; + int daemon_mode = 0; + char *config_file = NULL; + char *progname; + struct thread thread; + + /* Set umask before anything for security */ + umask (0027); + + /* get program name */ + progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + + /* Invoked by a priviledged user? -- endo. */ + if (getuid () != 0) + { + errno = EPERM; + perror (progname); + exit (1); + } + + zlog_default = openzlog (progname, ZLOG_NOLOG, ZLOG_OSPF, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + + 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 index 00000000..f7b18742 --- /dev/null +++ b/ospfd/ospf_neighbor.h @@ -0,0 +1,106 @@ +/* + * OSPF Neighbor functions. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_NEIGHBOR_H +#define _ZEBRA_OSPF_NEIGHBOR_H + +/* Neighbor Data Structure */ +struct ospf_neighbor +{ + /* This neighbor's parent ospf interface. */ + struct ospf_interface *oi; + + /* OSPF neighbor Information */ + u_char state; /* NSM status. */ + u_char dd_flags; /* DD bit flags. */ + u_int32_t dd_seqnum; /* DD Sequence Number. */ + + /* Neighbor Information from Hello. */ + struct prefix address; /* Neighbor Interface Address. */ + + struct in_addr src; /* Src address. */ + struct in_addr router_id; /* Router ID. */ + u_char options; /* Options. */ + int priority; /* Router Priority. */ + struct in_addr d_router; /* Designated Router. */ + struct in_addr bd_router; /* Backup Designated Router. */ + + /* Last sent Database Description packet. */ + struct ospf_packet *last_send; + /* Timestemp when last Database Description packet was sent */ + struct timeval last_send_ts; + + /* Last received Databse Description packet. */ + struct + { + u_char options; + u_char flags; + u_int32_t dd_seqnum; + } last_recv; + + /* LSA data. */ + struct ospf_lsdb ls_rxmt; + struct ospf_lsdb db_sum; + struct ospf_lsdb ls_req; + struct ospf_lsa *ls_req_last; + + u_int32_t crypt_seqnum; /* Cryptographic Sequence Number. */ + + /* Timer values. */ + u_int32_t v_inactivity; + u_int32_t v_db_desc; + u_int32_t v_ls_req; + u_int32_t v_ls_upd; + + /* Threads. */ + struct thread *t_inactivity; + struct thread *t_db_desc; + struct thread *t_ls_req; + struct thread *t_ls_upd; + struct thread *t_hello_reply; + + /* Statistics Field */ + u_int32_t state_change; + struct ospf_nbr_nbma *nbr_nbma; +}; + +/* Macros. */ +#define NBR_IS_DR(n) IPV4_ADDR_SAME (&n->address.u.prefix4, &n->d_router) +#define NBR_IS_BDR(n) IPV4_ADDR_SAME (&n->address.u.prefix4, &n->bd_router) + +/* Prototypes. */ +struct ospf_neighbor *ospf_nbr_new (struct ospf_interface *); +void ospf_nbr_free (struct ospf_neighbor *); +void ospf_nbr_delete (struct ospf_neighbor *); +int ospf_nbr_bidirectional (struct in_addr *, struct in_addr *, int); +void ospf_nbr_add_self (struct ospf_interface *); +int ospf_nbr_count (struct 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 index 00000000..56ec8647 --- /dev/null +++ b/ospfd/ospf_network.c @@ -0,0 +1,192 @@ +/* + * OSPF network related functions + * Copyright (C) 1999 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "thread.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "sockunion.h" +#include "log.h" +#include "sockopt.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_network.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_packet.h" + +/* Join to the OSPF ALL SPF ROUTERS multicast group. */ +int +ospf_if_add_allspfrouters (struct ospf *top, struct prefix *p, + unsigned int ifindex) +{ + int ret; + + ret = setsockopt_multicast_ipv4 (top->fd, IP_ADD_MEMBERSHIP, + p->u.prefix4, htonl (OSPF_ALLSPFROUTERS), + ifindex); + if (ret < 0) + zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (AllSPFRouters): %s", + strerror (errno)); + else + zlog_info ("interface %s join AllSPFRouters Multicast group.", + inet_ntoa (p->u.prefix4)); + + return ret; +} + +int +ospf_if_drop_allspfrouters (struct ospf *top, struct prefix *p, + unsigned int ifindex) +{ + int ret; + + ret = setsockopt_multicast_ipv4 (top->fd, IP_DROP_MEMBERSHIP, + p->u.prefix4, htonl (OSPF_ALLSPFROUTERS), + ifindex); + if (ret < 0) + zlog_warn("can't setsockopt IP_DROP_MEMBERSHIP (AllSPFRouters): %s", + strerror (errno)); + else + zlog_info ("interface %s leave AllSPFRouters Multicast group.", + inet_ntoa (p->u.prefix4)); + + return ret; +} + +/* Join to the OSPF ALL Designated ROUTERS multicast group. */ +int +ospf_if_add_alldrouters (struct ospf *top, struct prefix *p, unsigned int + ifindex) +{ + int ret; + + ret = setsockopt_multicast_ipv4 (top->fd, IP_ADD_MEMBERSHIP, + p->u.prefix4, htonl (OSPF_ALLDROUTERS), + ifindex); + if (ret < 0) + zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (AllDRouters): %s", + strerror (errno)); + else + zlog_info ("interface %s join AllDRouters Multicast group.", + inet_ntoa (p->u.prefix4)); + + return ret; +} + +int +ospf_if_drop_alldrouters (struct ospf *top, struct prefix *p, unsigned int + ifindex) +{ + int ret; + + ret = setsockopt_multicast_ipv4 (top->fd, IP_DROP_MEMBERSHIP, + p->u.prefix4, htonl (OSPF_ALLDROUTERS), + ifindex); + if (ret < 0) + zlog_warn ("can't setsockopt IP_DROP_MEMBERSHIP (AllDRouters): %s", + strerror (errno)); + else + zlog_info ("interface %s leave AllDRouters Multicast group.", + inet_ntoa (p->u.prefix4)); + + return ret; +} + +int +ospf_if_ipmulticast (struct ospf *top, struct prefix *p, unsigned int ifindex) +{ + u_char val; + int ret, len; + + val = 0; + len = sizeof (val); + + /* Prevent receiving self-origined multicast packets. */ + ret = setsockopt (top->fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&val, len); + if (ret < 0) + zlog_warn ("can't setsockopt IP_MULTICAST_LOOP(0): %s", strerror (errno)); + + /* Explicitly set multicast ttl to 1 -- endo. */ + val = 1; + ret = setsockopt (top->fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&val, len); + if (ret < 0) + zlog_warn ("can't setsockopt IP_MULTICAST_TTL(1): %s", strerror (errno)); + + ret = setsockopt_multicast_ipv4 (top->fd, IP_MULTICAST_IF, + p->u.prefix4, 0, ifindex); + if (ret < 0) + zlog_warn ("can't setsockopt IP_MULTICAST_IF: %s", strerror (errno)); + + return ret; +} + +int +ospf_sock_init (void) +{ + int ospf_sock; + int ret, tos, hincl = 1; + + ospf_sock = socket (AF_INET, SOCK_RAW, IPPROTO_OSPFIGP); + if (ospf_sock < 0) + { + zlog_warn ("ospf_read_sock_init: socket: %s", strerror (errno)); + return -1; + } + + /* Set precedence field. */ +#ifdef IPTOS_PREC_INTERNETCONTROL + tos = IPTOS_PREC_INTERNETCONTROL; + ret = setsockopt (ospf_sock, IPPROTO_IP, IP_TOS, + (char *) &tos, sizeof (int)); + if (ret < 0) + { + zlog_warn ("can't set sockopt IP_TOS %d to socket %d", tos, ospf_sock); + close (ospf_sock); /* Prevent sd leak. */ + return ret; + } +#endif /* IPTOS_PREC_INTERNETCONTROL */ + + /* we will include IP header with packet */ + ret = setsockopt (ospf_sock, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof (hincl)); + if (ret < 0) + zlog_warn ("Can't set IP_HDRINCL option"); + +#if defined (IP_PKTINFO) + ret = setsockopt (ospf_sock, IPPROTO_IP, IP_PKTINFO, &hincl, sizeof (hincl)); + if (ret < 0) + zlog_warn ("Can't set IP_PKTINFO option"); +#elif defined (IP_RECVIF) + ret = setsockopt (ospf_sock, IPPROTO_IP, IP_RECVIF, &hincl, sizeof (hincl)); + if (ret < 0) + zlog_warn ("Can't set IP_RECVIF option"); +#else +#warning "cannot be able to receive link information on this OS" +#endif + + return ospf_sock; +} diff --git a/ospfd/ospf_network.h b/ospfd/ospf_network.h new file mode 100644 index 00000000..52a25fd9 --- /dev/null +++ b/ospfd/ospf_network.h @@ -0,0 +1,34 @@ +/* + * OSPF network related functions. + * Copyright (C) 1999 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_NETWORK_H +#define _ZEBRA_OSPF_NETWORK_H + +/* Prototypes. */ +int ospf_if_add_allspfrouters (struct ospf *, struct prefix *, unsigned int); +int ospf_if_drop_allspfrouters (struct ospf *, struct prefix *, unsigned int); +int ospf_if_add_alldrouters (struct ospf *, struct prefix *, unsigned int); +int ospf_if_drop_alldrouters (struct ospf *, struct prefix *, unsigned int); +int ospf_if_ipmulticast (struct ospf *, struct prefix *, unsigned int); +int ospf_sock_init (void); + +#endif /* _ZEBRA_OSPF_NETWORK_H */ diff --git a/ospfd/ospf_nsm.h b/ospfd/ospf_nsm.h new file mode 100644 index 00000000..3d257305 --- /dev/null +++ b/ospfd/ospf_nsm.h @@ -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 index 00000000..67c6608b --- /dev/null +++ b/ospfd/ospf_opaque.c @@ -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 +#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 index 00000000..9aa08e5c --- /dev/null +++ b/ospfd/ospf_opaque.h @@ -0,0 +1,155 @@ +/* + * This is an implementation of rfc2370. + * Copyright (C) 2001 KDD R&D Laboratories, Inc. + * http://www.kddlabs.co.jp/ + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_OPAQUE_H +#define _ZEBRA_OSPF_OPAQUE_H + +#define IS_OPAQUE_LSA(type) \ + ((type) == OSPF_OPAQUE_LINK_LSA || \ + (type) == OSPF_OPAQUE_AREA_LSA || \ + (type) == OSPF_OPAQUE_AS_LSA) + +/* + * Usage of Opaque-LSA administrative flags in "struct ospf". + * + * 7 6 5 4 3 2 1 0 + * +---+---+---+---+---+---+---+---+ + * |///|///|///|///|B11|B10|B09| O | + * +---+---+---+---+---+---+---+---+ + * |<--------->| A + * | +--- Operation status (operational = 1) + * +----------- Blocking status for each LSA type + */ + +#define IS_OPAQUE_LSA_ORIGINATION_BLOCKED(V) \ + CHECK_FLAG((V), (OPAQUE_BLOCK_TYPE_09_LSA_BIT | \ + OPAQUE_BLOCK_TYPE_10_LSA_BIT | \ + OPAQUE_BLOCK_TYPE_11_LSA_BIT)) + +/* + * Opaque LSA's link state ID is redefined as follows. + * + * 24 16 8 0 + * +--------+--------+--------+--------+ + * |tttttttt|........|........|........| + * +--------+--------+--------+--------+ + * |<-Type->|<------- Opaque ID ------>| + */ +#define LSID_OPAQUE_TYPE_MASK 0xff000000 /* 8 bits */ +#define LSID_OPAQUE_ID_MASK 0x00ffffff /* 24 bits */ + +#define GET_OPAQUE_TYPE(lsid) \ + (((u_int32_t)(lsid) & LSID_OPAQUE_TYPE_MASK) >> 24) + +#define GET_OPAQUE_ID(lsid) \ + ((u_int32_t)(lsid) & LSID_OPAQUE_ID_MASK) + +#define SET_OPAQUE_LSID(type, id) \ + ((((type) << 24) & LSID_OPAQUE_TYPE_MASK) \ + | ((id) & LSID_OPAQUE_ID_MASK)) + +/* + * Opaque LSA types will be assigned by IANA. + * + */ +#define OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA 1 +#define OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC 2 +#define OPAQUE_TYPE_GRACE_LSA 3 + +/* Followings types are proposed in internet-draft documents. */ +#define OPAQUE_TYPE_8021_QOSPF 129 +#define OPAQUE_TYPE_SECONDARY_NEIGHBOR_DISCOVERY 224 +#define OPAQUE_TYPE_FLOODGATE 225 + +/* Ugly hack to make use of an unallocated value for wildcard matching! */ +#define OPAQUE_TYPE_WILDCARD 0 + +#define OPAQUE_TYPE_RANGE_UNASSIGNED(type) \ + ( 4 <= (type) && (type) <= 127) + +#define OPAQUE_TYPE_RANGE_RESERVED(type) \ + (127 < (type) && (type) <= 255) + +#define VALID_OPAQUE_INFO_LEN(lsahdr) \ + ((ntohs((lsahdr)->length) >= sizeof (struct lsa_header)) && \ + ((ntohs((lsahdr)->length) % sizeof (u_int32_t)) == 0)) + +/* Prototypes. */ +struct vty; +struct stream; + +extern void ospf_opaque_init (void); +extern void ospf_opaque_term (void); +extern int ospf_opaque_type9_lsa_init (struct ospf_interface *oi); +extern void ospf_opaque_type9_lsa_term (struct ospf_interface *oi); +extern int ospf_opaque_type10_lsa_init (struct ospf_area *area); +extern void ospf_opaque_type10_lsa_term (struct ospf_area *area); +extern int ospf_opaque_type11_lsa_init (struct ospf *ospf); +extern void ospf_opaque_type11_lsa_term (struct ospf *ospf); + +extern int +ospf_register_opaque_functab ( + u_char lsa_type, + u_char opaque_type, + int (* new_if_hook)(struct interface *ifp), + int (* del_if_hook)(struct interface *ifp), + void (* ism_change_hook)(struct ospf_interface *oi, int old_status), + void (* nsm_change_hook)(struct ospf_neighbor *nbr, int old_status), + void (* config_write_router)(struct vty *vty), + void (* config_write_if )(struct vty *vty, struct interface *ifp), + void (* config_write_debug )(struct vty *vty), + void (* show_opaque_info )(struct vty *vty, struct ospf_lsa *lsa), + int (* lsa_originator)(void *arg), + void (* lsa_refresher )(struct ospf_lsa *lsa), + int (* new_lsa_hook)(struct ospf_lsa *lsa), + int (* del_lsa_hook)(struct ospf_lsa *lsa) +); +extern void ospf_delete_opaque_functab (u_char lsa_type, u_char opaque_type); + +extern int ospf_opaque_new_if (struct interface *ifp); +extern int ospf_opaque_del_if (struct interface *ifp); +extern void ospf_opaque_ism_change (struct ospf_interface *oi, int old_status); +extern void ospf_opaque_nsm_change (struct ospf_neighbor *nbr, int old_status); +extern void ospf_opaque_config_write_router (struct vty *vty, struct ospf *); +extern void ospf_opaque_config_write_if (struct vty *vty, struct interface *ifp); +extern void ospf_opaque_config_write_debug (struct vty *vty); +extern void show_opaque_info_detail (struct vty *vty, struct ospf_lsa *lsa); +extern void ospf_opaque_lsa_dump (struct stream *s, u_int16_t length); + +extern void ospf_opaque_lsa_originate_schedule (struct ospf_interface *oi, int *init_delay); +extern struct ospf_lsa *ospf_opaque_lsa_install (struct ospf_lsa *new, int rt_recalc); +extern void ospf_opaque_lsa_refresh (struct ospf_lsa *lsa); + +extern void ospf_opaque_lsa_reoriginate_schedule (void *lsa_type_dependent, u_char lsa_type, u_char opaque_type); +extern void ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa); +extern void ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa); + +extern void ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, list lsas); +extern void ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, list lsas); +extern void ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, list acks); + +extern void htonf (float *src, float *dst); +extern void ntohf (float *src, float *dst); +extern struct ospf *oi_to_top (struct ospf_interface *oi); + +#endif /* _ZEBRA_OSPF_OPAQUE_H */ diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c new file mode 100644 index 00000000..2156ce33 --- /dev/null +++ b/ospfd/ospf_packet.c @@ -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 + +#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; +} + + +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; +} + + +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 */ +} + +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 . + */ + 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 index 00000000..81a104c6 --- /dev/null +++ b/ospfd/ospf_packet.h @@ -0,0 +1,171 @@ +/* + * OSPF Sending and Receiving OSPF Packets. + * Copyright (C) 1999 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_PACKET_H +#define _ZEBRA_OSPF_PACKET_H + +#define OSPF_HEADER_SIZE 24 +#define OSPF_AUTH_SIMPLE_SIZE 8 +#define OSPF_AUTH_MD5_SIZE 16 + +#define OSPF_MAX_PACKET_SIZE 65535 /* includes IP Header size. */ +#define OSPF_HELLO_MIN_SIZE 20 /* not including neighbors */ +#define OSPF_DB_DESC_MIN_SIZE 8 +#define OSPF_LS_REQ_MIN_SIZE 0 +#define OSPF_LS_UPD_MIN_SIZE 4 +#define OSPF_LS_ACK_MIN_SIZE 0 + +#define OSPF_MSG_HELLO 1 /* OSPF Hello Message. */ +#define OSPF_MSG_DB_DESC 2 /* OSPF Database Descriptoin Message. */ +#define OSPF_MSG_LS_REQ 3 /* OSPF Link State Request Message. */ +#define OSPF_MSG_LS_UPD 4 /* OSPF Link State Update Message. */ +#define OSPF_MSG_LS_ACK 5 /* OSPF Link State Acknoledgement Message. */ + +#define OSPF_SEND_PACKET_DIRECT 1 +#define OSPF_SEND_PACKET_INDIRECT 2 + +#ifdef HAVE_NSSA +#define OSPF_SEND_PACKET_LOOP 3 +#endif /* HAVE_NSSA */ + +#define OSPF_HELLO_REPLY_DELAY 1 + +struct ospf_packet +{ + struct ospf_packet *next; + + /* Pointer to data stream. */ + struct stream *s; + + /* IP destination address. */ + struct in_addr dst; + + /* OSPF packet length. */ + u_int16_t length; +}; + +/* OSPF packet queue structure. */ +struct ospf_fifo +{ + unsigned long count; + + struct ospf_packet *head; + struct ospf_packet *tail; +}; + +/* OSPF packet header structure. */ +struct ospf_header +{ + u_char version; /* OSPF Version. */ + u_char type; /* Packet Type. */ + u_int16_t length; /* Packet Length. */ + struct in_addr router_id; /* Router ID. */ + struct in_addr area_id; /* Area ID. */ + u_int16_t checksum; /* Check Sum. */ + u_int16_t auth_type; /* Authentication Type. */ + /* Authentication Data. */ + union + { + /* Simple Authentication. */ + u_char auth_data [OSPF_AUTH_SIMPLE_SIZE]; + /* Cryptographic Authentication. */ + struct + { + u_int16_t zero; /* Should be 0. */ + u_char key_id; /* Key ID. */ + u_char auth_data_len; /* Auth Data Length. */ + u_int32_t crypt_seqnum; /* Cryptographic Sequence Number. */ + } crypt; + } u; +}; + +/* OSPF Hello body format. */ +struct ospf_hello +{ + struct in_addr network_mask; + u_int16_t hello_interval; + u_char options; + u_char priority; + u_int32_t dead_interval; + struct in_addr d_router; + struct in_addr bd_router; + struct in_addr neighbors[1]; +}; + +/* OSPF Database Description body format. */ +struct ospf_db_desc +{ + u_int16_t mtu; + u_char options; + u_char flags; + u_int32_t dd_seqnum; +}; + + +/* Macros. */ +#define OSPF_PACKET_MAX(oi) ospf_packet_max (oi) +/* +#define OSPF_PACKET_MAX(oi) (((oi)->ifp->mtu - ((oi)->auth_md5 ? OSPF_AUTH_MD5_SIZE : 0)) - 88) +*/ + +#define OSPF_OUTPUT_PNT(S) ((S)->data + (S)->putp) +#define OSPF_OUTPUT_LENGTH(S) ((S)->endp) + +#define IS_SET_DD_MS(X) ((X) & OSPF_DD_FLAG_MS) +#define IS_SET_DD_M(X) ((X) & OSPF_DD_FLAG_M) +#define IS_SET_DD_I(X) ((X) & OSPF_DD_FLAG_I) +#define IS_SET_DD_ALL(X) ((X) & OSPF_DD_FLAG_ALL) + +/* Prototypes. */ +void ospf_output_forward (struct stream *, int); +struct ospf_packet *ospf_packet_new (size_t); +void ospf_packet_free (struct ospf_packet *); +struct ospf_fifo *ospf_fifo_new (); +void ospf_fifo_push (struct ospf_fifo *, struct ospf_packet *); +struct ospf_packet *ospf_fifo_pop (struct ospf_fifo *); +struct ospf_packet *ospf_fifo_head (struct ospf_fifo *); +void ospf_fifo_flush (struct ospf_fifo *); +void ospf_fifo_free (struct ospf_fifo *); +void ospf_packet_add (struct ospf_interface *, struct ospf_packet *); +void ospf_packet_delete (struct ospf_interface *); +struct stream *ospf_stream_dup (struct stream *); +struct ospf_packet *ospf_packet_dup (struct ospf_packet *); + +int ospf_read (struct thread *); +void ospf_hello_send (struct ospf_interface *); +void ospf_db_desc_send (struct ospf_neighbor *); +void ospf_db_desc_resend (struct ospf_neighbor *); +void ospf_ls_req_send (struct ospf_neighbor *); +void ospf_ls_upd_send_lsa (struct ospf_neighbor *, struct ospf_lsa *, int); +void ospf_ls_upd_send (struct ospf_neighbor *, list, int); +void ospf_ls_ack_send (struct ospf_neighbor *, struct ospf_lsa *); +void ospf_ls_ack_send_delayed (struct ospf_interface *); +void ospf_ls_retransmit (struct ospf_interface *, struct ospf_lsa *); +void ospf_ls_req_event (struct ospf_neighbor *); + +int ospf_ls_upd_timer (struct thread *); +int ospf_ls_ack_timer (struct thread *); +int ospf_poll_timer (struct thread *); +int ospf_hello_reply_timer (struct thread *); +void ospf_hello_send_sub (struct ospf_interface *, struct in_addr *); + +#endif /* _ZEBRA_OSPF_PACKET_H */ diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c new file mode 100644 index 00000000..96f7531f --- /dev/null +++ b/ospfd/ospf_route.c @@ -0,0 +1,1026 @@ +/* + * OSPF routing table. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "table.h" +#include "memory.h" +#include "linklist.h" +#include "log.h" +#include "if.h" +#include "command.h" +#include "sockunion.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_dump.h" + +struct ospf_route * +ospf_route_new () +{ + struct ospf_route *new; + + new = XCALLOC (MTYPE_OSPF_ROUTE, sizeof (struct ospf_route)); + + new->ctime = time (NULL); + new->mtime = new->ctime; + + return new; +} + +void +ospf_route_free (struct ospf_route *or) +{ + listnode node; + + if (or->path) + { + for (node = listhead (or->path); node; nextnode (node)) + ospf_path_free (node->data); + + list_delete (or->path); + } + + XFREE (MTYPE_OSPF_ROUTE, or); +} + +struct ospf_path * +ospf_path_new () +{ + struct ospf_path *new; + + new = XCALLOC (MTYPE_OSPF_PATH, sizeof (struct ospf_path)); + + return new; +} + +struct ospf_path * +ospf_path_dup (struct ospf_path *path) +{ + struct ospf_path *new; + + new = ospf_path_new (); + memcpy (new, path, sizeof (struct ospf_path)); + + return new; +} + +void +ospf_path_free (struct ospf_path *op) +{ + XFREE (MTYPE_OSPF_PATH, op); +} + +void +ospf_route_delete (struct route_table *rt) +{ + struct route_node *rn; + struct ospf_route *or; + + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((or = rn->info) != NULL) + { + if (or->type == OSPF_DESTINATION_NETWORK) + ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, + or); + else if (or->type == OSPF_DESTINATION_DISCARD) + ospf_zebra_delete_discard ((struct prefix_ipv4 *) &rn->p); + } +} + +void +ospf_route_table_free (struct route_table *rt) +{ + struct route_node *rn; + struct ospf_route *or; + + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((or = rn->info) != NULL) + { + ospf_route_free (or); + + rn->info = NULL; + route_unlock_node (rn); + } + + route_table_finish (rt); +} + +/* If a prefix and a nexthop match any route in the routing table, + then return 1, otherwise return 0. */ +int +ospf_route_match_same (struct route_table *rt, struct prefix_ipv4 *prefix, + struct ospf_route *newor) +{ + struct route_node *rn; + struct ospf_route *or; + struct ospf_path *op; + struct ospf_path *newop; + listnode n1; + listnode n2; + + if (! rt || ! prefix) + return 0; + + rn = route_node_lookup (rt, (struct prefix *) prefix); + if (! rn || ! rn->info) + return 0; + + route_unlock_node (rn); + + or = rn->info; + if (or->type == newor->type && or->cost == newor->cost) + { + if (or->type == OSPF_DESTINATION_NETWORK) + { + if (or->path->count != newor->path->count) + return 0; + + /* Check each path. */ + for (n1 = listhead (or->path), n2 = listhead (newor->path); + n1 && n2; nextnode (n1), nextnode (n2)) + { + op = getdata (n1); + newop = getdata (n2); + + if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop)) + return 0; + } + return 1; + } + else if (prefix_same (&rn->p, (struct prefix *) prefix)) + return 1; + } + return 0; +} + +/* rt: Old, cmprt: New */ +void +ospf_route_delete_uniq (struct route_table *rt, struct route_table *cmprt) +{ + struct route_node *rn; + struct ospf_route *or; + + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((or = rn->info) != NULL) + if (or->path_type == OSPF_PATH_INTRA_AREA || + or->path_type == OSPF_PATH_INTER_AREA) + { + if (or->type == OSPF_DESTINATION_NETWORK) + { + if (! ospf_route_match_same (cmprt, + (struct prefix_ipv4 *) &rn->p, or)) + ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or); + } + else if (or->type == OSPF_DESTINATION_DISCARD) + if (! ospf_route_match_same (cmprt, + (struct prefix_ipv4 *) &rn->p, or)) + ospf_zebra_delete_discard ((struct prefix_ipv4 *) &rn->p); + } +} + +/* Install routes to table. */ +void +ospf_route_install (struct 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 index 00000000..81f59c48 --- /dev/null +++ b/ospfd/ospf_route.h @@ -0,0 +1,165 @@ +/* + * OSPF routing table. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_ROUTE_H +#define _ZEBRA_OSPF_ROUTE_H + +#define OSPF_DESTINATION_ROUTER 1 +#define OSPF_DESTINATION_NETWORK 2 +#define OSPF_DESTINATION_DISCARD 3 + +#define OSPF_PATH_MIN 0 +#define OSPF_PATH_INTRA_AREA 1 +#define OSPF_PATH_INTER_AREA 2 +#define OSPF_PATH_TYPE1_EXTERNAL 3 +#define OSPF_PATH_TYPE2_EXTERNAL 4 +#define OSPF_PATH_MAX 5 + +/* OSPF Path. */ +struct ospf_path +{ + struct in_addr nexthop; + struct in_addr adv_router; + struct ospf_interface *oi; +}; + +/* Below is the structure linked to every + route node. Note that for Network routing + entries a single ospf_route is kept, while + for ABRs and ASBRs (Router routing entries), + we link an instance of ospf_router_route + where a list of paths is maintained, so + + nr->info is a (struct ospf_route *) for OSPF_DESTINATION_NETWORK + but + nr->info is a (struct ospf_router_route *) for OSPF_DESTINATION_ROUTER +*/ + +struct route_standard +{ + /* Link Sate Origin. */ + struct lsa_header *origin; + + /* Associated Area. */ + struct in_addr area_id; /* The area the route belongs to */ + +#ifdef HAVE_NSSA + /* Area Type */ + int external_routing; +#endif /* HAVE_NSSA */ + + /* Optional Capability. */ + u_char options; /* Get from LSA header. */ + + /* */ + u_char flags; /* From router-LSA */ +}; + +struct route_external +{ + /* Link State Origin. */ + struct ospf_lsa *origin; + + /* Link State Cost Type2. */ + u_int32_t type2_cost; + + /* Tag value. */ + u_int32_t tag; + + /* ASBR route. */ + struct ospf_route *asbr; +}; + +struct ospf_route +{ + /* Create time. */ + time_t ctime; + + /* Modified time. */ + time_t mtime; + + /* Destination Type. */ + u_char type; + + /* Destination ID. */ /* i.e. Link State ID. */ + struct in_addr id; + + /* Address Mask. */ + struct in_addr mask; /* Only valid for networks. */ + + /* Path Type. */ + u_char path_type; + + /* List of Paths. */ + list path; + + /* Link State Cost. */ + u_int32_t cost; /* i.e. metric. */ + + /* Route specific info. */ + union + { + struct route_standard std; + struct route_external ext; + } u; +}; + +struct ospf_path *ospf_path_new (); +void ospf_path_free (struct ospf_path *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 index 00000000..a2b257fa --- /dev/null +++ b/ospfd/ospf_routemap.c @@ -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 + +#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 index 00000000..6187977e --- /dev/null +++ b/ospfd/ospf_snmp.c @@ -0,0 +1,2443 @@ +/* OSPFv2 SNMP support + * Copyright (C) 2000 IP Infusion Inc. + * + * Written by Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#ifdef HAVE_SNMP +#include +#include +#include + +#include "if.h" +#include "log.h" +#include "prefix.h" +#include "table.h" +#include "command.h" +#include "memory.h" +#include "smux.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_flood.h" + +/* OSPF2-MIB. */ +#define OSPF2MIB 1,3,6,1,2,1,14 + +/* Zebra enterprise OSPF MIB. This variable is used for register + OSPF MIB to SNMP agent under SMUX protocol. */ +#define OSPFDOID 1,3,6,1,4,1,3317,1,2,5 + +/* OSPF MIB General Group values. */ +#define OSPFROUTERID 1 +#define OSPFADMINSTAT 2 +#define OSPFVERSIONNUMBER 3 +#define OSPFAREABDRRTRSTATUS 4 +#define OSPFASBDRRTRSTATUS 5 +#define OSPFEXTERNLSACOUNT 6 +#define OSPFEXTERNLSACKSUMSUM 7 +#define OSPFTOSSUPPORT 8 +#define OSPFORIGINATENEWLSAS 9 +#define OSPFRXNEWLSAS 10 +#define OSPFEXTLSDBLIMIT 11 +#define OSPFMULTICASTEXTENSIONS 12 +#define OSPFEXITOVERFLOWINTERVAL 13 +#define OSPFDEMANDEXTENSIONS 14 + +/* OSPF MIB ospfAreaTable. */ +#define OSPFAREAID 1 +#define OSPFAUTHTYPE 2 +#define OSPFIMPORTASEXTERN 3 +#define OSPFSPFRUNS 4 +#define OSPFAREABDRRTRCOUNT 5 +#define OSPFASBDRRTRCOUNT 6 +#define OSPFAREALSACOUNT 7 +#define OSPFAREALSACKSUMSUM 8 +#define OSPFAREASUMMARY 9 +#define OSPFAREASTATUS 10 + +/* OSPF MIB ospfStubAreaTable. */ +#define OSPFSTUBAREAID 1 +#define OSPFSTUBTOS 2 +#define OSPFSTUBMETRIC 3 +#define OSPFSTUBSTATUS 4 +#define OSPFSTUBMETRICTYPE 5 + +/* OSPF MIB ospfLsdbTable. */ +#define OSPFLSDBAREAID 1 +#define OSPFLSDBTYPE 2 +#define OSPFLSDBLSID 3 +#define OSPFLSDBROUTERID 4 +#define OSPFLSDBSEQUENCE 5 +#define OSPFLSDBAGE 6 +#define OSPFLSDBCHECKSUM 7 +#define OSPFLSDBADVERTISEMENT 8 + +/* OSPF MIB ospfAreaRangeTable. */ +#define OSPFAREARANGEAREAID 1 +#define OSPFAREARANGENET 2 +#define OSPFAREARANGEMASK 3 +#define OSPFAREARANGESTATUS 4 +#define OSPFAREARANGEEFFECT 5 + +/* OSPF MIB ospfHostTable. */ +#define OSPFHOSTIPADDRESS 1 +#define OSPFHOSTTOS 2 +#define OSPFHOSTMETRIC 3 +#define OSPFHOSTSTATUS 4 +#define OSPFHOSTAREAID 5 + +/* OSPF MIB ospfIfTable. */ +#define OSPFIFIPADDRESS 1 +#define OSPFADDRESSLESSIF 2 +#define OSPFIFAREAID 3 +#define OSPFIFTYPE 4 +#define OSPFIFADMINSTAT 5 +#define OSPFIFRTRPRIORITY 6 +#define OSPFIFTRANSITDELAY 7 +#define OSPFIFRETRANSINTERVAL 8 +#define OSPFIFHELLOINTERVAL 9 +#define OSPFIFRTRDEADINTERVAL 10 +#define OSPFIFPOLLINTERVAL 11 +#define OSPFIFSTATE 12 +#define OSPFIFDESIGNATEDROUTER 13 +#define OSPFIFBACKUPDESIGNATEDROUTER 14 +#define OSPFIFEVENTS 15 +#define OSPFIFAUTHKEY 16 +#define OSPFIFSTATUS 17 +#define OSPFIFMULTICASTFORWARDING 18 +#define OSPFIFDEMAND 19 +#define OSPFIFAUTHTYPE 20 + +/* OSPF MIB ospfIfMetricTable. */ +#define OSPFIFMETRICIPADDRESS 1 +#define OSPFIFMETRICADDRESSLESSIF 2 +#define OSPFIFMETRICTOS 3 +#define OSPFIFMETRICVALUE 4 +#define OSPFIFMETRICSTATUS 5 + +/* OSPF MIB ospfVirtIfTable. */ +#define OSPFVIRTIFAREAID 1 +#define OSPFVIRTIFNEIGHBOR 2 +#define OSPFVIRTIFTRANSITDELAY 3 +#define OSPFVIRTIFRETRANSINTERVAL 4 +#define OSPFVIRTIFHELLOINTERVAL 5 +#define OSPFVIRTIFRTRDEADINTERVAL 6 +#define OSPFVIRTIFSTATE 7 +#define OSPFVIRTIFEVENTS 8 +#define OSPFVIRTIFAUTHKEY 9 +#define OSPFVIRTIFSTATUS 10 +#define OSPFVIRTIFAUTHTYPE 11 + +/* OSPF MIB ospfNbrTable. */ +#define OSPFNBRIPADDR 1 +#define OSPFNBRADDRESSLESSINDEX 2 +#define OSPFNBRRTRID 3 +#define OSPFNBROPTIONS 4 +#define OSPFNBRPRIORITY 5 +#define OSPFNBRSTATE 6 +#define OSPFNBREVENTS 7 +#define OSPFNBRLSRETRANSQLEN 8 +#define OSPFNBMANBRSTATUS 9 +#define OSPFNBMANBRPERMANENCE 10 +#define OSPFNBRHELLOSUPPRESSED 11 + +/* OSPF MIB ospfVirtNbrTable. */ +#define OSPFVIRTNBRAREA 1 +#define OSPFVIRTNBRRTRID 2 +#define OSPFVIRTNBRIPADDR 3 +#define OSPFVIRTNBROPTIONS 4 +#define OSPFVIRTNBRSTATE 5 +#define OSPFVIRTNBREVENTS 6 +#define OSPFVIRTNBRLSRETRANSQLEN 7 +#define OSPFVIRTNBRHELLOSUPPRESSED 8 + +/* OSPF MIB ospfExtLsdbTable. */ +#define OSPFEXTLSDBTYPE 1 +#define OSPFEXTLSDBLSID 2 +#define OSPFEXTLSDBROUTERID 3 +#define OSPFEXTLSDBSEQUENCE 4 +#define OSPFEXTLSDBAGE 5 +#define OSPFEXTLSDBCHECKSUM 6 +#define OSPFEXTLSDBADVERTISEMENT 7 + +/* OSPF MIB ospfAreaAggregateTable. */ +#define OSPFAREAAGGREGATEAREAID 1 +#define OSPFAREAAGGREGATELSDBTYPE 2 +#define OSPFAREAAGGREGATENET 3 +#define OSPFAREAAGGREGATEMASK 4 +#define OSPFAREAAGGREGATESTATUS 5 +#define OSPFAREAAGGREGATEEFFECT 6 + +/* SYNTAX Status from OSPF-MIB. */ +#define OSPF_STATUS_ENABLED 1 +#define OSPF_STATUS_DISABLED 2 + +/* SNMP value hack. */ +#define COUNTER ASN_COUNTER +#define INTEGER ASN_INTEGER +#define GAUGE ASN_GAUGE +#define TIMETICKS ASN_TIMETICKS +#define IPADDRESS ASN_IPADDRESS +#define STRING ASN_OCTET_STR + +/* Declare static local variables for convenience. */ +SNMP_LOCAL_VARIABLES + +/* OSPF-MIB instances. */ +oid ospf_oid [] = { OSPF2MIB }; +oid ospfd_oid [] = { OSPFDOID }; + +/* IP address 0.0.0.0. */ +static struct in_addr ospf_empty_addr = {0}; + +/* Hook functions. */ +static u_char *ospfGeneralGroup (); +static u_char *ospfAreaEntry (); +static u_char *ospfStubAreaEntry (); +static u_char *ospfLsdbEntry (); +static u_char *ospfAreaRangeEntry (); +static u_char *ospfHostEntry (); +static u_char *ospfIfEntry (); +static u_char *ospfIfMetricEntry (); +static u_char *ospfVirtIfEntry (); +static u_char *ospfNbrEntry (); +static u_char *ospfVirtNbrEntry (); +static u_char *ospfExtLsdbEntry (); +static u_char *ospfAreaAggregateEntry (); + +struct variable ospf_variables[] = +{ + /* OSPF general variables */ + {OSPFROUTERID, IPADDRESS, RWRITE, ospfGeneralGroup, + 2, {1, 1}}, + {OSPFADMINSTAT, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 2}}, + {OSPFVERSIONNUMBER, INTEGER, RONLY, ospfGeneralGroup, + 2, {1, 3}}, + {OSPFAREABDRRTRSTATUS, INTEGER, RONLY, ospfGeneralGroup, + 2, {1, 4}}, + {OSPFASBDRRTRSTATUS, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 5}}, + {OSPFEXTERNLSACOUNT, GAUGE, RONLY, ospfGeneralGroup, + 2, {1, 6}}, + {OSPFEXTERNLSACKSUMSUM, INTEGER, RONLY, ospfGeneralGroup, + 2, {1, 7}}, + {OSPFTOSSUPPORT, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 8}}, + {OSPFORIGINATENEWLSAS, COUNTER, RONLY, ospfGeneralGroup, + 2, {1, 9}}, + {OSPFRXNEWLSAS, COUNTER, RONLY, ospfGeneralGroup, + 2, {1, 10}}, + {OSPFEXTLSDBLIMIT, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 11}}, + {OSPFMULTICASTEXTENSIONS, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 12}}, + {OSPFEXITOVERFLOWINTERVAL, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 13}}, + {OSPFDEMANDEXTENSIONS, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 14}}, + + /* OSPF area data structure. */ + {OSPFAREAID, IPADDRESS, RONLY, ospfAreaEntry, + 3, {2, 1, 1}}, + {OSPFAUTHTYPE, INTEGER, RWRITE, ospfAreaEntry, + 3, {2, 1, 2}}, + {OSPFIMPORTASEXTERN, INTEGER, RWRITE, ospfAreaEntry, + 3, {2, 1, 3}}, + {OSPFSPFRUNS, COUNTER, RONLY, ospfAreaEntry, + 3, {2, 1, 4}}, + {OSPFAREABDRRTRCOUNT, GAUGE, RONLY, ospfAreaEntry, + 3, {2, 1, 5}}, + {OSPFASBDRRTRCOUNT, GAUGE, RONLY, ospfAreaEntry, + 3, {2, 1, 6}}, + {OSPFAREALSACOUNT, GAUGE, RONLY, ospfAreaEntry, + 3, {2, 1, 7}}, + {OSPFAREALSACKSUMSUM, INTEGER, RONLY, ospfAreaEntry, + 3, {2, 1, 8}}, + {OSPFAREASUMMARY, INTEGER, RWRITE, ospfAreaEntry, + 3, {2, 1, 9}}, + {OSPFAREASTATUS, INTEGER, RWRITE, ospfAreaEntry, + 3, {2, 1, 10}}, + + /* OSPF stub area information. */ + {OSPFSTUBAREAID, IPADDRESS, RONLY, ospfStubAreaEntry, + 3, {3, 1, 1}}, + {OSPFSTUBTOS, INTEGER, RONLY, ospfStubAreaEntry, + 3, {3, 1, 2}}, + {OSPFSTUBMETRIC, INTEGER, RWRITE, ospfStubAreaEntry, + 3, {3, 1, 3}}, + {OSPFSTUBSTATUS, INTEGER, RWRITE, ospfStubAreaEntry, + 3, {3, 1, 4}}, + {OSPFSTUBMETRICTYPE, INTEGER, RWRITE, ospfStubAreaEntry, + 3, {3, 1, 5}}, + + /* OSPF link state database. */ + {OSPFLSDBAREAID, IPADDRESS, RONLY, ospfLsdbEntry, + 3, {4, 1, 1}}, + {OSPFLSDBTYPE, INTEGER, RONLY, ospfLsdbEntry, + 3, {4, 1, 2}}, + {OSPFLSDBLSID, IPADDRESS, RONLY, ospfLsdbEntry, + 3, {4, 1, 3}}, + {OSPFLSDBROUTERID, IPADDRESS, RONLY, ospfLsdbEntry, + 3, {4, 1, 4}}, + {OSPFLSDBSEQUENCE, INTEGER, RONLY, ospfLsdbEntry, + 3, {4, 1, 5}}, + {OSPFLSDBAGE, INTEGER, RONLY, ospfLsdbEntry, + 3, {4, 1, 6}}, + {OSPFLSDBCHECKSUM, INTEGER, RONLY, ospfLsdbEntry, + 3, {4, 1, 7}}, + {OSPFLSDBADVERTISEMENT, STRING, RONLY, ospfLsdbEntry, + 3, {4, 1, 8}}, + + /* Area range table. */ + {OSPFAREARANGEAREAID, IPADDRESS, RONLY, ospfAreaRangeEntry, + 3, {5, 1, 1}}, + {OSPFAREARANGENET, IPADDRESS, RONLY, ospfAreaRangeEntry, + 3, {5, 1, 2}}, + {OSPFAREARANGEMASK, IPADDRESS, RWRITE, ospfAreaRangeEntry, + 3, {5, 1, 3}}, + {OSPFAREARANGESTATUS, INTEGER, RWRITE, ospfAreaRangeEntry, + 3, {5, 1, 4}}, + {OSPFAREARANGEEFFECT, INTEGER, RWRITE, ospfAreaRangeEntry, + 3, {5, 1, 5}}, + + /* OSPF host table. */ + {OSPFHOSTIPADDRESS, IPADDRESS, RONLY, ospfHostEntry, + 3, {6, 1, 1}}, + {OSPFHOSTTOS, INTEGER, RONLY, ospfHostEntry, + 3, {6, 1, 2}}, + {OSPFHOSTMETRIC, INTEGER, RWRITE, ospfHostEntry, + 3, {6, 1, 3}}, + {OSPFHOSTSTATUS, INTEGER, RWRITE, ospfHostEntry, + 3, {6, 1, 4}}, + {OSPFHOSTAREAID, IPADDRESS, RONLY, ospfHostEntry, + 3, {6, 1, 5}}, + + /* OSPF interface table. */ + {OSPFIFIPADDRESS, IPADDRESS, RONLY, ospfIfEntry, + 3, {7, 1, 1}}, + {OSPFADDRESSLESSIF, INTEGER, RONLY, ospfIfEntry, + 3, {7, 1, 2}}, + {OSPFIFAREAID, IPADDRESS, RWRITE, ospfIfEntry, + 3, {7, 1, 3}}, + {OSPFIFTYPE, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 4}}, + {OSPFIFADMINSTAT, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 5}}, + {OSPFIFRTRPRIORITY, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 6}}, + {OSPFIFTRANSITDELAY, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 7}}, + {OSPFIFRETRANSINTERVAL, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 8}}, + {OSPFIFHELLOINTERVAL, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 9}}, + {OSPFIFRTRDEADINTERVAL, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 10}}, + {OSPFIFPOLLINTERVAL, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 11}}, + {OSPFIFSTATE, INTEGER, RONLY, ospfIfEntry, + 3, {7, 1, 12}}, + {OSPFIFDESIGNATEDROUTER, IPADDRESS, RONLY, ospfIfEntry, + 3, {7, 1, 13}}, + {OSPFIFBACKUPDESIGNATEDROUTER, IPADDRESS, RONLY, ospfIfEntry, + 3, {7, 1, 14}}, + {OSPFIFEVENTS, COUNTER, RONLY, ospfIfEntry, + 3, {7, 1, 15}}, + {OSPFIFAUTHKEY, STRING, RWRITE, ospfIfEntry, + 3, {7, 1, 16}}, + {OSPFIFSTATUS, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 17}}, + {OSPFIFMULTICASTFORWARDING, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 18}}, + {OSPFIFDEMAND, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 19}}, + {OSPFIFAUTHTYPE, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 20}}, + + /* OSPF interface metric table. */ + {OSPFIFMETRICIPADDRESS, IPADDRESS, RONLY, ospfIfMetricEntry, + 3, {8, 1, 1}}, + {OSPFIFMETRICADDRESSLESSIF, INTEGER, RONLY, ospfIfMetricEntry, + 3, {8, 1, 2}}, + {OSPFIFMETRICTOS, INTEGER, RONLY, ospfIfMetricEntry, + 3, {8, 1, 3}}, + {OSPFIFMETRICVALUE, INTEGER, RWRITE, ospfIfMetricEntry, + 3, {8, 1, 4}}, + {OSPFIFMETRICSTATUS, INTEGER, RWRITE, ospfIfMetricEntry, + 3, {8, 1, 5}}, + + /* OSPF virtual interface table. */ + {OSPFVIRTIFAREAID, IPADDRESS, RONLY, ospfVirtIfEntry, + 3, {9, 1, 1}}, + {OSPFVIRTIFNEIGHBOR, IPADDRESS, RONLY, ospfVirtIfEntry, + 3, {9, 1, 2}}, + {OSPFVIRTIFTRANSITDELAY, INTEGER, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 3}}, + {OSPFVIRTIFRETRANSINTERVAL, INTEGER, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 4}}, + {OSPFVIRTIFHELLOINTERVAL, INTEGER, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 5}}, + {OSPFVIRTIFRTRDEADINTERVAL, INTEGER, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 6}}, + {OSPFVIRTIFSTATE, INTEGER, RONLY, ospfVirtIfEntry, + 3, {9, 1, 7}}, + {OSPFVIRTIFEVENTS, COUNTER, RONLY, ospfVirtIfEntry, + 3, {9, 1, 8}}, + {OSPFVIRTIFAUTHKEY, STRING, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 9}}, + {OSPFVIRTIFSTATUS, INTEGER, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 10}}, + {OSPFVIRTIFAUTHTYPE, INTEGER, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 11}}, + + /* OSPF neighbor table. */ + {OSPFNBRIPADDR, IPADDRESS, RONLY, ospfNbrEntry, + 3, {10, 1, 1}}, + {OSPFNBRADDRESSLESSINDEX, INTEGER, RONLY, ospfNbrEntry, + 3, {10, 1, 2}}, + {OSPFNBRRTRID, IPADDRESS, RONLY, ospfNbrEntry, + 3, {10, 1, 3}}, + {OSPFNBROPTIONS, INTEGER, RONLY, ospfNbrEntry, + 3, {10, 1, 4}}, + {OSPFNBRPRIORITY, INTEGER, RWRITE, ospfNbrEntry, + 3, {10, 1, 5}}, + {OSPFNBRSTATE, INTEGER, RONLY, ospfNbrEntry, + 3, {10, 1, 6}}, + {OSPFNBREVENTS, COUNTER, RONLY, ospfNbrEntry, + 3, {10, 1, 7}}, + {OSPFNBRLSRETRANSQLEN, GAUGE, RONLY, ospfNbrEntry, + 3, {10, 1, 8}}, + {OSPFNBMANBRSTATUS, INTEGER, RWRITE, ospfNbrEntry, + 3, {10, 1, 9}}, + {OSPFNBMANBRPERMANENCE, INTEGER, RONLY, ospfNbrEntry, + 3, {10, 1, 10}}, + {OSPFNBRHELLOSUPPRESSED, INTEGER, RONLY, ospfNbrEntry, + 3, {10, 1, 11}}, + + /* OSPF virtual neighbor table. */ + {OSPFVIRTNBRAREA, IPADDRESS, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 1}}, + {OSPFVIRTNBRRTRID, IPADDRESS, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 2}}, + {OSPFVIRTNBRIPADDR, IPADDRESS, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 3}}, + {OSPFVIRTNBROPTIONS, INTEGER, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 4}}, + {OSPFVIRTNBRSTATE, INTEGER, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 5}}, + {OSPFVIRTNBREVENTS, COUNTER, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 6}}, + {OSPFVIRTNBRLSRETRANSQLEN, INTEGER, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 7}}, + {OSPFVIRTNBRHELLOSUPPRESSED, INTEGER, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 8}}, + + /* OSPF link state database, external. */ + {OSPFEXTLSDBTYPE, INTEGER, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 1}}, + {OSPFEXTLSDBLSID, IPADDRESS, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 2}}, + {OSPFEXTLSDBROUTERID, IPADDRESS, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 3}}, + {OSPFEXTLSDBSEQUENCE, INTEGER, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 4}}, + {OSPFEXTLSDBAGE, INTEGER, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 5}}, + {OSPFEXTLSDBCHECKSUM, INTEGER, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 6}}, + {OSPFEXTLSDBADVERTISEMENT, STRING, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 7}}, + + /* OSPF area aggregate table. */ + {OSPFAREAAGGREGATEAREAID, IPADDRESS, RONLY, ospfAreaAggregateEntry, + 3, {14, 1, 1}}, + {OSPFAREAAGGREGATELSDBTYPE, INTEGER, RONLY, ospfAreaAggregateEntry, + 3, {14, 1, 2}}, + {OSPFAREAAGGREGATENET, IPADDRESS, RONLY, ospfAreaAggregateEntry, + 3, {14, 1, 3}}, + {OSPFAREAAGGREGATEMASK, IPADDRESS, RONLY, ospfAreaAggregateEntry, + 3, {14, 1, 4}}, + {OSPFAREAAGGREGATESTATUS, INTEGER, RWRITE, ospfAreaAggregateEntry, + 3, {14, 1, 5}}, + {OSPFAREAAGGREGATEEFFECT, INTEGER, RWRITE, ospfAreaAggregateEntry, + 3, {14, 1, 6}} +}; + +/* The administrative status of OSPF. When OSPF is enbled on at least + one interface return 1. */ +int +ospf_admin_stat () +{ + 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; +} + +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; +} + +struct route_table *ospf_snmp_vl_table; + +void +ospf_snmp_vl_add (struct ospf_vl_data *vl_data) +{ + struct prefix_ls lp; + struct route_node *rn; + + memset (&lp, 0, sizeof (struct prefix_ls)); + lp.family = 0; + lp.prefixlen = 64; + lp.id = vl_data->vl_area_id; + lp.adv_router = vl_data->vl_peer; + + rn = route_node_get (ospf_snmp_vl_table, (struct prefix *) &lp); + rn->info = vl_data; +} + +void +ospf_snmp_vl_delete (struct ospf_vl_data *vl_data) +{ + struct prefix_ls lp; + struct route_node *rn; + + memset (&lp, 0, sizeof (struct prefix_ls)); + lp.family = 0; + lp.prefixlen = 64; + lp.id = vl_data->vl_area_id; + lp.adv_router = vl_data->vl_peer; + + rn = route_node_lookup (ospf_snmp_vl_table, (struct prefix *) &lp); + if (! rn) + return; + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); +} + +struct ospf_vl_data * +ospf_snmp_vl_lookup (struct in_addr *area_id, struct in_addr *neighbor) +{ + struct prefix_ls lp; + struct route_node *rn; + struct ospf_vl_data *vl_data; + + memset (&lp, 0, sizeof (struct prefix_ls)); + lp.family = 0; + lp.prefixlen = 64; + lp.id = *area_id; + lp.adv_router = *neighbor; + + rn = route_node_lookup (ospf_snmp_vl_table, (struct prefix *) &lp); + if (rn) + { + vl_data = rn->info; + route_unlock_node (rn); + return vl_data; + } + return NULL; +} + +struct ospf_vl_data * +ospf_snmp_vl_lookup_next (struct in_addr *area_id, struct in_addr *neighbor, + int first) +{ + struct prefix_ls lp; + struct route_node *rn; + struct ospf_vl_data *vl_data; + + memset (&lp, 0, sizeof (struct prefix_ls)); + lp.family = 0; + lp.prefixlen = 64; + lp.id = *area_id; + lp.adv_router = *neighbor; + + if (first) + rn = route_top (ospf_snmp_vl_table); + else + { + rn = route_node_get (ospf_snmp_vl_table, (struct prefix *) &lp); + rn = route_next (rn); + } + + for (; rn; rn = route_next (rn)) + if (rn->info) + break; + + if (rn && rn->info) + { + vl_data = rn->info; + *area_id = vl_data->vl_area_id; + *neighbor = vl_data->vl_peer; + route_unlock_node (rn); + return vl_data; + } + return NULL; +} + +struct ospf_vl_data * +ospfVirtIfLookup (struct variable *v, oid *name, size_t *length, + struct in_addr *area_id, struct in_addr *neighbor, int exact) +{ + int first; + int len; + struct ospf_vl_data *vl_data; + + if (exact) + { + if (*length != v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE) + return NULL; + + oid2in_addr (name + v->namelen, IN_ADDR_SIZE, area_id); + oid2in_addr (name + v->namelen + IN_ADDR_SIZE, IN_ADDR_SIZE, neighbor); + + return ospf_snmp_vl_lookup (area_id, neighbor); + } + else + { + first = 0; + + len = *length - v->namelen; + if (len <= 0) + first = 1; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + oid2in_addr (name + v->namelen, len, area_id); + + len = *length - v->namelen - IN_ADDR_SIZE; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + oid2in_addr (name + v->namelen + IN_ADDR_SIZE, len, neighbor); + + vl_data = ospf_snmp_vl_lookup_next (area_id, neighbor, first); + + if (vl_data) + { + *length = v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE; + oid_copy_addr (name + v->namelen, area_id, IN_ADDR_SIZE); + oid_copy_addr (name + v->namelen + IN_ADDR_SIZE, neighbor, + IN_ADDR_SIZE); + return vl_data; + } + } + return NULL; +} + +static u_char * +ospfVirtIfEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct ospf_vl_data *vl_data; + struct ospf_interface *oi; + struct in_addr area_id; + struct in_addr neighbor; + + memset (&area_id, 0, sizeof (struct in_addr)); + memset (&neighbor, 0, sizeof (struct in_addr)); + + vl_data = ospfVirtIfLookup (v, name, length, &area_id, &neighbor, exact); + if (! vl_data) + return NULL; + oi = vl_data->vl_oi; + if (! oi) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFVIRTIFAREAID: + return SNMP_IPADDRESS (area_id); + break; + case OSPFVIRTIFNEIGHBOR: + return SNMP_IPADDRESS (neighbor); + break; + case OSPFVIRTIFTRANSITDELAY: + return SNMP_INTEGER (OSPF_IF_PARAM (oi, transmit_delay)); + break; + case OSPFVIRTIFRETRANSINTERVAL: + return SNMP_INTEGER (OSPF_IF_PARAM (oi, retransmit_interval)); + break; + case OSPFVIRTIFHELLOINTERVAL: + return SNMP_INTEGER (OSPF_IF_PARAM (oi, v_hello)); + break; + case OSPFVIRTIFRTRDEADINTERVAL: + return SNMP_INTEGER (OSPF_IF_PARAM (oi, v_wait)); + break; + case OSPFVIRTIFSTATE: + return SNMP_INTEGER (oi->state); + break; + case OSPFVIRTIFEVENTS: + return SNMP_INTEGER (oi->state_change); + break; + case OSPFVIRTIFAUTHKEY: + *var_len = 0; + return (u_char *) OSPF_IF_PARAM (oi, auth_simple); + break; + case OSPFVIRTIFSTATUS: + return SNMP_INTEGER (SNMP_VALID); + break; + case OSPFVIRTIFAUTHTYPE: + if (oi->area) + return SNMP_INTEGER (oi->area->auth_type); + else + return SNMP_INTEGER (0); + break; + default: + return NULL; + break; + } + return NULL; +} + +struct ospf_neighbor * +ospf_snmp_nbr_lookup (struct 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; +} + +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; +} + +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; +} + +static u_char * +ospfAreaAggregateEntry (struct variable *v, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFAREAAGGREGATEAREAID: + return (u_char *) NULL; + break; + case OSPFAREAAGGREGATELSDBTYPE: + return (u_char *) NULL; + break; + case OSPFAREAAGGREGATENET: + return (u_char *) NULL; + break; + case OSPFAREAAGGREGATEMASK: + return (u_char *) NULL; + break; + case OSPFAREAAGGREGATESTATUS: + return (u_char *) NULL; + break; + case OSPFAREAAGGREGATEEFFECT: + return (u_char *) NULL; + break; + default: + return NULL; + break; + } + return NULL; +} + +/* Register OSPF2-MIB. */ +void +ospf_snmp_init () +{ + ospf_snmp_iflist = list_new (); + ospf_snmp_vl_table = route_table_init (); + smux_init (ospfd_oid, sizeof (ospfd_oid) / sizeof (oid)); + REGISTER_MIB("mibII/ospf", ospf_variables, variable, ospf_oid); + smux_start (); +} +#endif /* HAVE_SNMP */ diff --git a/ospfd/ospf_snmp.h b/ospfd/ospf_snmp.h new file mode 100644 index 00000000..d82f87b1 --- /dev/null +++ b/ospfd/ospf_snmp.h @@ -0,0 +1,33 @@ +/* OSPFv2 SNMP support + * Copyright (C) 2000 IP Infusion Inc. + * + * Written by Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_SNMP_H +#define _ZEBRA_OSPF_SNMP_H + +void ospf_snmp_if_update (struct interface *); +void ospf_snmp_if_delete (struct interface *); + +void ospf_snmp_vl_add (struct ospf_vl_data *); +void ospf_snmp_vl_delete (struct ospf_vl_data *); + +#endif /* _ZEBRA_OSPF_SNMP_H */ diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c new file mode 100644 index 00000000..d6254717 --- /dev/null +++ b/ospfd/ospf_spf.c @@ -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 + +#include "thread.h" +#include "memory.h" +#include "hash.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "log.h" +#include "sockunion.h" /* for inet_ntop () */ + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ia.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_dump.h" + +#define DEBUG + +struct vertex_nexthop * +vertex_nexthop_new (struct vertex *parent) +{ + struct vertex_nexthop *new; + + new = XCALLOC (MTYPE_OSPF_NEXTHOP, sizeof (struct vertex_nexthop)); + new->parent = parent; + + return new; +} + +void +vertex_nexthop_free (struct vertex_nexthop *nh) +{ + XFREE (MTYPE_OSPF_NEXTHOP, nh); +} + +struct vertex_nexthop * +vertex_nexthop_dup (struct vertex_nexthop *nh) +{ + struct vertex_nexthop *new; + + new = vertex_nexthop_new (nh->parent); + + new->oi = nh->oi; + new->router = nh->router; + + return new; +} + + +struct vertex * +ospf_vertex_new (struct ospf_lsa *lsa) +{ + struct vertex *new; + + new = XMALLOC (MTYPE_OSPF_VERTEX, sizeof (struct vertex)); + memset (new, 0, sizeof (struct vertex)); + + new->flags = 0; + new->type = lsa->data->type; + new->id = lsa->data->id; + new->lsa = lsa->data; + new->distance = 0; + new->child = list_new (); + new->nexthop = list_new (); + + return new; +} + +void +ospf_vertex_free (struct vertex *v) +{ + listnode node; + + list_delete (v->child); + + if (listcount (v->nexthop) > 0) + for (node = listhead (v->nexthop); node; nextnode (node)) + vertex_nexthop_free (node->data); + + list_delete (v->nexthop); + + XFREE (MTYPE_OSPF_VERTEX, v); +} + +void +ospf_vertex_add_parent (struct vertex *v) +{ + struct vertex_nexthop *nh; + listnode node; + + for (node = listhead (v->nexthop); node; nextnode (node)) + { + nh = (struct vertex_nexthop *) getdata (node); + + /* No need to add two links from the same parent. */ + if (listnode_lookup (nh->parent->child, v) == NULL) + listnode_add (nh->parent->child, v); + } +} + +void +ospf_spf_init (struct ospf_area *area) +{ + struct vertex *v; + + /* Create root node. */ + v = ospf_vertex_new (area->router_lsa_self); + + area->spf = v; + + /* Reset ABR and ASBR router counts. */ + area->abr_count = 0; + area->asbr_count = 0; +} + +int +ospf_spf_has_vertex (struct route_table *rv, struct route_table *nv, + struct lsa_header *lsa) +{ + struct prefix p; + struct route_node *rn; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = lsa->id; + + if (lsa->type == OSPF_ROUTER_LSA) + rn = route_node_get (rv, &p); + else + rn = route_node_get (nv, &p); + + if (rn->info != NULL) + { + route_unlock_node (rn); + return 1; + } + return 0; +} + +listnode +ospf_vertex_lookup (list vlist, struct in_addr id, int type) +{ + listnode node; + struct vertex *v; + + for (node = listhead (vlist); node; nextnode (node)) + { + v = (struct vertex *) getdata (node); + if (IPV4_ADDR_SAME (&id, &v->id) && type == v->type) + return node; + } + + return NULL; +} + +int +ospf_lsa_has_link (struct lsa_header *w, struct lsa_header *v) +{ + int i; + int length; + struct router_lsa *rl; + struct network_lsa *nl; + + /* In case of W is Network LSA. */ + if (w->type == OSPF_NETWORK_LSA) + { + if (v->type == OSPF_NETWORK_LSA) + return 0; + + nl = (struct network_lsa *) w; + length = (ntohs (w->length) - OSPF_LSA_HEADER_SIZE - 4) / 4; + + for (i = 0; i < length; i++) + if (IPV4_ADDR_SAME (&nl->routers[i], &v->id)) + return 1; + return 0; + } + + /* In case of W is Router LSA. */ + if (w->type == OSPF_ROUTER_LSA) + { + rl = (struct router_lsa *) w; + + length = ntohs (w->length); + + for (i = 0; + i < ntohs (rl->links) && length >= sizeof (struct router_lsa); + i++, length -= 12) + { + switch (rl->link[i].type) + { + case LSA_LINK_TYPE_POINTOPOINT: + case LSA_LINK_TYPE_VIRTUALLINK: + /* Router LSA ID. */ + if (v->type == OSPF_ROUTER_LSA && + IPV4_ADDR_SAME (&rl->link[i].link_id, &v->id)) + { + return 1; + } + break; + case LSA_LINK_TYPE_TRANSIT: + /* Network LSA ID. */ + if (v->type == OSPF_NETWORK_LSA && + IPV4_ADDR_SAME (&rl->link[i].link_id, &v->id)) + { + return 1; + } + break; + case LSA_LINK_TYPE_STUB: + /* Not take into count? */ + continue; + default: + break; + } + } + } + return 0; +} + +/* Add the nexthop to the list, only if it is unique. + * If it's not unique, free the nexthop entry. + */ +void +ospf_nexthop_add_unique (struct vertex_nexthop *new, list nexthop) +{ + struct vertex_nexthop *nh; + listnode node; + int match; + + match = 0; + for (node = listhead (nexthop); node; nextnode (node)) + { + nh = node->data; + + /* Compare the two entries. */ + /* XXX + * Comparing the parent preserves the shortest path tree + * structure even when the nexthops are identical. + */ + if (nh->oi == new->oi && + IPV4_ADDR_SAME (&nh->router, &new->router) && + nh->parent == new->parent) + { + match = 1; + break; + } + } + + if (!match) + listnode_add (nexthop, new); + else + vertex_nexthop_free (new); +} + +/* Merge entries in list b into list a. */ +void +ospf_nexthop_merge (list a, list b) +{ + struct listnode *n; + + for (n = listhead (b); n; nextnode (n)) + { + ospf_nexthop_add_unique (n->data, a); + } +} + +#define ROUTER_LSA_MIN_SIZE 12 +#define ROUTER_LSA_TOS_SIZE 4 + +struct router_lsa_link * +ospf_get_next_link (struct vertex *v, struct vertex *w, + struct router_lsa_link *prev_link) +{ + u_char *p; + u_char *lim; + struct router_lsa_link *l; + + if (prev_link == NULL) + p = ((u_char *) v->lsa) + 24; + else + { + p = (u_char *)prev_link; + p += (ROUTER_LSA_MIN_SIZE + + (prev_link->m[0].tos_count * ROUTER_LSA_TOS_SIZE)); + } + + lim = ((u_char *) v->lsa) + ntohs (v->lsa->length); + + while (p < lim) + { + l = (struct router_lsa_link *) p; + + p += (ROUTER_LSA_MIN_SIZE + + (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE)); + + if (l->m[0].type == LSA_LINK_TYPE_STUB) + continue; + + /* Defer NH calculation via VLs until summaries from + transit areas area confidered */ + + if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK) + continue; + + if (IPV4_ADDR_SAME (&l->link_id, &w->id)) + return l; + } + + return NULL; +} + +/* Calculate nexthop from root to vertex W. */ +void +ospf_nexthop_calculation (struct ospf_area *area, + struct vertex *v, struct vertex *w) +{ + listnode node; + struct vertex_nexthop *nh, *x; + struct ospf_interface *oi = NULL; + struct router_lsa_link *l = NULL; + + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_nexthop_calculation(): Start"); + + /* W's parent is root. */ + if (v == area->spf) + { + if (w->type == OSPF_VERTEX_ROUTER) + { + while ((l = ospf_get_next_link (v, w, l))) + { + struct router_lsa_link *l2 = NULL; + + if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT) + { + 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"); +} + +/* 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 index 00000000..7fe682ee --- /dev/null +++ b/ospfd/ospf_spf.h @@ -0,0 +1,50 @@ +/* + * OSPF calculation. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#define OSPF_VERTEX_ROUTER 1 +#define OSPF_VERTEX_NETWORK 2 + +#define OSPF_VERTEX_PROCESSED 0x01 + + +struct vertex +{ + u_char flags; + u_char type; + struct in_addr id; + struct lsa_header *lsa; + u_int32_t distance; + list child; + list nexthop; +}; + +struct vertex_nexthop +{ + struct ospf_interface *oi; + struct in_addr router; + struct vertex *parent; +}; + +void ospf_spf_calculate_schedule (); +void ospf_rtrs_free (struct route_table *); + +/* void ospf_spf_calculate_timer_add (); */ diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c new file mode 100644 index 00000000..aedac32a --- /dev/null +++ b/ospfd/ospf_te.c @@ -0,0 +1,1921 @@ +/* + * This is an implementation of draft-katz-yeung-ospf-traffic-06.txt + * Copyright (C) 2001 KDD R&D Laboratories, Inc. + * http://www.kddlabs.co.jp/ + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/***** MTYPE definition is not reflected to "memory.h" yet. *****/ +#define MTYPE_OSPF_MPLS_TE_LINKPARAMS 0 + +#include + +#ifdef HAVE_OSPF_TE +#ifndef HAVE_OPAQUE_LSA +#error "Wrong configure option" +#endif /* HAVE_OPAQUE_LSA */ + +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "memory.h" +#include "command.h" +#include "vty.h" +#include "stream.h" +#include "log.h" +#include "thread.h" +#include "hash.h" +#include "sockunion.h" /* for inet_aton() */ + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_te.h" + +/* Following structure are internal use only. */ +struct ospf_mpls_te +{ + enum { disabled, enabled } status; + + /* List elements are zebra-interfaces (ifp), not ospf-interfaces (oi). */ + list iflist; + + /* Store Router-TLV in network byte order. */ + struct te_tlv_router_addr router_addr; +}; + +struct mpls_te_link +{ + /* + * According to MPLS-TE (draft) specification, 24-bit Opaque-ID field + * is subdivided into 8-bit "unused" field and 16-bit "instance" field. + * In this implementation, each Link-TLV has its own instance. + */ + u_int32_t instance; + + /* Reference pointer to a Zebra-interface. */ + struct interface *ifp; + + /* Area info in which this MPLS-TE link belongs to. */ + struct ospf_area *area; + + /* Flags to manage this link parameters. */ + u_int32_t flags; +#define LPFLG_LOOKUP_DONE 0x1 +#define LPFLG_LSA_ENGAGED 0x2 +#define LPFLG_LSA_FORCED_REFRESH 0x4 + + /* Store Link-TLV in network byte order. */ + struct te_tlv_link link_header; + struct te_link_subtlv_link_type link_type; + struct te_link_subtlv_link_id link_id; + struct te_link_subtlv_lclif_ipaddr *lclif_ipaddr; + struct te_link_subtlv_rmtif_ipaddr *rmtif_ipaddr; + struct te_link_subtlv_te_metric te_metric; + struct te_link_subtlv_max_bw max_bw; + struct te_link_subtlv_max_rsv_bw max_rsv_bw; + struct te_link_subtlv_unrsv_bw unrsv_bw; + struct te_link_subtlv_rsc_clsclr rsc_clsclr; +}; + +/* + * Global variable to manage Opaque-LSA/MPLS-TE on this node. + * Note that all parameter values are stored in network byte order. + */ +static struct ospf_mpls_te OspfMplsTE; + +enum oifstate { + OI_ANY, OI_DOWN, OI_UP +}; + +enum sched_opcode { + REORIGINATE_PER_AREA, REFRESH_THIS_LSA, FLUSH_THIS_LSA +}; + +/*------------------------------------------------------------------------* + * Followings are initialize/terminate functions for MPLS-TE handling. + *------------------------------------------------------------------------*/ + +static int ospf_mpls_te_new_if (struct interface *ifp); +static int ospf_mpls_te_del_if (struct interface *ifp); +static void ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_status); +static void ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_status); +static void ospf_mpls_te_config_write_router (struct vty *vty); +static void ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp); +static void ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa); +static int ospf_mpls_te_lsa_originate (void *arg); +static void ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa); +static void ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, enum sched_opcode); + +static void del_mpls_te_link (void *val); +static void ospf_mpls_te_register_vty (void); + +int +ospf_mpls_te_init (void) +{ + int rc; + + rc = ospf_register_opaque_functab ( + OSPF_OPAQUE_AREA_LSA, + OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, + ospf_mpls_te_new_if, + ospf_mpls_te_del_if, + ospf_mpls_te_ism_change, + ospf_mpls_te_nsm_change, + ospf_mpls_te_config_write_router, + ospf_mpls_te_config_write_if, + NULL,/* ospf_mpls_te_config_write_debug */ + ospf_mpls_te_show_info, + ospf_mpls_te_lsa_originate, + ospf_mpls_te_lsa_refresh, + NULL,/* ospf_mpls_te_new_lsa_hook */ + NULL /* ospf_mpls_te_del_lsa_hook */); + if (rc != 0) + { + zlog_warn ("ospf_mpls_te_init: Failed to register functions"); + goto out; + } + + memset (&OspfMplsTE, 0, sizeof (struct ospf_mpls_te)); + OspfMplsTE.status = disabled; + OspfMplsTE.iflist = list_new (); + OspfMplsTE.iflist->del = del_mpls_te_link; + + ospf_mpls_te_register_vty (); + +out: + return rc; +} + +void +ospf_mpls_te_term (void) +{ + list_delete (OspfMplsTE.iflist); + + OspfMplsTE.iflist = NULL; + OspfMplsTE.status = disabled; + + ospf_delete_opaque_functab (OSPF_OPAQUE_AREA_LSA, + OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); + return; +} + +/*------------------------------------------------------------------------* + * Followings are control functions for MPLS-TE parameters management. + *------------------------------------------------------------------------*/ + +static void +del_mpls_te_link (void *val) +{ + XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, val); + return; +} + +static u_int32_t +get_mpls_te_instance_value () +{ + static u_int32_t seqno = 0; + + if (LEGAL_TE_INSTANCE_RANGE (seqno + 1)) + seqno += 1; + else + seqno = 1; /* Avoid zero. */ + + return seqno; +} + +static struct ospf_interface * +lookup_oi_by_ifp (struct interface *ifp, + struct ospf_area *area, enum oifstate oifstate) +{ + struct ospf_interface *oi = NULL; + struct route_node *rn; + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + if ((oi = rn->info) == NULL) + continue; + + switch (oifstate) + { + case OI_ANY: + break; + case OI_DOWN: + if (ospf_if_is_enable (oi)) + continue; + break; + case OI_UP: + if (! ospf_if_is_enable (oi)) + continue; + break; + default: + zlog_warn ("lookup_oi_by_ifp: Unknown oifstate: %x", oifstate); + goto out; + } + + if (area == NULL || oi->area == area) + return oi; + } +out: + return NULL; +} + +static struct mpls_te_link * +lookup_linkparams_by_ifp (struct interface *ifp) +{ + listnode node; + struct mpls_te_link *lp; + + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + if ((lp = getdata (node)) != NULL) + if (lp->ifp == ifp) + return lp; + + return NULL; +} + +static struct mpls_te_link * +lookup_linkparams_by_instance (struct ospf_lsa *lsa) +{ + listnode node; + struct mpls_te_link *lp; + int key = GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)); + + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + if ((lp = getdata (node)) != NULL) + if (lp->instance == key) + return lp; + + zlog_warn ("lookup_linkparams_by_instance: Entry not found: key(%x)", key); + return NULL; +} + +static void +ospf_mpls_te_foreach_area ( + void (*func)(struct mpls_te_link *lp, enum sched_opcode), + enum sched_opcode sched_opcode) +{ + listnode node, node2; + struct mpls_te_link *lp; + struct ospf_area *area; + + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + { + if ((lp = getdata (node)) == NULL) + continue; + if ((area = lp->area) == NULL) + continue; + if (lp->flags & LPFLG_LOOKUP_DONE) + continue; + + if (func != NULL) + (* func)(lp, sched_opcode); + + for (node2 = nextnode (node); node2; nextnode (node2)) + if ((lp = getdata (node2)) != NULL) + if (lp->area != NULL) + if (IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id)) + lp->flags |= LPFLG_LOOKUP_DONE; + } + + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + if ((lp = getdata (node)) != NULL) + if (lp->area != NULL) + lp->flags &= ~LPFLG_LOOKUP_DONE; + + return; +} + +static void +set_mpls_te_router_addr (struct in_addr ipv4) +{ + OspfMplsTE.router_addr.header.type = htons (TE_TLV_ROUTER_ADDR); + OspfMplsTE.router_addr.header.length = htons (sizeof (ipv4)); + OspfMplsTE.router_addr.value = ipv4; + return; +} + +static void +set_linkparams_link_header (struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh; + u_int16_t length = 0; + + /* TE_LINK_SUBTLV_LINK_TYPE */ + if (ntohs (lp->link_type.header.type) != 0) + length += TLV_SIZE (&lp->link_type.header); + + /* TE_LINK_SUBTLV_LINK_ID */ + if (ntohs (lp->link_id.header.type) != 0) + length += TLV_SIZE (&lp->link_id.header); + + /* TE_LINK_SUBTLV_LCLIF_IPADDR */ + if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL + && ntohs (tlvh->type) != 0) + length += TLV_SIZE (tlvh); + + /* TE_LINK_SUBTLV_RMTIF_IPADDR */ + if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL + && ntohs (tlvh->type) != 0) + length += TLV_SIZE (tlvh); + + /* TE_LINK_SUBTLV_TE_METRIC */ + if (ntohs (lp->te_metric.header.type) != 0) + length += TLV_SIZE (&lp->te_metric.header); + + /* TE_LINK_SUBTLV_MAX_BW */ + if (ntohs (lp->max_bw.header.type) != 0) + length += TLV_SIZE (&lp->max_bw.header); + + /* TE_LINK_SUBTLV_MAX_RSV_BW */ + if (ntohs (lp->max_rsv_bw.header.type) != 0) + length += TLV_SIZE (&lp->max_rsv_bw.header); + + /* TE_LINK_SUBTLV_UNRSV_BW */ + if (ntohs (lp->unrsv_bw.header.type) != 0) + length += TLV_SIZE (&lp->unrsv_bw.header); + + /* TE_LINK_SUBTLV_RSC_CLSCLR */ + if (ntohs (lp->rsc_clsclr.header.type) != 0) + length += TLV_SIZE (&lp->rsc_clsclr.header); + + lp->link_header.header.type = htons (TE_TLV_LINK); + lp->link_header.header.length = htons (length); + + return; +} + +static void +set_linkparams_link_type (struct ospf_interface *oi, struct mpls_te_link *lp) +{ + lp->link_type.header.type = htons (TE_LINK_SUBTLV_LINK_TYPE); + lp->link_type.header.length = htons (sizeof (lp->link_type.link_type.value)); + + switch (oi->type) + { + case OSPF_IFTYPE_POINTOPOINT: + lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_PTP; + break; + case OSPF_IFTYPE_BROADCAST: + case OSPF_IFTYPE_NBMA: + lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_MA; + break; + default: + /* Not supported yet. *//* XXX */ + lp->link_type.header.type = htons (0); + break; + } + return; +} + +static void +set_linkparams_link_id (struct ospf_interface *oi, struct mpls_te_link *lp) +{ + struct ospf_neighbor *nbr; + int done = 0; + + lp->link_id.header.type = htons (TE_LINK_SUBTLV_LINK_ID); + lp->link_id.header.length = htons (sizeof (lp->link_id.value)); + + /* + * The Link ID is identical to the contents of the Link ID field + * in the Router LSA for these link types. + */ + switch (oi->type) + { + case OSPF_IFTYPE_POINTOPOINT: + /* Take the router ID of the neighbor. */ + if (((nbr = ospf_nbr_lookup_ptop (oi->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 index 00000000..8a7a98c7 --- /dev/null +++ b/ospfd/ospf_te.h @@ -0,0 +1,193 @@ +/* + * This is an implementation of draft-katz-yeung-ospf-traffic-06.txt + * Copyright (C) 2001 KDD R&D Laboratories, Inc. + * http://www.kddlabs.co.jp/ + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_MPLS_TE_H +#define _ZEBRA_OSPF_MPLS_TE_H + +/* + * Opaque LSA's link state ID for Traffic Engineering is + * structured as follows. + * + * 24 16 8 0 + * +--------+--------+--------+--------+ + * | 1 | MBZ |........|........| + * +--------+--------+--------+--------+ + * |<-Type->||<-- Instance --->| + * + * + * Type: IANA has assigned '1' for Traffic Engineering. + * MBZ: Reserved, must be set to zero. + * Instance: User may select an arbitrary 16-bit value. + * + */ + +#define LEGAL_TE_INSTANCE_RANGE(i) (0 <= (i) && (i) <= 0xffff) + +/* + * 24 16 8 0 + * +--------+--------+--------+--------+ --- + * | LS age |Options | 10 | A + * +--------+--------+--------+--------+ | + * | 1 | 0 | Instance | | + * +--------+--------+--------+--------+ | + * | Advertising router | | Standard (Opaque) LSA header; + * +--------+--------+--------+--------+ | Only type-10 is used. + * | LS sequence number | | + * +--------+--------+--------+--------+ | + * | LS checksum | Length | V + * +--------+--------+--------+--------+ --- + * | Type | Length | A + * +--------+--------+--------+--------+ | TLV part for TE; Values might be + * | Values ... | V structured as a set of sub-TLVs. + * +--------+--------+--------+--------+ --- + */ + +/* + * Following section defines TLV (tag, length, value) structures, + * used for Traffic Engineering. + */ +struct te_tlv_header +{ + u_int16_t type; /* TE_TLV_XXX (see below) */ + u_int16_t length; /* Value portion only, in octets */ +}; + +#define TLV_HDR_SIZE \ + sizeof (struct te_tlv_header) + +#define TLV_BODY_SIZE(tlvh) \ + ROUNDUP (ntohs ((tlvh)->length), sizeof (u_int32_t)) + +#define TLV_SIZE(tlvh) \ + (TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh)) + +#define TLV_HDR_TOP(lsah) \ + (struct te_tlv_header *)((char *)(lsah) + OSPF_LSA_HEADER_SIZE) + +#define TLV_HDR_NEXT(tlvh) \ + (struct te_tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh)) + +/* + * Following section defines TLV body parts. + */ +/* Router Address TLV *//* Mandatory */ +#define TE_TLV_ROUTER_ADDR 1 +struct te_tlv_router_addr +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + struct in_addr value; +}; + +/* Link TLV */ +#define TE_TLV_LINK 2 +struct te_tlv_link +{ + struct te_tlv_header header; + /* A set of link-sub-TLVs will follow. */ +}; + +/* Link Type Sub-TLV *//* Mandatory */ +#define TE_LINK_SUBTLV_LINK_TYPE 1 +struct te_link_subtlv_link_type +{ + struct te_tlv_header header; /* Value length is 1 octet. */ + struct { +#define LINK_TYPE_SUBTLV_VALUE_PTP 1 +#define LINK_TYPE_SUBTLV_VALUE_MA 2 + u_char value; + u_char padding[3]; + } link_type; +}; + +/* Link Sub-TLV: Link ID *//* Mandatory */ +#define TE_LINK_SUBTLV_LINK_ID 2 +struct te_link_subtlv_link_id +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + struct in_addr value; /* Same as router-lsa's link-id. */ +}; + +/* Link Sub-TLV: Local Interface IP Address *//* Optional */ +#define TE_LINK_SUBTLV_LCLIF_IPADDR 3 +struct te_link_subtlv_lclif_ipaddr +{ + struct te_tlv_header header; /* Value length is 4 x N octets. */ + struct in_addr value[1]; /* Local IP address(es). */ +}; + +/* Link Sub-TLV: Remote Interface IP Address *//* Optional */ +#define TE_LINK_SUBTLV_RMTIF_IPADDR 4 +struct te_link_subtlv_rmtif_ipaddr +{ + struct te_tlv_header header; /* Value length is 4 x N octets. */ + struct in_addr value[1]; /* Neighbor's IP address(es). */ +}; + +/* Link Sub-TLV: Traffic Engineering Metric *//* Optional */ +#define TE_LINK_SUBTLV_TE_METRIC 5 +struct te_link_subtlv_te_metric +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + u_int32_t value; /* Link metric for TE purpose. */ +}; + +/* Link Sub-TLV: Maximum Bandwidth *//* Optional */ +#define TE_LINK_SUBTLV_MAX_BW 6 +struct te_link_subtlv_max_bw +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + float value; /* bytes/sec */ +}; + +/* Link Sub-TLV: Maximum Reservable Bandwidth *//* Optional */ +#define TE_LINK_SUBTLV_MAX_RSV_BW 7 +struct te_link_subtlv_max_rsv_bw +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + float value; /* bytes/sec */ +}; + +/* Link Sub-TLV: Unreserved Bandwidth *//* Optional */ +#define TE_LINK_SUBTLV_UNRSV_BW 8 +struct te_link_subtlv_unrsv_bw +{ + struct te_tlv_header header; /* Value length is 32 octets. */ + float value[8]; /* One for each priority level. */ +}; + +/* Link Sub-TLV: Resource Class/Color *//* Optional */ +#define TE_LINK_SUBTLV_RSC_CLSCLR 9 +struct te_link_subtlv_rsc_clsclr +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + u_int32_t value; /* Admin. group membership. */ +}; + +/* Here are "non-official" architechtual constants. */ +#define MPLS_TE_MINIMUM_BANDWIDTH 1.0 /* Reasonable? *//* XXX */ + +/* Prototypes. */ +extern int ospf_mpls_te_init (void); +extern void ospf_mpls_te_term (void); + +#endif /* _ZEBRA_OSPF_MPLS_TE_H */ diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c new file mode 100644 index 00000000..73215fa5 --- /dev/null +++ b/ospfd/ospf_vty.c @@ -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 + +#include "memory.h" +#include "thread.h" +#include "prefix.h" +#include "table.h" +#include "vty.h" +#include "command.h" +#include "plist.h" +#include "log.h" +#include "zclient.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_zebra.h" +/*#include "ospfd/ospf_routemap.h" */ +#include "ospfd/ospf_vty.h" +#include "ospfd/ospf_dump.h" + + +static char *ospf_network_type_str[] = +{ + "Null", + "POINTOPOINT", + "BROADCAST", + "NBMA", + "POINTOMULTIPOINT", + "VIRTUALLINK", + "LOOPBACK" +}; + + +/* Utility functions. */ +int +ospf_str2area_id (char *str, struct in_addr *area_id, int *format) +{ + char *endptr = NULL; + unsigned long ret; + + /* match "A.B.C.D". */ + if (strchr (str, '.') != NULL) + { + ret = inet_aton (str, area_id); + if (!ret) + return -1; + *format = OSPF_AREA_ID_FORMAT_ADDRESS; + } + /* match "<0-4294967295>". */ + else + { + ret = strtoul (str, &endptr, 10); + if (*endptr != '\0' || (ret == ULONG_MAX && errno == ERANGE)) + return -1; + + area_id->s_addr = htonl (ret); + *format = OSPF_AREA_ID_FORMAT_DECIMAL; + } + + return 0; +} + + +int +str2distribute_source (char *str, int *source) +{ + /* Sanity check. */ + if (str == NULL) + return 0; + + if (strncmp (str, "k", 1) == 0) + *source = ZEBRA_ROUTE_KERNEL; + else if (strncmp (str, "c", 1) == 0) + *source = ZEBRA_ROUTE_CONNECT; + else if (strncmp (str, "s", 1) == 0) + *source = ZEBRA_ROUTE_STATIC; + else if (strncmp (str, "r", 1) == 0) + *source = ZEBRA_ROUTE_RIP; + else if (strncmp (str, "b", 1) == 0) + *source = ZEBRA_ROUTE_BGP; + else + return 0; + + return 1; +} + +int +str2metric (char *str, int *metric) +{ + /* Sanity check. */ + if (str == NULL) + return 0; + + *metric = strtol (str, NULL, 10); + if (*metric < 0 && *metric > 16777214) + { + /* vty_out (vty, "OSPF metric value is invalid%s", VTY_NEWLINE); */ + return 0; + } + + return 1; +} + +int +str2metric_type (char *str, int *metric_type) +{ + /* Sanity check. */ + if (str == NULL) + return 0; + + if (strncmp (str, "1", 1) == 0) + *metric_type = EXTERNAL_METRIC_TYPE_1; + else if (strncmp (str, "2", 1) == 0) + *metric_type = EXTERNAL_METRIC_TYPE_2; + else + return 0; + + return 1; +} + +int +ospf_oi_count (struct interface *ifp) +{ + struct route_node *rn; + int i = 0; + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + if (rn->info) + i++; + + return i; +} + + +DEFUN (router_ospf, + router_ospf_cmd, + "router ospf", + "Enable a routing process\n" + "Start OSPF configuration\n") +{ + vty->node = OSPF_NODE; + vty->index = ospf_get (); + + return CMD_SUCCESS; +} + +DEFUN (no_router_ospf, + no_router_ospf_cmd, + "no router ospf", + NO_STR + "Enable a routing process\n" + "Start OSPF configuration\n") +{ + 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; +} + + +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") + +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; +} + + +/* Command Handler Logic in VLink stuff is delicate!! + + ALTER AT YOUR OWN RISK!!!! + + Various dummy values are used to represent 'NoChange' state for + VLink configuration NOT being changed by a VLink command, and + special syntax is used within the command strings so that the + typed in command verbs can be seen in the configuration command + bacckend handler. This is to drastically reduce the verbeage + required to coe up with a reasonably compatible Cisco VLink command + + - Matthew Grant + Wed, 21 Feb 2001 15:13:52 +1300 + */ + + +/* Configuration data for virtual links + */ +struct ospf_vl_config_data { + struct vty *vty; /* vty stuff */ + struct in_addr area_id; /* area ID from command line */ + int format; /* command line area ID format */ + struct in_addr vl_peer; /* command line vl_peer */ + int auth_type; /* Authehntication type, if given */ + char *auth_key; /* simple password if present */ + int crypto_key_id; /* Cryptographic key ID */ + char *md5_key; /* MD5 authentication key */ + int hello_interval; /* Obvious what these are... */ + int retransmit_interval; + int transmit_delay; + int dead_interval; +}; + +void +ospf_vl_config_data_init (struct ospf_vl_config_data *vl_config, + struct vty *vty) +{ + memset (vl_config, 0, sizeof (struct ospf_vl_config_data)); + vl_config->auth_type = OSPF_AUTH_CMD_NOTSEEN; + vl_config->vty = vty; +} + +struct ospf_vl_data * +ospf_find_vl_data (struct ospf_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) + + +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; +} + + +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; +} + + +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; +} + + +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; +} + + +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") + + +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; +} + + +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" +}; + + + +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; +} + + +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; +} + + +/* 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") + + +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") + + +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; +} + + +char *ospf_abr_type_str[] = +{ + "unknown", + "standard", + "ibm", + "cisco", + "shortcut" +}; + +char *ospf_shortcut_mode_str[] = +{ + "default", + "enable", + "disable" +}; + + +void +area_id2str (char *buf, int length, struct ospf_area *area) +{ + memset (buf, 0, length); + + if (area->format == OSPF_AREA_ID_FORMAT_ADDRESS) + strncpy (buf, inet_ntoa (area->area_id), length); + else + sprintf (buf, "%lu", (unsigned long) ntohl (area->area_id.s_addr)); +} + + +char *ospf_int_type_str[] = +{ + "unknown", /* should never be used. */ + "point-to-point", + "broadcast", + "non-broadcast", + "point-to-multipoint", + "virtual-link", /* should never be used. */ + "loopback" +}; + +/* Configuration write function for ospfd. */ +int +config_write_interface (struct vty *vty) +{ + listnode n1, n2; + struct interface *ifp; + struct crypt_key *ck; + int write = 0; + struct route_node *rn = NULL; + struct ospf_if_params *params; + + for (n1 = listhead (iflist); n1; nextnode (n1)) + { + ifp = getdata (n1); + + if (memcmp (ifp->name, "VLINK", 5) == 0) + continue; + + vty_out (vty, "!%s", VTY_NEWLINE); + vty_out (vty, "interface %s%s", ifp->name, + VTY_NEWLINE); + if (ifp->desc) + vty_out (vty, " description %s%s", ifp->desc, + VTY_NEWLINE); + + write++; + + params = IF_DEF_PARAMS (ifp); + + do { + /* Interface Network print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, type) && + params->type != OSPF_IFTYPE_BROADCAST && + params->type != OSPF_IFTYPE_LOOPBACK) + { + vty_out (vty, " ip ospf network %s", + ospf_int_type_str[params->type]); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* OSPF interface authentication print */ + if (OSPF_IF_PARAM_CONFIGURED (params, auth_type) && + params->auth_type != OSPF_AUTH_NOTSET) + { + char *auth_str; + + /* Translation tables are not that much help here due to syntax + of the simple option */ + switch (params->auth_type) + { + + case OSPF_AUTH_NULL: + auth_str = " null"; + break; + + case OSPF_AUTH_SIMPLE: + auth_str = ""; + break; + + case OSPF_AUTH_CRYPTOGRAPHIC: + auth_str = " message-digest"; + break; + + default: + auth_str = ""; + break; + } + + vty_out (vty, " ip ospf authentication%s", auth_str); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Simple Authentication Password print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, auth_simple) && + params->auth_simple[0] != '\0') + { + vty_out (vty, " ip ospf authentication-key %s", + params->auth_simple); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Cryptographic Authentication Key print. */ + for (n2 = listhead (params->auth_crypt); n2; nextnode (n2)) + { + ck = getdata (n2); + vty_out (vty, " ip ospf message-digest-key %d md5 %s", + ck->key_id, ck->auth_key); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Interface Output Cost print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, output_cost_cmd)) + { + vty_out (vty, " ip ospf cost %u", params->output_cost_cmd); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Hello Interval print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, v_hello) && + params->v_hello != OSPF_HELLO_INTERVAL_DEFAULT) + { + vty_out (vty, " ip ospf hello-interval %u", params->v_hello); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + + /* Router Dead Interval print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, v_wait) && + params->v_wait != OSPF_ROUTER_DEAD_INTERVAL_DEFAULT) + { + vty_out (vty, " ip ospf dead-interval %u", params->v_wait); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Router Priority print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, priority) && + params->priority != OSPF_ROUTER_PRIORITY_DEFAULT) + { + vty_out (vty, " ip ospf priority %u", params->priority); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Retransmit Interval print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, retransmit_interval) && + params->retransmit_interval != OSPF_RETRANSMIT_INTERVAL_DEFAULT) + { + vty_out (vty, " ip ospf retransmit-interval %u", + params->retransmit_interval); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Transmit Delay print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, transmit_delay) && + params->transmit_delay != OSPF_TRANSMIT_DELAY_DEFAULT) + { + vty_out (vty, " ip ospf transmit-delay %u", params->transmit_delay); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + while (1) + { + if (rn == NULL) + rn = route_top (IF_OIFS_PARAMS (ifp)); + else + rn = route_next (rn); + + if (rn == NULL) + break; + params = rn->info; + if (params != NULL) + break; + } + } while (rn); + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_config_write_if (vty, ifp); +#endif /* HAVE_OPAQUE_LSA */ + } + + return write; +} + +int +config_write_network_area (struct vty *vty) +{ + struct 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; +} + + +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 */ +} + + +/* 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 +}; + + +/* 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 index 00000000..9f30e204 --- /dev/null +++ b/ospfd/ospf_vty.h @@ -0,0 +1,85 @@ +/* OSPF VTY interface. + * Copyright (C) 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* Macros. */ +#define VTY_GET_UINT32(NAME,V,STR) \ +{ \ + char *endptr = NULL; \ + (V) = strtoul ((STR), &endptr, 10); \ + if (*endptr != '\0' || ((V) == ULONG_MAX && errno == ERANGE)) \ + { \ + vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ +} + +#define VTY_GET_IPV4_ADDRESS(NAME,V,STR) \ +{ \ + int retv; \ + retv = inet_aton ((STR), &(V)); \ + if (!retv) \ + { \ + vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ +} + +#define VTY_GET_IPV4_PREFIX(NAME,V,STR) \ +{ \ + int retv; \ + retv = str2prefix_ipv4 ((STR), &(V)); \ + if (retv <= 0) \ + { \ + vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ +} + +#define VTY_GET_OSPF_AREA_ID(V,F,STR) \ +{ \ + int retv; \ + retv = ospf_str2area_id ((STR), &(V), &(F)); \ + if (retv < 0) \ + { \ + vty_out (vty, "%% Invalid OSPF area ID%s", VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ +} + +#define VTY_GET_OSPF_AREA_ID_NO_BB(NAME,V,F,STR) \ +{ \ + int retv; \ + retv = ospf_str2area_id ((STR), &(V), &(F)); \ + if (retv < 0) \ + { \ + vty_out (vty, "%% Invalid OSPF area ID%s", VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ + if (OSPF_IS_AREA_ID_BACKBONE ((V))) \ + { \ + vty_out (vty, "%% You can't configure %s to backbone%s", \ + NAME, VTY_NEWLINE); \ + } \ +} + +/* Prototypes. */ +void ospf_vty_init (); +void ospf_vty_show_init (); diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c new file mode 100644 index 00000000..1ad31f29 --- /dev/null +++ b/ospfd/ospf_zebra.c @@ -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 + +#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; +} + +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; +} + + +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 (); +} + + +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 index 00000000..5dbf5739 --- /dev/null +++ b/ospfd/ospf_zebra.h @@ -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 index 00000000..e7de8eab --- /dev/null +++ b/ospfd/ospfd.c @@ -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 + +#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; + + +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; +} + +/* 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; +} + + +/* 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); +} + + +/* 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; +} + + +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); + } +} + + +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; +} + + +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; +} + + +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 index 00000000..0e8ac67b --- /dev/null +++ b/ospfd/ospfd.conf.sample @@ -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 index 00000000..a83231b2 --- /dev/null +++ b/ospfd/ospfd.h @@ -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 index 00000000..d085d06e --- /dev/null +++ b/ports/Makefile @@ -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 diff --git a/ports/README b/ports/README new file mode 100644 index 00000000..a650eaa2 --- /dev/null +++ b/ports/README @@ -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 index 00000000..520c348c --- /dev/null +++ b/ports/files/md5 @@ -0,0 +1 @@ +MD5 (zebra-980224.tar.gz) = c6887645741200c43341156c168c7034 diff --git a/ports/pkg/COMMENT b/ports/pkg/COMMENT new file mode 100644 index 00000000..53c55e36 --- /dev/null +++ b/ports/pkg/COMMENT @@ -0,0 +1 @@ +Zebra Routing protocol daemon diff --git a/ports/pkg/DESCR b/ports/pkg/DESCR new file mode 100644 index 00000000..0c8d01b7 --- /dev/null +++ b/ports/pkg/DESCR @@ -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 index 00000000..ccc69ebe --- /dev/null +++ b/ports/pkg/PLIST @@ -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 index 00000000..1f91515a --- /dev/null +++ b/ripd/.cvsignore @@ -0,0 +1,7 @@ +Makefile +*.o +ripd +ripd.conf +tags +TAGS +.deps diff --git a/ripd/ChangeLog b/ripd/ChangeLog new file mode 100644 index 00000000..42fced50 --- /dev/null +++ b/ripd/ChangeLog @@ -0,0 +1,749 @@ +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2002-06-30 Kunihiro Ishiguro + + * ripd.c (rip_output_process): When outgoing interface is same as + next hop interface, announce RIPv2 next hop otherwise set next hop + to 0. Revert previous change then take 6WIND way. + +2001-09-14 Akihiro Mizutani + + * ripd.c: RIP enabled interface's route is advertised by default. + +2001-08-28 NOGUCHI Kay + + * rip_snmp.c (rip_ifaddr_delete): Add route_node_lookup() return + value check. + + * rip_interface.c (rip_multicast_leave): Fix bug of multiple IP + address on one interface multicast join/leave bug. + +2001-08-26 NOGUCHI Kay + + * rip_interface.c (no_rip_passive_interface): Add NO_STR. + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-06-17 Kunihiro Ishiguro + + * rip_routemap.c (route_match_ip_address_prefix_list): Add match + ip next-hop prefix-list WORD. + +2001-02-18 Kunihiro Ishiguro + + * rip_interface.c (rip_passive_interface_clean): Call + rip_passive_interface_apply_all. + +2001-02-12 Kunihiro Ishiguro + + * ripd.c (rip_response_process): Multicast address nexthop check + is moved from rip_nexthop_check. + +2001-02-08 Matthew Grant + + * rip_interface.c (ipv4_multicast_join): Use + setsockopt_multicast_ipv4. + (ipv4_multicast_leave): Likewise. + (rip_if_ipv4_address_check): Interface which has IPv4 address can + be enabled. + +2001-02-08 Kunihiro Ishiguro + + * rip_interface.c (rip_interface_delete): To support pseudo + interface do not free interface structure. + * ripd.c (rip_output_process): If output interface is in simple + password authentication mode, we need space for authentication + data. + +2001-02-01 Kunihiro Ishiguro + + * ripd.c (rip_nexthop_check): Fix multicast address nexthop check. + + * zebra-0.91 is released. + +2001-01-27 Kunihiro Ishiguro + + * ripd.c (show_ip_rip): Show metric infinity route's timeout. + (rip_rte_process): If current route is metric infinity, route is + replaced with received rte. + (rip_redistribute_delete): When redistribute route is deleted, + perform poisoned reverse. + (rip_redistribute_withdraw): Likewise. + +2001-01-25 Kunihiro Ishiguro + + * ripd.c (rip_response_process): RIPv2 routing table entry with + non directly reachable nexthop was dropped. The code is changed + to treat it as 0.0.0.0 nexthop. + (rip_destination_check): Check net 0 address destination. + (rip_nexthop_check): New function for checking nexthop address + validity. + +2001-01-15 Kunihiro Ishiguro + + * ripd.c (rip_request_process): Triggered update only send changed + route. + + * rip_interface.c: Delete RIP_API part until new implementation + comes out. + + * rip_snmp.: Likewise. + + * rip_zebra.c: Likewise. + + * ripd.c: Likewise. + +2001-01-11 Kunihiro Ishiguro + + * rip_interface.c (rip_if_init): Remove HAVE_IF_PSEUDO part. + +2001-01-09 Kunihiro Ishiguro + + * zebra-0.90 is released. + +2001-01-01 Kunihiro Ishiguro + + * ripd.h (RIP_VTYSH_PATH): Change "/tmp/ripd" to "/tmp/.ripd". + +2000-12-25 David Lipovkov + + * ripd.c (rip_rte_process): When a route is in garbage collection + process (invalid with metric 16) and a router receives the same + route with valid metric then route was not installed into zebra + rib, but only into ripd rib. Moreover , it will never get into + zebra rib, because ripd wrongly assumes it's already there. + (rip_redistribute_add): When doing redistribute into rip other + route (e.g. connected) and the same route exists in ripd rib we + changed it in place - bug. Now we don't forget to remove old route + from zebra. + (rip_timeout): When removing routes from zebra I made sure that we + remove route with the metric we have in zebra and not the new + one. It doesn't make a difference now,but could be significant + when multipath support is done. + +2000-12-25 David Lipovkov + + * rip_zebra.c (rip_metric_unset): Fix bug of metric value unset. + +2000-11-25 Frank van Maarseveen + + * ripd.c (rip_request_process): Check passive flag of the + interface. + +2000-11-23 Frank van Maarseveen + + * rip_interface.c (rip_multicast_join): When IP_ADD_MEMBERSHIP + failed do not set runnning flag to the interface. + +2000-11-16 Kunihiro Ishiguro + + * ripd.c (rip_output_process): Memory leak related classfull + network generation is fixed. + +2000-11-16 Frank van Maarseveen + + * rip_interface.c (if_check_address): Obsolete pointopoint address + check is removed. + +2000-11-02 Frank van Maarseveen + + * rip_interface.c (if_check_address): Add pointopoint address + check. + (rip_interface_up): Add check for passive interface when interface + goes up. + +2000-10-23 Jochen Friedrich + + * rip_snmp.c: rip_oid and ripd_oid are used in smux_open after it + is registered. So those variables must be static. + +2000-10-19 Kunihiro Ishiguro + + * rip_interface.c: Change to "no ip rip (send|receive)" command + accept version number argument. + +2000-10-17 Akihiro Mizutani + + * rip_routemap.c (route_set_ip_nexthop_compile): Change "match ip + next-hop" from IP address to access-list name. + +2000-10-17 Kunihiro Ishiguro + + * rip_peer.c: Change ot use linklist.c instaed of newlist.c. + +2000-10-16 Kunihiro Ishiguro + + * rip_offset.c: Change to use linklist.c instead of newlist.c. + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 is released. + +2000-09-26 Akihiro Mizutani + + * rip_routemap.c (match_ip_nexthop): Add next-hop format check. + +2000-09-18 David Lipovkov + + * rip_interface.c (ripd_api_get_if_rx_version): Corrects rip SNMP + and rip API functions dealing with rip version. + + * rip_snmp.c (Status_Valid): SNMPv2-TC TEXTUAL-CONVENTION. + +2000-09-10 Kunihiro Ishiguro + + * rip_snmp.c (rip2IfLookup): Use rip_ifaddr_lookup_next() instead + of rip_if_lookup_next(). + + * rip_interface.c (rip_enable_network_lookup): Interface enable + check by interface's address with /32 prefix. + + * ripd.c (rip_read): When RIP is configured with authentication + and no authentication in incoming packet, drop the packet. + + * rip_interface.c (rip_interface_reset): RIP_AUTH_SIMPLE_PASSWORD + is default mode of authentication. + (rip_interface_new): Likewise. + (no_ip_rip_authentication_mode): Likewise. + + * ripd.c (rip_read): Likewise. + +2000-09-10 David Lipovkov + + * rip_snmp.c: Set ASN_INTEGER v->type where it is needed. + +2000-09-08 Kunihiro Ishiguro + + * ripd.c (rip_auth_simple_password): Simple password + authentication using key-chain. + (rip_write_rte): Likewise. + + * rip_interface.c (ip_rip_authentication_key_chain): Add check for + authentication string configuration. + +2000-09-08 Akihiro Mizutani + + * ripd.c (rip_write_rte): Add check for ri->auth_str. + +2000-09-07 Kunihiro Ishiguro + + * ripd_api.h: New file is added. + +2000-08-22 Kunihiro Ishiguro + + * ripd.c (rip_rte_process): rip_route_process() is renamed to + rip_rte_process() to clarify meanings of the function. + rip_route_process() is newly added to process RIP route selection. + +2000-08-18 Kunihiro Ishiguro + + * ripd.c (rip_incoming_filter): Extract incoming filter code to + function from rip_route_process(). Add check for all interface + filter. + (rip_outgoing_filter): Extract incoming filter code to function + from rip_output_process(). Add check for all interface filter. + + * rip_zebra.c (rip_redistribute_clean): Reset redistribute status + when "no router rip" is performed. + + * rip_interface.c (rip_interface_clean): Reset interface's RIP + enable status. + +2000-08-17 Kunihiro Ishiguro + + * ripd.c (rip_route_process): When metric infinity is received the + route is removed from service immediately. + (rip_timeout): Likewise. + (rip_garbage_collect): Do not delete route in garbage collection. + (rip_output_process): Check metric_out exceed metric infinity. + + * zebra-0.88 is released. + +2000-08-15 Kunihiro Ishiguro + + * ripd.c (rip_distance_apply): Unlock node when there is matched + node. + +2000-08-13 Akihiro Mizutani + + * rip_routemap.c (match_ip_nexthop): Add check for IP address + validness. + (no_set_metric): Add new ALIAS. + +2000-08-07 Kunihiro Ishiguro + + * ripd.h (struct rip ): Add distance. + +2000-08-05 Kunihiro Ishiguro + + * rip_zebra.c (rip_zebra_ipv4_add): Use new Zebra api to register + routes. Pass RIP metric value to zebra. + +2000-08-02 Kunihiro Ishiguro + + * rip_main.c (main): Make struct thread thread from global + variable to local variable in main. + +2000-08-06 Kunihiro Ishiguro + + * ripd.c (rip_packet_dump): Add MD5 authentication dump function. + (rip_auth_md5): RIP MD5 authentication packet receive works. + +2000-08-02 David Lipovkov + + * rip_interface.c (rip_if_init): Install interface "pseudo" + commands. + (rip_interface_delete): Do not call if_delete() when interface is + pseudo interface. + +2000-07-31 Kunihiro Ishiguro + + * rip_interface.c (ip_rip_authentication_mode): "ip rip + authentication mode (md5|text)" is added. + (ip_rip_authentication_key_chain): "ip rip authentication + key-chain KEY-CHAIN" is added. + (rip_interface_clean): Clean all interface configuration. + (rip_interface_reset): Reset all interface configuration. + (rip_clean_network): Clean rip_enable_network. + + * ripd.h (struct rip_interface): Add key_chain member. + + * ripd.c: Include md5-gnu.h. + +2000-07-30 Kunihiro Ishiguro + + * ripd.h (RIP_NO_AUTH): Change RIP_NO_AUTH value from 1 to 0. + + * ripd.c (rip_authentication): Use RIP_AUTH_SIMPLE_PASSWORD + instead of raw value 2. + (rip_write_rte): Likewise. + (rip_write_rte): Check ri->auth_type instead of ri->auth_str. + +2000-07-30 David Lipovkov + + * rip_interface.c (rip_if_down): Do not delete ZEBRA_ROUTE_KERNEL + route. + +2000-07-27 Kunihiro Ishiguro + + * ripd.c (rip_update_process): Add "passive-interface" command. + + * ripd.h (struct rip_interface): Add passive member to struct + rip_interface. + +2000-07-24 Kunihiro Ishiguro + + * rip_interface.c (rip_if_init): Multiple RIP routes for one + prefix change. The codes are enclosed by #ifdef NEW_RIP_TABLE. + +2000-07-24 Akihiro Mizutani + + * rip_interface.c (rip_if_init): Use install_default() for + INTERFACE_NODE. + +2000-07-24 Kunihiro Ishiguro + + * ripd.c: First update timer will be invoked in two seconds. + +2000-07-09 Jochen Friedrich + + * rip_snmp.c: Local function definitions to static. Add INTEGER + ASN_INTEGER and TIMETICKS ASN_TIMETICKS definition. + (rip2PeerLookup): Peer with domain lookup implemented. + (rip2PeerTable): Temporary disable RIP2PEERLASTUPDATE value + support due to unknown SNMP agent startup time. + +2000-07-05 Kunihiro Ishiguro + + * ripd.h: Sweep obsolete definitions. + + * rip_interface.c (rip_split_horizon): Add "ip split-horizon" + command. + + * ripd.c (rip_output_process): Remove split_horizon argument. + (rip_update_process): Likewise. + + * ripd.h (struct rip_interface): Add split_horizon flag to struct + rip_interface. + +2000-07-04 Akihiro Mizutani + + * ripd.c (rip_version): Change VERSION to <1-2>. + Add "no version" command. + +2000-07-03 Kunihiro Ishiguro + + * rip_zebra.c (rip_redistribute_type_metric): "redistribute TYPE + metric <0-16>" command is added. + + * rip_routemap.c (route_set_metric): Set metric_set when metric is + modified. + + * ripd.h (struct rip_info): To check route-map set metric or not, + new member metric_set is added to struct rip_info. + + * ripd.c (rip_route_process): Move metric handling code from + rip_response_process() to rip_route_process(). + (rip_output_process): Set output offset-list metric. + +2000-07-02 Kunihiro Ishiguro + + * rip_offset.c (rip_offset_list): New file for offset-list. + +2000-07-02 Akihiro Mizutani + + * ripd.h (struct rip ): Add default_metric. + + * ripd.c (rip_default_metric): "default-metric <1-16>" command is + added. + (config_write_rip): Change configuration order. + + * rip_zebra.c: Fix help strings. + +2000-07-02 David Lipovkov + + * rip_interface.c (rip_if_init): Add IF_DELETE_HOOK. + +2000-07-01 Kunihiro Ishiguro + + * ripd.c (rip_output_process): If specified route-map does not + exist, it treated as deny all. + +2000-06-30 Kunihiro Ishiguro + + * rip_routemap.c (rip_route_map_init): Call rip_route_map_update + when route-map is deleted. + +2000-06-28 Kunihiro Ishiguro + + * rip_routemap.c (set_metric): For consistency with bgpd's set + metric, value range is set to <0-4294967295>. + +2000-06-28 David Lipovkov + + * rip_routemap.c (rip_route_map_update): Add check for rip is + enabled or not for avoid core dump. + + * rip_debug.c (debug_rip_packet_direct): Fix bug of setting + rip_debug_packet flag. + +2000-06-13 David Lipovkov + + * rip_interface.c (rip_interface_delete): All work is done in + rip_if_down(). + +2000-06-06 Kunihiro Ishiguro + + * ripd.c (rip_redistribute_delete): Fix bug of missing + route_unlock_node() when redistribute route is not found. + +2000-06-05 Akihirof Mizutani + + * rip_debug.c (rip_debug_init): Disable show debugging in + VIEW_NODE like other protocol daemon. + + * rip_routemap.c: Change command argument to more comprehensive. + + METRIC -> <0-16> + IFNAME -> WORD + IP_ADDR -> A.B.C.D + ACCSESS_LIST -> WORD + +2000-06-05 David Lipovkov + + * rip_interface.c (rip_interface_delete): Delete all routes + include static and kernel through the interface , because even if + the interface is added again there is no guarantee that it will + get the same ifindex as before. + +2000-05-31 Akihirof Mizutani + + * rip_debug.c: Fix rip debug help string. + +2000-04-27 Mirko Karanovic + + * rip_interface.c (rip_interface_down): Remove interface from + multicast group when interface goes down. + +2000-04-03 David Lipovkov + + * rip_interface.c (rip_interface_down): Implemented rip functions + for interface up/down events: rip_interface_up() and + rip_interface_down() + +2000-03-16 David Lipovkov + + * rip_zebra.c (rip_zclient_init): Added rip functions for + interface up/down events. + +2000-02-15 Hidetoshi Shimokawa + + * ripd.c (rip_write_rte): "set metic" in route-map has no effect + for RIPv1 in ripd. It worked fine for RIPv2. + +2000-01-17 Kunihiro Ishiguro + + * ripd.c (show_ip_protocols_rip): Fix bug of "show ip protocls" + mis-display RIP version. + + * ripd.h (struct rip_peer): Add timeout thread to rip_peer + structure. + +2000-01-16 Kunihiro Ishiguro + + * rip_peer.c: Add new file for supporting RIP peer. + +1999-12-26 David Lipovkov + + * ripd.c (rip_authentication): RIP authantication string is 16 + bytes long. + +1999-12-10 Kunihiro Ishiguro + + * ripd.c (rip_read): Add check for minimum packet length. + Authentication check is moved from rip_process_response() to + rip_read(). Patch from David Lipovkov is + applied then add rte number check by Kunihiro Ishiguro + . + +1999-12-07 Kunihiro Ishiguro + + * ripd.c (rip_response_process): In case of packet is RIPv2 and + network is non zero and netmask is zero, apply netmask rule as + same as RIPv1. + +1999-11-06 Kunihiro Ishiguro + + * ripd.c (rip_timers): Fix bug of timers basic argument format. + +1999-11-03 Kunihiro Ishiguro + + * rip_snmp.c (rip2IfConfAddress): Forgot to include + RIP2IFCONFDOMAIN. + +1999-10-28 Kunihiro Ishiguro + + * ripd.h (struct rip_peer): New structure added. + +1999-10-26 Kunihiro Ishiguro + + * rip_zebra.c (rip_zebra_ipv4_add): Increment + rip_global_route_changes when route change occur. + (rip_zebra_ipv4_delete): Likewise. + + * ripd.c (rip_request_process): Increment rip_global_queries when + reply to the query is sent. + +1999-10-25 Kunihiro Ishiguro + + * rip_debug.c (rip_debug_reset): Reset function added. + + * ripd.c (rip_update_process): Logging bug is fixed. + +1999-10-10 Marc Boucher + + * ripd.c (config_write_rip): Add config_write_distribute() call. + +1999-09-29 Kunihiro Ishiguro + + * ripd.c (rip_distribute_update): Fix bug of access-list + prefix-list updates. + +1999-09-10 VOP + + * rip_zebra.c: Add redistribute route-map feature. + +1999-09-10 Kunihiro Ishiguro + + * ripd.c (rip_response_process): Add check for given prefix is + given mask applied one. + +1999-09-03 VOP + + * rip_interface.c (rip_interface_multicast_set): Bug fix about + setting multicast interface. + +1999-09-02 VOP + + * rip_routemap.c: New file added. + +1999-09-02 Kunihiro Ishiguro + + * ripd.c (show_ip_protocols_rip): Show next update time. + (show_ip_protocols_rip): Show redistribute information. + +1999-08-25 Kunihiro Ishiguro + + * RIPv2-MIB.txt: New file added. + + * rip_snmp.c: New file added. + +1999-08-24 Kunihiro Ishiguro + + * rip_interface.c (ip_rip_authentication_string): RIPv2 + authentication command is added. + +1999-08-23 Kunihiro Ishiguro + + * rip_interface.c (rip_interface_multicast_set): Process of + setting IP_MULTICAST_IF on specific interface. + + * ripd.c (rip_read): Add packet size check. + +1999-08-16 Kunihiro Ishiguro + + * ripd.c (rip_request_process): Fill in RIP_METRIC_INFINITY with + network byte order using htonl (). + (rip_response_process): Pass host byte order address to IN_CLASSC + and IN_CLASSB macro. + +1999-08-08 davidm@nbase.co.il (David Mozes) + + * rip_zebra.c (rip_zebra_read_ipv4): Fix split horizon problem. + +1999-07-03 Kunihiro Ishiguro + + * ripd.c (rip_timer_set): Function added. + +1999-07-01 Kunihiro Ishiguro + + * rip_debug.c: New file added. + rip_debug.h: New file added. + +1999-07-01 Rick Payne + + * rip_zebra.c (zebra_init): Install standard commands to + ZEBRA_NODE. + +1999-06-01 David Luyer + + * ripd.c (rip_process_route): Add support for RIP version 1. + +1999-05-29 Kunihiro Ishiguro + + * rip_zebra.c: Change to use lib/zclient.[ch]. + +1999-05-20 Carlos Alberto Barcenilla + + * ripd.c (rip_add_route): Change the existance route's metric check + to the condition specified by RFC2453. + +1999-05-17 Carlos Alberto Barcenilla + + * ripd.c (rip_process_route): Add the if metric to the route metric. + + * ripd.c (rip_add_route): Deleted add if metric to the route. + +1999-05-16 Carlos Alberto Barcenilla + + * rip_interface.c (if_valid_neighbor): New function. + + * ripd.c (rip_process_route): Added check whether the datagram + is from a valid neighbor. + +1999-05-15 Kunihiro Ishiguro + + * ripd.c (rip_process_route): Set interface pointer to rinfo. + +1999-05-15 Carlos Alberto Barcenilla + + * ripd.c (rip_check_address): Unicast and not net 0 or 127 check + added. + +1999-05-14 Stephen R. van den Berg + + * rip_main.c (signal_init): SIGTERM call sigint. + (sigint): Loggging more better message. + +1999-05-10 Kunihiro Ishiguro + + * ripd.c (rip_add_route): Fix previous route_unlock_node() chenge. + + * rip_main.c (main): Change default zlog output to ZLOG_STDOUT for + debugging. + +1999-05-09 Patrick Koppen + + * rip_interface.c (rip_request): Fix old semantics for fetching + connected address. + + * ripd.c (rip_add_route): Update timer when the route is updated. + +1999-05-09 Carlos Alberto Barcenilla + + * rip_zebra.c (struct zebra): Add ridist_static, ridist_connect, + redist_rip, redist_ripng. + + * rip_zebra.c (zebra_create): Updated for current zebra method. + + * ripd.c (rip_add_route): Add missing route_unlock_node(). + +1999-05-03 Kunihiro Ishiguro + + * ripd.c (rip_add_route): Add metric check. Reported by Carlos + Alberto Barcenilla . + +1999-02-18 Peter Galbavy + + * syslog support added + +1998-12-13 Kunihiro Ishiguro + + * ripd.c (rip_announce_func): Apply new lib functions. + +1998-12-09 Kunihiro Ishiguro + + * ripd.c (config_write_rip): Delete vector v argument. + * rip_zebra.c (config_write_zebra): Likewise. + * rip_interface.c (interface_config_write): Likewise. + +1998-09-07 Kunihiro Ishiguro + + * rip_announce.c (rip_rib_close): When ripd terminates delete all + added route. + +1998-09-01 Kunihiro Ishiguro + + * rip_interface.c: return read packet size. + +1998-05-18 Yamshita TAKAO + + * ripd.h: Modify for compile on Solaris. + +1998-05-07 Kunihiro Ishiguro + + * ripd.c: DEFUN function return CMD_SUCCESS. + change xmalloc to XMALLOC macro. + +1998-05-03 Kunihiro Ishiguro + + * rip_main.c: change CONFDIR to SYSCONFDIR. + +1998-05-01 Kunihiro Ishiguro + + * .cvsignore: added. + +1998-02-04 Kunihiro Ishiguro + + * rip_interface.c (config_write_interface): correct ADVERTISE spell. + + * rip_main.c (main): add usage() and make cleanup. + +1998-01-05 Kunihiro Ishiguro + + * ripd.c (rip_version): add rip version command. + +1998-01-04 Kunihiro Ishiguro + + * rip_interface.c (zebra_get_interface): added to get + interface's information. + + * ChangeLog: create. diff --git a/ripd/Makefile.am b/ripd/Makefile.am new file mode 100644 index 00000000..fd254851 --- /dev/null +++ b/ripd/Makefile.am @@ -0,0 +1,37 @@ +## Process this file with automake to produce Makefile.in. + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 + +noinst_LIBRARIES = librip.a +sbin_PROGRAMS = ripd + +librip_a_SOURCES = \ + ripd.c rip_zebra.c rip_interface.c rip_debug.c rip_snmp.c \ + rip_routemap.c rip_peer.c rip_offset.c + +noinst_HEADERS = \ + ripd.h rip_debug.h + +ripd_SOURCES = \ + rip_main.c $(librip_a_SOURCES) + +ripd_LDADD = ../lib/libzebra.a + +sysconf_DATA = ripd.conf.sample + +EXTRA_DIST = $(sysconf_DATA) RIPv2-MIB.txt + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done diff --git a/ripd/Makefile.in b/ripd/Makefile.in new file mode 100644 index 00000000..fa355ef8 --- /dev/null +++ b/ripd/Makefile.in @@ -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 index 00000000..6c92fb5f --- /dev/null +++ b/ripd/RIPv2-MIB.txt @@ -0,0 +1,530 @@ + RIPv2-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, Counter32, + TimeTicks, IpAddress FROM SNMPv2-SMI + TEXTUAL-CONVENTION, RowStatus FROM SNMPv2-TC + MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF + mib-2 FROM RFC1213-MIB; + + -- This MIB module uses the extended OBJECT-TYPE macro as + -- defined in [9]. + + rip2 MODULE-IDENTITY + LAST-UPDATED "9407272253Z" -- Wed Jul 27 22:53:04 PDT 1994 + ORGANIZATION "IETF RIP-II Working Group" + CONTACT-INFO + " Fred Baker + Postal: Cisco Systems + 519 Lado Drive + Santa Barbara, California 93111 + Tel: +1 805 681 0115 + E-Mail: fbaker@cisco.com + + Postal: Gary Malkin + Xylogics, Inc. + 53 Third Avenue + Burlington, MA 01803 + + Phone: (617) 272-8140 + EMail: gmalkin@Xylogics.COM" + DESCRIPTION + "The MIB module to describe the RIP2 Version 2 Protocol" + ::= { mib-2 23 } + + -- RIP-2 Management Information Base + + -- the RouteTag type represents the contents of the + -- Route Domain field in the packet header or route entry. + -- The use of the Route Domain is deprecated. + + RouteTag ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "the RouteTag type represents the contents of the Route Domain + field in the packet header or route entry" + SYNTAX OCTET STRING (SIZE (2)) + +--4.1 Global Counters + +-- The RIP-2 Globals Group. +-- Implementation of this group is mandatory for systems +-- which implement RIP-2. + +-- These counters are intended to facilitate debugging quickly +-- changing routes or failing neighbors + +rip2Globals OBJECT IDENTIFIER ::= { rip2 1 } + + rip2GlobalRouteChanges OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of route changes made to the IP Route + Database by RIP. This does not include the refresh + of a route's age." + ::= { rip2Globals 1 } + + rip2GlobalQueries OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of responses sent to RIP queries + from other systems." + ::= { rip2Globals 2 } + +--4.2 RIP Interface Tables + +-- RIP Interfaces Groups +-- Implementation of these Groups is mandatory for systems +-- which implement RIP-2. + +-- The RIP Interface Status Table. + + rip2IfStatTable OBJECT-TYPE + SYNTAX SEQUENCE OF Rip2IfStatEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A list of subnets which require separate + status monitoring in RIP." + ::= { rip2 2 } + + rip2IfStatEntry OBJECT-TYPE + SYNTAX Rip2IfStatEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A Single Routing Domain in a single Subnet." + INDEX { rip2IfStatAddress } + ::= { rip2IfStatTable 1 } + + Rip2IfStatEntry ::= + SEQUENCE { + rip2IfStatAddress + IpAddress, + rip2IfStatRcvBadPackets + Counter32, + rip2IfStatRcvBadRoutes + Counter32, + rip2IfStatSentUpdates + Counter32, + rip2IfStatStatus + RowStatus + } + + rip2IfStatAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of this system on the indicated + subnet. For unnumbered interfaces, the value 0.0.0.N, + where the least significant 24 bits (N) is the ifIndex + for the IP Interface in network byte order." + ::= { rip2IfStatEntry 1 } + + rip2IfStatRcvBadPackets OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of RIP response packets received by + the RIP process which were subsequently discarded + for any reason (e.g. a version 0 packet, or an + unknown command type)." + ::= { rip2IfStatEntry 2 } + + rip2IfStatRcvBadRoutes OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of routes, in valid RIP packets, + which were ignored for any reason (e.g. unknown + address family, or invalid metric)." + ::= { rip2IfStatEntry 3 } + + rip2IfStatSentUpdates OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of triggered RIP updates actually + sent on this interface. This explicitly does + NOT include full updates sent containing new + information." + ::= { rip2IfStatEntry 4 } + + rip2IfStatStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Writing invalid has the effect of deleting + this interface." + ::= { rip2IfStatEntry 5 } + +-- The RIP Interface Configuration Table. + + rip2IfConfTable OBJECT-TYPE + SYNTAX SEQUENCE OF Rip2IfConfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A list of subnets which require separate + configuration in RIP." + ::= { rip2 3 } + + rip2IfConfEntry OBJECT-TYPE + SYNTAX Rip2IfConfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A Single Routing Domain in a single Subnet." + INDEX { rip2IfConfAddress } + ::= { rip2IfConfTable 1 } + + Rip2IfConfEntry ::= + SEQUENCE { + rip2IfConfAddress + IpAddress, + rip2IfConfDomain + RouteTag, + rip2IfConfAuthType + INTEGER, + rip2IfConfAuthKey + OCTET STRING (SIZE(0..16)), + rip2IfConfSend + INTEGER, + rip2IfConfReceive + INTEGER, + rip2IfConfDefaultMetric + INTEGER, + rip2IfConfStatus + RowStatus, + rip2IfConfSrcAddress + IpAddress + } + + rip2IfConfAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of this system on the indicated + subnet. For unnumbered interfaces, the value 0.0.0.N, + where the least significant 24 bits (N) is the ifIndex + for the IP Interface in network byte order." + ::= { rip2IfConfEntry 1 } + + rip2IfConfDomain OBJECT-TYPE + SYNTAX RouteTag + MAX-ACCESS read-create + STATUS obsolete + DESCRIPTION + "Value inserted into the Routing Domain field + of all RIP packets sent on this interface." + DEFVAL { '0000'h } + ::= { rip2IfConfEntry 2 } + + rip2IfConfAuthType OBJECT-TYPE + SYNTAX INTEGER { + noAuthentication (1), + simplePassword (2), + md5 (3) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The type of Authentication used on this + interface." + DEFVAL { noAuthentication } + ::= { rip2IfConfEntry 3 } + + rip2IfConfAuthKey OBJECT-TYPE + SYNTAX OCTET STRING (SIZE(0..16)) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The value to be used as the Authentication Key + whenever the corresponding instance of + rip2IfConfAuthType has a value other than + noAuthentication. A modification of the corresponding + instance of rip2IfConfAuthType does not modify + the rip2IfConfAuthKey value. If a string shorter + than 16 octets is supplied, it will be left- + justified and padded to 16 octets, on the right, + with nulls (0x00). + + Reading this object always results in an OCTET + STRING of length zero; authentication may not + be bypassed by reading the MIB object." + DEFVAL { ''h } + ::= { rip2IfConfEntry 4 } + + rip2IfConfSend OBJECT-TYPE + SYNTAX INTEGER { + doNotSend (1), + ripVersion1 (2), + rip1Compatible (3), + ripVersion2 (4), + ripV1Demand (5), + ripV2Demand (6) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "What the router sends on this interface. + ripVersion1 implies sending RIP updates compliant + with RFC 1058. rip1Compatible implies + broadcasting RIP-2 updates using RFC 1058 route + subsumption rules. ripVersion2 implies + multicasting RIP-2 updates. ripV1Demand indicates + the use of Demand RIP on a WAN interface under RIP + Version 1 rules. ripV2Demand indicates the use of + Demand RIP on a WAN interface under Version 2 rules." + DEFVAL { rip1Compatible } + ::= { rip2IfConfEntry 5 } + + rip2IfConfReceive OBJECT-TYPE + SYNTAX INTEGER { + rip1 (1), + rip2 (2), + rip1OrRip2 (3), + doNotRecieve (4) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This indicates which version of RIP updates + are to be accepted. Note that rip2 and + rip1OrRip2 implies reception of multicast + packets." + DEFVAL { rip1OrRip2 } + ::= { rip2IfConfEntry 6 } + + rip2IfConfDefaultMetric OBJECT-TYPE + SYNTAX INTEGER ( 0..15 ) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable indicates the metric that is to + be used for the default route entry in RIP updates + originated on this interface. A value of zero + indicates that no default route should be + originated; in this case, a default route via + another router may be propagated." + ::= { rip2IfConfEntry 7 } + + rip2IfConfStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Writing invalid has the effect of deleting + this interface." + ::= { rip2IfConfEntry 8 } + + rip2IfConfSrcAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The IP Address this system will use as a source + address on this interface. If it is a numbered + interface, this MUST be the same value as + rip2IfConfAddress. On unnumbered interfaces, + it must be the value of rip2IfConfAddress for + some interface on the system." + ::= { rip2IfConfEntry 9 } + +--4.3 Peer Table + +-- Peer Table + +-- The RIP Peer Group +-- Implementation of this Group is Optional + +-- This group provides information about active peer +-- relationships intended to assist in debugging. An +-- active peer is a router from which a valid RIP +-- updated has been heard in the last 180 seconds. + + rip2PeerTable OBJECT-TYPE + SYNTAX SEQUENCE OF Rip2PeerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A list of RIP Peers." + ::= { rip2 4 } + + rip2PeerEntry OBJECT-TYPE + SYNTAX Rip2PeerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information regarding a single routing peer." + INDEX { rip2PeerAddress, rip2PeerDomain } + ::= { rip2PeerTable 1 } + + Rip2PeerEntry ::= + SEQUENCE { + rip2PeerAddress + IpAddress, + rip2PeerDomain + RouteTag, + rip2PeerLastUpdate + TimeTicks, + rip2PeerVersion + INTEGER, + rip2PeerRcvBadPackets + Counter32, + rip2PeerRcvBadRoutes + Counter32 + } + + rip2PeerAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address that the peer is using as its source + address. Note that on an unnumbered link, this may + not be a member of any subnet on the system." + ::= { rip2PeerEntry 1 } + + rip2PeerDomain OBJECT-TYPE + SYNTAX RouteTag + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value in the Routing Domain field in RIP + packets received from the peer. As domain suuport + is deprecated, this must be zero." + ::= { rip2PeerEntry 2 } + + rip2PeerLastUpdate OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of sysUpTime when the most recent + RIP update was received from this system." + ::= { rip2PeerEntry 3 } + + rip2PeerVersion OBJECT-TYPE + SYNTAX INTEGER ( 0..255 ) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The RIP version number in the header of the + last RIP packet received." + ::= { rip2PeerEntry 4 } + + rip2PeerRcvBadPackets OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of RIP response packets from this + peer discarded as invalid." + ::= { rip2PeerEntry 5 } + + + rip2PeerRcvBadRoutes OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of routes from this peer that were + ignored because the entry format was invalid." + ::= { rip2PeerEntry 6 } + +-- conformance information + +rip2Conformance OBJECT IDENTIFIER ::= { rip2 5 } + +rip2Groups OBJECT IDENTIFIER ::= { rip2Conformance 1 } +rip2Compliances OBJECT IDENTIFIER ::= { rip2Conformance 2 } + +-- compliance statements +rip2Compliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement " + MODULE -- this module + MANDATORY-GROUPS { + rip2GlobalGroup, + rip2IfStatGroup, + rip2IfConfGroup, + rip2PeerGroup + } + GROUP rip2GlobalGroup + DESCRIPTION + "This group defines global controls for RIP-II systems." + GROUP rip2IfStatGroup + DESCRIPTION + "This group defines interface statistics for RIP-II systems." + GROUP rip2IfConfGroup + DESCRIPTION + "This group defines interface configuration for RIP-II systems." + GROUP rip2PeerGroup + DESCRIPTION + "This group defines peer information for RIP-II systems." + ::= { rip2Compliances 1 } + +-- units of conformance + +rip2GlobalGroup OBJECT-GROUP + OBJECTS { + rip2GlobalRouteChanges, + rip2GlobalQueries + } + STATUS current + DESCRIPTION + "This group defines global controls for RIP-II systems." + ::= { rip2Groups 1 } +rip2IfStatGroup OBJECT-GROUP + OBJECTS { + rip2IfStatAddress, + rip2IfStatRcvBadPackets, + rip2IfStatRcvBadRoutes, + rip2IfStatSentUpdates, + rip2IfStatStatus + } + STATUS current + DESCRIPTION + "This group defines interface statistics for RIP-II systems." + ::= { rip2Groups 2 } +rip2IfConfGroup OBJECT-GROUP + OBJECTS { + rip2IfConfAddress, + rip2IfConfAuthType, + rip2IfConfAuthKey, + rip2IfConfSend, + rip2IfConfReceive, + rip2IfConfDefaultMetric, + rip2IfConfStatus, + rip2IfConfSrcAddress + } + STATUS current + DESCRIPTION + "This group defines interface configuration for RIP-II systems." + ::= { rip2Groups 3 } +rip2PeerGroup OBJECT-GROUP + OBJECTS { + rip2PeerAddress, + rip2PeerDomain, + rip2PeerLastUpdate, + rip2PeerVersion, + rip2PeerRcvBadPackets, + rip2PeerRcvBadRoutes + } + STATUS current + DESCRIPTION + "This group defines peer information for RIP-II systems." + ::= { rip2Groups 4 } +END diff --git a/ripd/rip_debug.c b/ripd/rip_debug.c new file mode 100644 index 00000000..4f09200a --- /dev/null +++ b/ripd/rip_debug.c @@ -0,0 +1,290 @@ +/* RIP debug routines + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include +#include "command.h" +#include "ripd/rip_debug.h" + +/* For debug statement. */ +unsigned long rip_debug_event = 0; +unsigned long rip_debug_packet = 0; +unsigned long rip_debug_zebra = 0; + +DEFUN (show_debugging_rip, + show_debugging_rip_cmd, + "show debugging rip", + SHOW_STR + DEBUG_STR + RIP_STR) +{ + vty_out (vty, "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 index 00000000..3b44d0cf --- /dev/null +++ b/ripd/rip_debug.h @@ -0,0 +1,54 @@ +/* RIP debug routines + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RIP_DEBUG_H +#define _ZEBRA_RIP_DEBUG_H + +/* RIP debug event flags. */ +#define RIP_DEBUG_EVENT 0x01 + +/* RIP debug packet flags. */ +#define RIP_DEBUG_PACKET 0x01 +#define RIP_DEBUG_SEND 0x20 +#define RIP_DEBUG_RECV 0x40 +#define RIP_DEBUG_DETAIL 0x80 + +/* RIP debug zebra flags. */ +#define RIP_DEBUG_ZEBRA 0x01 + +/* Debug related macro. */ +#define IS_RIP_DEBUG_EVENT (rip_debug_event & RIP_DEBUG_EVENT) + +#define IS_RIP_DEBUG_PACKET (rip_debug_packet & RIP_DEBUG_PACKET) +#define IS_RIP_DEBUG_SEND (rip_debug_packet & RIP_DEBUG_SEND) +#define IS_RIP_DEBUG_RECV (rip_debug_packet & RIP_DEBUG_RECV) +#define IS_RIP_DEBUG_DETAIL (rip_debug_packet & RIP_DEBUG_DETAIL) + +#define IS_RIP_DEBUG_ZEBRA (rip_debug_zebra & RIP_DEBUG_ZEBRA) + +extern unsigned long rip_debug_event; +extern unsigned long rip_debug_packet; +extern unsigned long rip_debug_zebra; + +void rip_debug_init (); +void rip_debug_reset (); + +#endif /* _ZEBRA_RIP_DEBUG_H */ diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c new file mode 100644 index 00000000..06d4416b --- /dev/null +++ b/ripd/rip_interface.c @@ -0,0 +1,2001 @@ +/* Interface related function for RIP. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "command.h" +#include "if.h" +#include "sockunion.h" +#include "prefix.h" +#include "memory.h" +#include "network.h" +#include "table.h" +#include "log.h" +#include "stream.h" +#include "thread.h" +#include "zclient.h" +#include "filter.h" +#include "sockopt.h" + +#include "zebra/connected.h" + +#include "ripd/ripd.h" +#include "ripd/rip_debug.h" + +void rip_enable_apply (struct interface *); +void rip_passive_interface_apply (struct interface *); +int rip_if_down(struct interface *ifp); + +struct message ri_version_msg[] = +{ + {RI_RIP_VERSION_1, "1"}, + {RI_RIP_VERSION_2, "2"}, + {RI_RIP_VERSION_1_AND_2, "1 2"}, + {0, NULL} +}; + +/* RIP enabled network vector. */ +vector rip_enable_interface; + +/* RIP enabled interface table. */ +struct route_table *rip_enable_network; + +/* Vector to store passive-interface name. */ +vector Vrip_passive_interface; + +/* Join to the RIP version 2 multicast group. */ +int +ipv4_multicast_join (int sock, + struct in_addr group, + struct in_addr ifa, + unsigned int ifindex) +{ + int ret; + + ret = setsockopt_multicast_ipv4 (sock, + IP_ADD_MEMBERSHIP, + ifa, + group.s_addr, + ifindex); + + if (ret < 0) + zlog (NULL, LOG_INFO, "can't setsockopt IP_ADD_MEMBERSHIP %s", + strerror (errno)); + + return ret; +} + +/* Leave from the RIP version 2 multicast group. */ +int +ipv4_multicast_leave (int sock, + struct in_addr group, + struct in_addr ifa, + unsigned int ifindex) +{ + int ret; + + ret = setsockopt_multicast_ipv4 (sock, + IP_DROP_MEMBERSHIP, + ifa, + group.s_addr, + ifindex); + + if (ret < 0) + zlog (NULL, LOG_INFO, "can't setsockopt IP_DROP_MEMBERSHIP"); + + return ret; +} + +/* Allocate new RIP's interface configuration. */ +struct rip_interface * +rip_interface_new () +{ + struct rip_interface *ri; + + ri = XMALLOC (MTYPE_RIP_INTERFACE, sizeof (struct rip_interface)); + memset (ri, 0, sizeof (struct rip_interface)); + + /* Default authentication type is simple password for Cisco + compatibility. */ + /* ri->auth_type = RIP_NO_AUTH; */ + ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD; + + /* Set default split-horizon behavior. If the interface is Frame + Relay or SMDS is enabled, the default value for split-horizon is + off. But currently Zebra does detect Frame Relay or SMDS + interface. So all interface is set to split horizon. */ + ri->split_horizon_default = 1; + ri->split_horizon = ri->split_horizon_default; + + return ri; +} + +void +rip_interface_multicast_set (int sock, struct interface *ifp) +{ + int ret; + listnode node; + struct servent *sp; + struct sockaddr_in from; + + for (node = listhead (ifp->connected); node; nextnode (node)) + { + struct prefix_ipv4 *p; + struct connected *connected; + struct in_addr addr; + + connected = getdata (node); + p = (struct prefix_ipv4 *) connected->address; + + if (p->family == AF_INET) + { + addr = p->prefix; + + if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF, + addr, 0, ifp->ifindex) < 0) + { + zlog_warn ("Can't setsockopt IP_MULTICAST_IF to fd %d", sock); + return; + } + + /* Bind myself. */ + memset (&from, 0, sizeof (struct sockaddr_in)); + + /* Set RIP port. */ + sp = getservbyname ("router", "udp"); + if (sp) + from.sin_port = sp->s_port; + else + from.sin_port = htons (RIP_PORT_DEFAULT); + + /* Address shoud be any address. */ + from.sin_family = AF_INET; + from.sin_addr = addr; +#ifdef HAVE_SIN_LEN + from.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + + ret = bind (sock, (struct sockaddr *) & from, + sizeof (struct sockaddr_in)); + if (ret < 0) + { + zlog_warn ("Can't bind socket: %s", strerror (errno)); + return; + } + + return; + + } + } +} + +/* Send RIP request packet to specified interface. */ +void +rip_request_interface_send (struct interface *ifp, u_char version) +{ + struct sockaddr_in to; + + /* RIPv2 support multicast. */ + if (version == RIPv2 && if_is_multicast (ifp)) + { + + if (IS_RIP_DEBUG_EVENT) + zlog_info ("multicast request on %s", ifp->name); + + rip_request_send (NULL, ifp, version); + return; + } + + /* RIPv1 and non multicast interface. */ + if (if_is_pointopoint (ifp) || if_is_broadcast (ifp)) + { + listnode cnode; + + if (IS_RIP_DEBUG_EVENT) + zlog_info ("broadcast request to %s", ifp->name); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + struct prefix_ipv4 *p; + struct connected *connected; + + connected = getdata (cnode); + p = (struct prefix_ipv4 *) connected->destination; + + if (p->family == AF_INET) + { + memset (&to, 0, sizeof (struct sockaddr_in)); + to.sin_port = htons (RIP_PORT_DEFAULT); + to.sin_addr = p->prefix; + +#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; +} + +/* Check interface is enabled by network statement. */ +int +rip_enable_network_lookup (struct interface *ifp) +{ + struct listnode *nn; + struct connected *connected; + struct prefix_ipv4 address; + + for (nn = listhead (ifp->connected); nn; nextnode (nn)) + if ((connected = getdata (nn)) != NULL) + { + struct prefix *p; + struct route_node *node; + + p = connected->address; + + if (p->family == AF_INET) + { + address.family = AF_INET; + address.prefix = p->u.prefix4; + address.prefixlen = IPV4_MAX_BITLEN; + + node = route_node_match (rip_enable_network, + (struct prefix *)&address); + if (node) + { + route_unlock_node (node); + return 1; + } + } + } + return -1; +} + +/* Add RIP enable network. */ +int +rip_enable_network_add (struct prefix *p) +{ + struct route_node *node; + + node = route_node_get (rip_enable_network, p); + + if (node->info) + { + route_unlock_node (node); + return -1; + } + else + node->info = "enabled"; + + return 1; +} + +/* Delete RIP enable network. */ +int +rip_enable_network_delete (struct prefix *p) +{ + struct route_node *node; + + node = route_node_lookup (rip_enable_network, p); + if (node) + { + node->info = NULL; + + /* Unlock info lock. */ + route_unlock_node (node); + + /* Unlock lookup lock. */ + route_unlock_node (node); + + return 1; + } + return -1; +} + +/* Check interface is enabled by ifname statement. */ +int +rip_enable_if_lookup (char *ifname) +{ + int i; + char *str; + + for (i = 0; i < vector_max (rip_enable_interface); i++) + if ((str = vector_slot (rip_enable_interface, i)) != NULL) + if (strcmp (str, ifname) == 0) + return i; + return -1; +} + +/* Add interface to rip_enable_if. */ +int +rip_enable_if_add (char *ifname) +{ + int ret; + + ret = rip_enable_if_lookup (ifname); + if (ret >= 0) + return -1; + + vector_set (rip_enable_interface, strdup (ifname)); + + return 1; +} + +/* Delete interface from rip_enable_if. */ +int +rip_enable_if_delete (char *ifname) +{ + int index; + char *str; + + index = rip_enable_if_lookup (ifname); + if (index < 0) + return -1; + + str = vector_slot (rip_enable_interface, index); + free (str); + vector_unset (rip_enable_interface, index); + + return 1; +} + +/* Join to multicast group and send request to the interface. */ +int +rip_interface_wakeup (struct thread *t) +{ + struct interface *ifp; + struct rip_interface *ri; + + /* Get interface. */ + ifp = THREAD_ARG (t); + + ri = ifp->info; + ri->t_wakeup = NULL; + + /* Join to multicast group. */ + if (rip_multicast_join (ifp, rip->sock) < 0) + { + zlog_err ("multicast join failed, interface %s not running", ifp->name); + return 0; + } + + /* Set running flag. */ + ri->running = 1; + + /* Send RIP request to the interface. */ + rip_request_interface (ifp); + + return 0; +} + +int rip_redistribute_check (int); + +void +rip_connect_set (struct interface *ifp, int set) +{ + struct listnode *nn; + struct connected *connected; + struct prefix_ipv4 address; + + for (nn = listhead (ifp->connected); nn; nextnode (nn)) + if ((connected = getdata (nn)) != NULL) + { + struct prefix *p; + p = connected->address; + + if (p->family != AF_INET) + continue; + + address.family = AF_INET; + address.prefix = p->u.prefix4; + address.prefixlen = p->prefixlen; + apply_mask_ipv4 (&address); + + if (set) + rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, + &address, connected->ifp->ifindex, NULL); + else + { + rip_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, + &address, connected->ifp->ifindex); + if (rip_redistribute_check (ZEBRA_ROUTE_CONNECT)) + rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_REDISTRIBUTE, + &address, connected->ifp->ifindex, NULL); + } + } +} + +/* Update interface status. */ +void +rip_enable_apply (struct interface *ifp) +{ + int ret; + struct rip_interface *ri = NULL; + + /* Check interface. */ + if (if_is_loopback (ifp)) + return; + + if (! if_is_up (ifp)) + return; + + ri = ifp->info; + + /* Check network configuration. */ + ret = rip_enable_network_lookup (ifp); + + /* If the interface is matched. */ + if (ret > 0) + ri->enable_network = 1; + else + ri->enable_network = 0; + + /* Check interface name configuration. */ + ret = rip_enable_if_lookup (ifp->name); + if (ret >= 0) + ri->enable_interface = 1; + else + ri->enable_interface = 0; + + /* any interface MUST have an IPv4 address */ + if ( ! rip_if_ipv4_address_check (ifp) ) + { + ri->enable_network = 0; + ri->enable_interface = 0; + } + + /* Update running status of the interface. */ + if (ri->enable_network || ri->enable_interface) + { + if (! ri->running) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("turn on %s", ifp->name); + + /* Add interface wake up thread. */ + if (! ri->t_wakeup) + ri->t_wakeup = thread_add_timer (master, rip_interface_wakeup, + ifp, 1); + rip_connect_set (ifp, 1); + } + } + else + { + if (ri->running) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("turn off %s", ifp->name); + + /* Might as well clean up the route table as well */ + rip_if_down(ifp); + + ri->running = 0; + rip_connect_set (ifp, 0); + } + } +} + +/* Apply network configuration to all interface. */ +void +rip_enable_apply_all () +{ + struct interface *ifp; + listnode node; + + /* Check each interface. */ + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + rip_enable_apply (ifp); + } +} + +int +rip_neighbor_lookup (struct sockaddr_in *from) +{ + struct prefix_ipv4 p; + struct route_node *node; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefix = from->sin_addr; + p.prefixlen = IPV4_MAX_BITLEN; + + node = route_node_lookup (rip->neighbor, (struct prefix *) &p); + if (node) + { + route_unlock_node (node); + return 1; + } + return 0; +} + +/* Add new RIP neighbor to the neighbor tree. */ +int +rip_neighbor_add (struct prefix_ipv4 *p) +{ + struct route_node *node; + + node = route_node_get (rip->neighbor, (struct prefix *) p); + + if (node->info) + return -1; + + node->info = rip->neighbor; + + return 0; +} + +/* Delete RIP neighbor from the neighbor tree. */ +int +rip_neighbor_delete (struct prefix_ipv4 *p) +{ + struct route_node *node; + + /* Lock for look up. */ + node = route_node_lookup (rip->neighbor, (struct prefix *) p); + if (! node) + return -1; + + node->info = NULL; + + /* Unlock lookup lock. */ + route_unlock_node (node); + + /* Unlock real neighbor information lock. */ + route_unlock_node (node); + + return 0; +} + +/* Clear all network and neighbor configuration. */ +void +rip_clean_network () +{ + int i; + char *str; + struct route_node *rn; + + /* rip_enable_network. */ + for (rn = route_top (rip_enable_network); rn; rn = route_next (rn)) + if (rn->info) + { + rn->info = NULL; + route_unlock_node (rn); + } + + /* rip_enable_interface. */ + for (i = 0; i < vector_max (rip_enable_interface); i++) + if ((str = vector_slot (rip_enable_interface, i)) != NULL) + { + free (str); + vector_slot (rip_enable_interface, i) = NULL; + } +} + +/* Utility function for looking up passive interface settings. */ +int +rip_passive_interface_lookup (char *ifname) +{ + int i; + char *str; + + for (i = 0; i < vector_max (Vrip_passive_interface); i++) + if ((str = vector_slot (Vrip_passive_interface, i)) != NULL) + if (strcmp (str, ifname) == 0) + return i; + return -1; +} + +void +rip_passive_interface_apply (struct interface *ifp) +{ + int ret; + struct rip_interface *ri; + + ri = ifp->info; + + ret = rip_passive_interface_lookup (ifp->name); + if (ret < 0) + ri->passive = 0; + else + ri->passive = 1; +} + +void +rip_passive_interface_apply_all () +{ + struct interface *ifp; + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + rip_passive_interface_apply (ifp); + } +} + +/* Passive interface. */ +int +rip_passive_interface_set (struct vty *vty, char *ifname) +{ + if (rip_passive_interface_lookup (ifname) >= 0) + return CMD_WARNING; + + vector_set (Vrip_passive_interface, strdup (ifname)); + + rip_passive_interface_apply_all (); + + return CMD_SUCCESS; +} + +int +rip_passive_interface_unset (struct vty *vty, char *ifname) +{ + int i; + char *str; + + i = rip_passive_interface_lookup (ifname); + if (i < 0) + return CMD_WARNING; + + str = vector_slot (Vrip_passive_interface, i); + free (str); + vector_unset (Vrip_passive_interface, i); + + rip_passive_interface_apply_all (); + + return CMD_SUCCESS; +} + +/* Free all configured RIP passive-interface settings. */ +void +rip_passive_interface_clean () +{ + int i; + char *str; + + for (i = 0; i < vector_max (Vrip_passive_interface); i++) + if ((str = vector_slot (Vrip_passive_interface, i)) != NULL) + { + free (str); + vector_slot (Vrip_passive_interface, i) = NULL; + } + rip_passive_interface_apply_all (); +} + +/* RIP enable network or interface configuration. */ +DEFUN (rip_network, + rip_network_cmd, + "network (A.B.C.D/M|WORD)", + "Enable routing on an IP network\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Interface name\n") +{ + int ret; + struct prefix_ipv4 p; + + ret = str2prefix_ipv4 (argv[0], &p); + + if (ret) + ret = rip_enable_network_add ((struct prefix *) &p); + else + ret = rip_enable_if_add (argv[0]); + + if (ret < 0) + { + vty_out (vty, "There is a same network configuration %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + rip_enable_apply_all (); + + return CMD_SUCCESS; +} + +/* RIP enable network or interface configuration. */ +DEFUN (no_rip_network, + no_rip_network_cmd, + "no network (A.B.C.D/M|WORD)", + NO_STR + "Enable routing on an IP network\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Interface name\n") +{ + int ret; + struct prefix_ipv4 p; + + ret = str2prefix_ipv4 (argv[0], &p); + + if (ret) + ret = rip_enable_network_delete ((struct prefix *) &p); + else + ret = rip_enable_if_delete (argv[0]); + + if (ret < 0) + { + vty_out (vty, "Can't find network configuration %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + rip_enable_apply_all (); + + return CMD_SUCCESS; +} + +/* RIP neighbor configuration set. */ +DEFUN (rip_neighbor, + rip_neighbor_cmd, + "neighbor A.B.C.D", + "Specify a neighbor router\n" + "Neighbor address\n") +{ + int ret; + struct prefix_ipv4 p; + + ret = str2prefix_ipv4 (argv[0], &p); + + if (ret <= 0) + { + vty_out (vty, "Please specify address by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rip_neighbor_add (&p); + + return CMD_SUCCESS; +} + +/* RIP neighbor configuration unset. */ +DEFUN (no_rip_neighbor, + no_rip_neighbor_cmd, + "no neighbor A.B.C.D", + NO_STR + "Specify a neighbor router\n" + "Neighbor address\n") +{ + int ret; + struct prefix_ipv4 p; + + ret = str2prefix_ipv4 (argv[0], &p); + + if (ret <= 0) + { + vty_out (vty, "Please specify address by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rip_neighbor_delete (&p); + + return CMD_SUCCESS; +} + +DEFUN (ip_rip_receive_version, + ip_rip_receive_version_cmd, + "ip rip receive version (1|2)", + IP_STR + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n" + "RIP version 1\n" + "RIP version 2\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* Version 1. */ + if (atoi (argv[0]) == 1) + { + ri->ri_receive = RI_RIP_VERSION_1; + return CMD_SUCCESS; + } + if (atoi (argv[0]) == 2) + { + ri->ri_receive = RI_RIP_VERSION_2; + return CMD_SUCCESS; + } + return CMD_WARNING; +} + +DEFUN (ip_rip_receive_version_1, + ip_rip_receive_version_1_cmd, + "ip rip receive version 1 2", + IP_STR + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n" + "RIP version 1\n" + "RIP version 2\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* Version 1 and 2. */ + ri->ri_receive = RI_RIP_VERSION_1_AND_2; + return CMD_SUCCESS; +} + +DEFUN (ip_rip_receive_version_2, + ip_rip_receive_version_2_cmd, + "ip rip receive version 2 1", + IP_STR + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n" + "RIP version 2\n" + "RIP version 1\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* Version 1 and 2. */ + ri->ri_receive = RI_RIP_VERSION_1_AND_2; + return CMD_SUCCESS; +} + +DEFUN (no_ip_rip_receive_version, + no_ip_rip_receive_version_cmd, + "no ip rip receive version", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + ri->ri_receive = RI_RIP_UNSPEC; + return CMD_SUCCESS; +} + +ALIAS (no_ip_rip_receive_version, + no_ip_rip_receive_version_num_cmd, + "no ip rip receive version (1|2)", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n" + "Version 1\n" + "Version 2\n") + +DEFUN (ip_rip_send_version, + ip_rip_send_version_cmd, + "ip rip send version (1|2)", + IP_STR + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n" + "RIP version 1\n" + "RIP version 2\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* Version 1. */ + if (atoi (argv[0]) == 1) + { + ri->ri_send = RI_RIP_VERSION_1; + return CMD_SUCCESS; + } + if (atoi (argv[0]) == 2) + { + ri->ri_send = RI_RIP_VERSION_2; + return CMD_SUCCESS; + } + return CMD_WARNING; +} + +DEFUN (ip_rip_send_version_1, + ip_rip_send_version_1_cmd, + "ip rip send version 1 2", + IP_STR + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n" + "RIP version 1\n" + "RIP version 2\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* Version 1 and 2. */ + ri->ri_send = RI_RIP_VERSION_1_AND_2; + return CMD_SUCCESS; +} + +DEFUN (ip_rip_send_version_2, + ip_rip_send_version_2_cmd, + "ip rip send version 2 1", + IP_STR + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n" + "RIP version 2\n" + "RIP version 1\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* Version 1 and 2. */ + ri->ri_send = RI_RIP_VERSION_1_AND_2; + return CMD_SUCCESS; +} + +DEFUN (no_ip_rip_send_version, + no_ip_rip_send_version_cmd, + "no ip rip send version", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + ri->ri_send = RI_RIP_UNSPEC; + return CMD_SUCCESS; +} + +ALIAS (no_ip_rip_send_version, + no_ip_rip_send_version_num_cmd, + "no ip rip send version (1|2)", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n" + "Version 1\n" + "Version 2\n") + +DEFUN (ip_rip_authentication_mode, + ip_rip_authentication_mode_cmd, + "ip rip authentication mode (md5|text)", + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication mode\n" + "Keyed message digest\n" + "Clear text authentication\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + if (strncmp ("md5", argv[0], strlen (argv[0])) == 0) + ri->auth_type = RIP_AUTH_MD5; + else if (strncmp ("text", argv[0], strlen (argv[0])) == 0) + ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD; + else + { + vty_out (vty, "mode should be md5 or text%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (no_ip_rip_authentication_mode, + no_ip_rip_authentication_mode_cmd, + "no ip rip authentication mode", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication mode\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* ri->auth_type = RIP_NO_AUTH; */ + ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD; + + return CMD_SUCCESS; +} + +ALIAS (no_ip_rip_authentication_mode, + no_ip_rip_authentication_mode_type_cmd, + "no ip rip authentication mode (md5|text)", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication mode\n" + "Keyed message digest\n" + "Clear text authentication\n") + +DEFUN (ip_rip_authentication_string, + ip_rip_authentication_string_cmd, + "ip rip authentication string LINE", + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication string\n" + "Authentication string\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + if (strlen (argv[0]) > 16) + { + vty_out (vty, "%% RIPv2 authentication string must be shorter than 16%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (ri->key_chain) + { + vty_out (vty, "%% key-chain configuration exists%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (ri->auth_str) + free (ri->auth_str); + + ri->auth_str = strdup (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (no_ip_rip_authentication_string, + no_ip_rip_authentication_string_cmd, + "no ip rip authentication string", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication string\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + if (ri->auth_str) + free (ri->auth_str); + + ri->auth_str = NULL; + + return CMD_SUCCESS; +} + +ALIAS (no_ip_rip_authentication_string, + no_ip_rip_authentication_string2_cmd, + "no ip rip authentication string LINE", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication string\n" + "Authentication string\n") + +DEFUN (ip_rip_authentication_key_chain, + ip_rip_authentication_key_chain_cmd, + "ip rip authentication key-chain LINE", + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication key-chain\n" + "name of key-chain\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *) vty->index; + ri = ifp->info; + + if (ri->auth_str) + { + vty_out (vty, "%% authentication string configuration exists%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (ri->key_chain) + free (ri->key_chain); + + ri->key_chain = strdup (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (no_ip_rip_authentication_key_chain, + no_ip_rip_authentication_key_chain_cmd, + "no ip rip authentication key-chain", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication key-chain\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *) vty->index; + ri = ifp->info; + + if (ri->key_chain) + free (ri->key_chain); + + ri->key_chain = NULL; + + return CMD_SUCCESS; +} + +ALIAS (no_ip_rip_authentication_key_chain, + no_ip_rip_authentication_key_chain2_cmd, + "no ip rip authentication key-chain LINE", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication key-chain\n" + "name of key-chain\n") + +DEFUN (rip_split_horizon, + rip_split_horizon_cmd, + "ip split-horizon", + IP_STR + "Perform split horizon\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = vty->index; + ri = ifp->info; + + ri->split_horizon = 1; + return CMD_SUCCESS; +} + +DEFUN (no_rip_split_horizon, + no_rip_split_horizon_cmd, + "no ip split-horizon", + NO_STR + IP_STR + "Perform split horizon\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = vty->index; + ri = ifp->info; + + ri->split_horizon = 0; + return CMD_SUCCESS; +} + +DEFUN (rip_passive_interface, + rip_passive_interface_cmd, + "passive-interface IFNAME", + "Suppress routing updates on an interface\n" + "Interface name\n") +{ + return rip_passive_interface_set (vty, argv[0]); +} + +DEFUN (no_rip_passive_interface, + no_rip_passive_interface_cmd, + "no passive-interface IFNAME", + NO_STR + "Suppress routing updates on an interface\n" + "Interface name\n") +{ + return rip_passive_interface_unset (vty, argv[0]); +} + +/* Write rip configuration of each interface. */ +int +rip_interface_config_write (struct vty *vty) +{ + listnode node; + struct interface *ifp; + + for (node = listhead (iflist); node; nextnode (node)) + { + struct rip_interface *ri; + + ifp = getdata (node); + ri = ifp->info; + + vty_out (vty, "interface %s%s", ifp->name, + VTY_NEWLINE); + + if (ifp->desc) + vty_out (vty, " description %s%s", ifp->desc, + VTY_NEWLINE); + + /* Split horizon. */ + if (ri->split_horizon != ri->split_horizon_default) + { + if (ri->split_horizon) + vty_out (vty, " ip split-horizon%s", VTY_NEWLINE); + else + vty_out (vty, " no ip split-horizon%s", VTY_NEWLINE); + } + + /* RIP version setting. */ + if (ri->ri_send != RI_RIP_UNSPEC) + vty_out (vty, " ip rip send version %s%s", + lookup (ri_version_msg, ri->ri_send), + VTY_NEWLINE); + + if (ri->ri_receive != RI_RIP_UNSPEC) + vty_out (vty, " ip rip receive version %s%s", + lookup (ri_version_msg, ri->ri_receive), + VTY_NEWLINE); + + /* RIP authentication. */ +#if 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 index 00000000..1070fb45 --- /dev/null +++ b/ripd/rip_main.c @@ -0,0 +1,270 @@ +/* RIPd main routine. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "version.h" +#include "getopt.h" +#include "thread.h" +#include "command.h" +#include "memory.h" +#include "prefix.h" +#include "filter.h" +#include "keychain.h" +#include "log.h" + +#include "ripd/ripd.h" + +/* ripd options. */ +static struct option longopts[] = +{ + { "daemon", no_argument, NULL, 'd'}, + { "config_file", required_argument, NULL, 'f'}, + { "pid_file", required_argument, NULL, 'i'}, + { "help", no_argument, NULL, 'h'}, + { "vty_addr", required_argument, NULL, 'A'}, + { "vty_port", required_argument, NULL, 'P'}, + { "retain", no_argument, NULL, 'r'}, + { "version", no_argument, NULL, 'v'}, + { 0 } +}; + +/* Configuration file and directory. */ +char config_current[] = RIPD_DEFAULT_CONFIG; +char config_default[] = SYSCONFDIR RIPD_DEFAULT_CONFIG; +char *config_file = NULL; + +/* ripd program name */ + +/* Route retain mode flag. */ +int retain_mode = 0; + +/* RIP VTY bind address. */ +char *vty_addr = NULL; + +/* RIP VTY connection port. */ +int vty_port = RIP_VTY_PORT; + +/* Master of threads. */ +struct thread_master *master; + +/* Process ID saved for use by init system */ +char *pid_file = PATH_RIPD_PID; + +/* Help information display. */ +static void +usage (char *progname, int status) +{ + if (status != 0) + fprintf (stderr, "Try `%s --help' for more information.\n", progname); + else + { + printf ("Usage : %s [OPTION...]\n\ +Daemon which manages RIP version 1 and 2.\n\n\ +-d, --daemon Runs in daemon mode\n\ +-f, --config_file Set configuration file name\n\ +-i, --pid_file Set process identifier file name\n\ +-A, --vty_addr Set vty's bind address\n\ +-P, --vty_port Set vty's port number\n\ +-r, --retain When program terminates, retain added route by ripd.\n\ +-v, --version Print program version\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); + } + + exit (status); +} + +/* Signale wrapper. */ +RETSIGTYPE * +signal_set (int signo, void (*func)(int)) +{ + int ret; + struct sigaction sig; + struct sigaction osig; + + sig.sa_handler = func; + sigemptyset (&sig.sa_mask); + sig.sa_flags = 0; +#ifdef SA_RESTART + sig.sa_flags |= SA_RESTART; +#endif /* SA_RESTART */ + + ret = sigaction (signo, &sig, &osig); + + if (ret < 0) + return (SIG_ERR); + else + return (osig.sa_handler); +} + +/* SIGHUP handler. */ +void +sighup (int sig) +{ + zlog_info ("SIGHUP received"); + rip_clean (); + rip_reset (); + zlog_info ("ripd restarting!"); + + /* Reload config file. */ + vty_read_config (config_file, config_current, config_default); + + /* Create VTY's socket */ + vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH); + + /* Try to return to normal operation. */ +} + +/* SIGINT handler. */ +void +sigint (int sig) +{ + zlog (NULL, LOG_INFO, "Terminating on signal"); + + if (! retain_mode) + rip_clean (); + + exit (0); +} + +/* SIGUSR1 handler. */ +void +sigusr1 (int sig) +{ + zlog_rotate (NULL); +} + +/* Initialization of signal handles. */ +void +signal_init () +{ + signal_set (SIGHUP, sighup); + signal_set (SIGINT, sigint); + signal_set (SIGTERM, sigint); + signal_set (SIGPIPE, SIG_IGN); + signal_set (SIGUSR1, sigusr1); +} + +/* Main routine of ripd. */ +int +main (int argc, char **argv) +{ + char *p; + int daemon_mode = 0; + char *progname; + struct thread thread; + + /* Set umask before anything for security */ + umask (0027); + + /* Get program name. */ + progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + + /* First of all we need logging init. */ + zlog_default = openzlog (progname, ZLOG_NOLOG, ZLOG_RIP, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + + /* Command line option parse. */ + while (1) + { + int opt; + + opt = getopt_long (argc, argv, "df:hA:P:rv", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + case 'd': + daemon_mode = 1; + break; + case 'f': + config_file = optarg; + break; + case 'A': + vty_addr = optarg; + break; + case 'i': + pid_file = optarg; + break; + case 'P': + vty_port = atoi (optarg); + break; + case 'r': + retain_mode = 1; + break; + case 'v': + print_version (progname); + exit (0); + break; + case 'h': + usage (progname, 0); + break; + default: + usage (progname, 1); + break; + } + } + + /* Prepare master thread. */ + master = thread_master_create (); + + /* Library initialization. */ + signal_init (); + cmd_init (1); + vty_init (); + memory_init (); + keychain_init (); + + /* RIP related initialization. */ + rip_init (); + rip_if_init (); + rip_zclient_init (); + rip_peer_init (); + + /* Sort all installed commands. */ + sort_node (); + + /* Get configuration file. */ + vty_read_config (config_file, config_current, config_default); + + /* Change to the daemon program. */ + if (daemon_mode) + daemon (0, 0); + + /* Pid file create. */ + pid_output (pid_file); + + /* Create VTY's socket */ + vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH); + + /* Execute each thread. */ + while (thread_fetch (master, &thread)) + thread_call (&thread); + + /* Not reached. */ + exit (0); +} diff --git a/ripd/rip_offset.c b/ripd/rip_offset.c new file mode 100644 index 00000000..0d473482 --- /dev/null +++ b/ripd/rip_offset.c @@ -0,0 +1,414 @@ +/* RIP offset-list + * Copyright (C) 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "if.h" +#include "prefix.h" +#include "filter.h" +#include "command.h" +#include "linklist.h" +#include "memory.h" + +#define RIP_OFFSET_LIST_IN 0 +#define RIP_OFFSET_LIST_OUT 1 +#define RIP_OFFSET_LIST_MAX 2 + +struct rip_offset_list +{ + char *ifname; + + struct + { + char *alist_name; + /* struct access_list *alist; */ + int metric; + } direct[RIP_OFFSET_LIST_MAX]; +}; + +static struct list *rip_offset_list_master; + +int +strcmp_safe (char *s1, char *s2) +{ + if (s1 == NULL && s2 == NULL) + return 0; + if (s1 == NULL) + return -1; + if (s2 == NULL) + return 1; + return strcmp (s1, s2); +} + +struct rip_offset_list * +rip_offset_list_new () +{ + struct rip_offset_list *new; + + new = XMALLOC (MTYPE_RIP_OFFSET_LIST, sizeof (struct rip_offset_list)); + memset (new, 0, sizeof (struct rip_offset_list)); + return new; +} + +void +rip_offset_list_free (struct rip_offset_list *offset) +{ + XFREE (MTYPE_RIP_OFFSET_LIST, offset); +} + +struct rip_offset_list * +rip_offset_list_lookup (char *ifname) +{ + struct rip_offset_list *offset; + struct listnode *nn; + + LIST_LOOP (rip_offset_list_master, offset, nn) + { + if (strcmp_safe (offset->ifname, ifname) == 0) + return offset; + } + return NULL; +} + +struct rip_offset_list * +rip_offset_list_get (char *ifname) +{ + struct rip_offset_list *offset; + + offset = rip_offset_list_lookup (ifname); + if (offset) + return offset; + + offset = rip_offset_list_new (); + if (ifname) + offset->ifname = strdup (ifname); + listnode_add_sort (rip_offset_list_master, offset); + + return offset; +} + +int +rip_offset_list_set (struct vty *vty, char *alist, char *direct_str, + char *metric_str, char *ifname) +{ + int direct; + int metric; + struct rip_offset_list *offset; + + /* Check direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = RIP_OFFSET_LIST_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = RIP_OFFSET_LIST_OUT; + else + { + vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check metric. */ + metric = atoi (metric_str); + if (metric < 0 || metric > 16) + { + vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get offset-list structure with interface name. */ + offset = rip_offset_list_get (ifname); + + if (offset->direct[direct].alist_name) + free (offset->direct[direct].alist_name); + offset->direct[direct].alist_name = strdup (alist); + offset->direct[direct].metric = metric; + + return CMD_SUCCESS; +} + +int +rip_offset_list_unset (struct vty *vty, char *alist, char *direct_str, + char *metric_str, char *ifname) +{ + int direct; + int metric; + struct rip_offset_list *offset; + + /* Check direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = RIP_OFFSET_LIST_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = RIP_OFFSET_LIST_OUT; + else + { + vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check metric. */ + metric = atoi (metric_str); + if (metric < 0 || metric > 16) + { + vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get offset-list structure with interface name. */ + offset = rip_offset_list_lookup (ifname); + + if (offset) + { + if (offset->direct[direct].alist_name) + free (offset->direct[direct].alist_name); + offset->direct[direct].alist_name = NULL; + + if (offset->direct[RIP_OFFSET_LIST_IN].alist_name == NULL && + offset->direct[RIP_OFFSET_LIST_OUT].alist_name == NULL) + { + listnode_delete (rip_offset_list_master, offset); + if (offset->ifname) + free (offset->ifname); + rip_offset_list_free (offset); + } + } + else + { + vty_out (vty, "Can't find offset-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +#define OFFSET_LIST_IN_NAME(O) ((O)->direct[RIP_OFFSET_LIST_IN].alist_name) +#define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIP_OFFSET_LIST_IN].metric) + +#define OFFSET_LIST_OUT_NAME(O) ((O)->direct[RIP_OFFSET_LIST_OUT].alist_name) +#define OFFSET_LIST_OUT_METRIC(O) ((O)->direct[RIP_OFFSET_LIST_OUT].metric) + +/* If metric is modifed return 1. */ +int +rip_offset_list_apply_in (struct prefix_ipv4 *p, struct interface *ifp, + u_int32_t *metric) +{ + struct rip_offset_list *offset; + struct access_list *alist; + + /* Look up offset-list with interface name. */ + offset = rip_offset_list_lookup (ifp->name); + if (offset && OFFSET_LIST_IN_NAME (offset)) + { + alist = access_list_lookup (AFI_IP, OFFSET_LIST_IN_NAME (offset)); + + if (alist + && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) + { + *metric += OFFSET_LIST_IN_METRIC (offset); + return 1; + } + return 0; + } + /* Look up offset-list without interface name. */ + offset = rip_offset_list_lookup (NULL); + if (offset && OFFSET_LIST_IN_NAME (offset)) + { + alist = access_list_lookup (AFI_IP, OFFSET_LIST_IN_NAME (offset)); + + if (alist + && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) + { + *metric += OFFSET_LIST_IN_METRIC (offset); + return 1; + } + return 0; + } + return 0; +} + +/* If metric is modifed return 1. */ +int +rip_offset_list_apply_out (struct prefix_ipv4 *p, struct interface *ifp, + u_int32_t *metric) +{ + struct rip_offset_list *offset; + struct access_list *alist; + + /* Look up offset-list with interface name. */ + offset = rip_offset_list_lookup (ifp->name); + if (offset && OFFSET_LIST_OUT_NAME (offset)) + { + alist = access_list_lookup (AFI_IP, OFFSET_LIST_OUT_NAME (offset)); + + if (alist + && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) + { + *metric += OFFSET_LIST_OUT_METRIC (offset); + return 1; + } + return 0; + } + + /* Look up offset-list without interface name. */ + offset = rip_offset_list_lookup (NULL); + if (offset && OFFSET_LIST_OUT_NAME (offset)) + { + alist = access_list_lookup (AFI_IP, OFFSET_LIST_OUT_NAME (offset)); + + if (alist + && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) + { + *metric += OFFSET_LIST_OUT_METRIC (offset); + return 1; + } + return 0; + } + return 0; +} + +DEFUN (rip_offset_list, + rip_offset_list_cmd, + "offset-list WORD (in|out) <0-16>", + "Modify RIP metric\n" + "Access-list name\n" + "For incoming updates\n" + "For outgoing updates\n" + "Metric value\n") +{ + return rip_offset_list_set (vty, argv[0], argv[1], argv[2], NULL); +} + +DEFUN (rip_offset_list_ifname, + rip_offset_list_ifname_cmd, + "offset-list WORD (in|out) <0-16> IFNAME", + "Modify RIP metric\n" + "Access-list name\n" + "For incoming updates\n" + "For outgoing updates\n" + "Metric value\n" + "Interface to match\n") +{ + return rip_offset_list_set (vty, argv[0], argv[1], argv[2], argv[3]); +} + +DEFUN (no_rip_offset_list, + no_rip_offset_list_cmd, + "no offset-list WORD (in|out) <0-16>", + NO_STR + "Modify RIP metric\n" + "Access-list name\n" + "For incoming updates\n" + "For outgoing updates\n" + "Metric value\n") +{ + return rip_offset_list_unset (vty, argv[0], argv[1], argv[2], NULL); +} + +DEFUN (no_rip_offset_list_ifname, + no_rip_offset_list_ifname_cmd, + "no offset-list WORD (in|out) <0-16> IFNAME", + NO_STR + "Modify RIP metric\n" + "Access-list name\n" + "For incoming updates\n" + "For outgoing updates\n" + "Metric value\n" + "Interface to match\n") +{ + return rip_offset_list_unset (vty, argv[0], argv[1], argv[2], argv[3]); +} + +int +offset_list_cmp (struct rip_offset_list *o1, struct rip_offset_list *o2) +{ + return strcmp_safe (o1->ifname, o2->ifname); +} + +void +offset_list_del (struct rip_offset_list *offset) +{ + if (OFFSET_LIST_IN_NAME (offset)) + free (OFFSET_LIST_IN_NAME (offset)); + if (OFFSET_LIST_OUT_NAME (offset)) + free (OFFSET_LIST_OUT_NAME (offset)); + if (offset->ifname) + free (offset->ifname); + rip_offset_list_free (offset); +} + +void +rip_offset_init () +{ + rip_offset_list_master = list_new (); + rip_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp; + rip_offset_list_master->del = (void (*)(void *)) offset_list_del; + + install_element (RIP_NODE, &rip_offset_list_cmd); + install_element (RIP_NODE, &rip_offset_list_ifname_cmd); + install_element (RIP_NODE, &no_rip_offset_list_cmd); + install_element (RIP_NODE, &no_rip_offset_list_ifname_cmd); +} + +void +rip_offset_clean () +{ + list_delete (rip_offset_list_master); + + rip_offset_list_master = list_new (); + rip_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp; + rip_offset_list_master->del = (void (*)(void *)) offset_list_del; +} + +int +config_write_rip_offset_list (struct vty *vty) +{ + struct listnode *nn; + struct rip_offset_list *offset; + + LIST_LOOP (rip_offset_list_master, offset, nn) + { + if (! offset->ifname) + { + if (offset->direct[RIP_OFFSET_LIST_IN].alist_name) + vty_out (vty, " offset-list %s in %d%s", + offset->direct[RIP_OFFSET_LIST_IN].alist_name, + offset->direct[RIP_OFFSET_LIST_IN].metric, + VTY_NEWLINE); + if (offset->direct[RIP_OFFSET_LIST_OUT].alist_name) + vty_out (vty, " offset-list %s out %d%s", + offset->direct[RIP_OFFSET_LIST_OUT].alist_name, + offset->direct[RIP_OFFSET_LIST_OUT].metric, + VTY_NEWLINE); + } + else + { + if (offset->direct[RIP_OFFSET_LIST_IN].alist_name) + vty_out (vty, " offset-list %s in %d %s%s", + offset->direct[RIP_OFFSET_LIST_IN].alist_name, + offset->direct[RIP_OFFSET_LIST_IN].metric, + offset->ifname, VTY_NEWLINE); + if (offset->direct[RIP_OFFSET_LIST_OUT].alist_name) + vty_out (vty, " offset-list %s out %d %s%s", + offset->direct[RIP_OFFSET_LIST_OUT].alist_name, + offset->direct[RIP_OFFSET_LIST_OUT].metric, + offset->ifname, VTY_NEWLINE); + } + } + + return 0; +} diff --git a/ripd/rip_peer.c b/ripd/rip_peer.c new file mode 100644 index 00000000..20c2da73 --- /dev/null +++ b/ripd/rip_peer.c @@ -0,0 +1,211 @@ +/* RIP peer support + * Copyright (C) 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "if.h" +#include "prefix.h" +#include "command.h" +#include "linklist.h" +#include "thread.h" +#include "memory.h" + +#include "ripd/ripd.h" + +/* Linked list of RIP peer. */ +struct list *peer_list; + +struct rip_peer * +rip_peer_new () +{ + struct rip_peer *new; + + new = XMALLOC (MTYPE_RIP_PEER, sizeof (struct rip_peer)); + memset (new, 0, sizeof (struct rip_peer)); + return new; +} + +void +rip_peer_free (struct rip_peer *peer) +{ + XFREE (MTYPE_RIP_PEER, peer); +} + +struct rip_peer * +rip_peer_lookup (struct in_addr *addr) +{ + struct rip_peer *peer; + struct listnode *nn; + + LIST_LOOP (peer_list, peer, nn) + { + if (IPV4_ADDR_SAME (&peer->addr, addr)) + return peer; + } + return NULL; +} + +struct rip_peer * +rip_peer_lookup_next (struct in_addr *addr) +{ + struct rip_peer *peer; + struct listnode *nn; + + LIST_LOOP (peer_list, peer, nn) + { + if (htonl (peer->addr.s_addr) > htonl (addr->s_addr)) + return peer; + } + return NULL; +} + +/* RIP peer is timeout. */ +int +rip_peer_timeout (struct thread *t) +{ + struct rip_peer *peer; + + peer = THREAD_ARG (t); + listnode_delete (peer_list, peer); + rip_peer_free (peer); + + return 0; +} + +/* Get RIP peer. At the same time update timeout thread. */ +struct rip_peer * +rip_peer_get (struct in_addr *addr) +{ + struct rip_peer *peer; + + peer = rip_peer_lookup (addr); + + if (peer) + { + if (peer->t_timeout) + thread_cancel (peer->t_timeout); + } + else + { + peer = rip_peer_new (); + peer->addr = *addr; + listnode_add_sort (peer_list, peer); + } + + /* Update timeout thread. */ + peer->t_timeout = thread_add_timer (master, rip_peer_timeout, peer, + RIP_PEER_TIMER_DEFAULT); + + /* Last update time set. */ + time (&peer->uptime); + + return peer; +} + +void +rip_peer_update (struct sockaddr_in *from, u_char version) +{ + struct rip_peer *peer; + peer = rip_peer_get (&from->sin_addr); + peer->version = version; +} + +void +rip_peer_bad_route (struct sockaddr_in *from) +{ + struct rip_peer *peer; + peer = rip_peer_get (&from->sin_addr); + peer->recv_badroutes++; +} + +void +rip_peer_bad_packet (struct sockaddr_in *from) +{ + struct rip_peer *peer; + peer = rip_peer_get (&from->sin_addr); + peer->recv_badpackets++; +} + +/* Display peer uptime. */ +char * +rip_peer_uptime (struct rip_peer *peer, char *buf, size_t len) +{ + time_t uptime; + struct tm *tm; + + /* If there is no connection has been done before print `never'. */ + if (peer->uptime == 0) + { + snprintf (buf, len, "never "); + return buf; + } + + /* Get current time. */ + uptime = time (NULL); + uptime -= peer->uptime; + tm = gmtime (&uptime); + + /* Making formatted timer strings. */ +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + + if (uptime < ONE_DAY_SECOND) + snprintf (buf, len, "%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (uptime < ONE_WEEK_SECOND) + snprintf (buf, len, "%dd%02dh%02dm", + tm->tm_yday, tm->tm_hour, tm->tm_min); + else + snprintf (buf, len, "%02dw%dd%02dh", + tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + return buf; +} + +void +rip_peer_display (struct vty *vty) +{ + struct rip_peer *peer; + struct listnode *nn; +#define RIP_UPTIME_LEN 25 + char timebuf[RIP_UPTIME_LEN]; + + LIST_LOOP (peer_list, peer, nn) + { + vty_out (vty, " %-16s %9d %9d %9d %s%s", inet_ntoa (peer->addr), + peer->recv_badpackets, peer->recv_badroutes, + ZEBRA_RIP_DISTANCE_DEFAULT, + rip_peer_uptime (peer, timebuf, RIP_UPTIME_LEN), + VTY_NEWLINE); + } +} + +int +rip_peer_list_cmp (struct rip_peer *p1, struct rip_peer *p2) +{ + return htonl (p1->addr.s_addr) > htonl (p2->addr.s_addr); +} + +void +rip_peer_init () +{ + peer_list = list_new (); + peer_list->cmp = (int (*)(void *, void *)) rip_peer_list_cmp; +} diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c new file mode 100644 index 00000000..791de412 --- /dev/null +++ b/ripd/rip_routemap.c @@ -0,0 +1,898 @@ +/* RIPv2 routemap. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "memory.h" +#include "prefix.h" +#include "routemap.h" +#include "command.h" +#include "filter.h" +#include "log.h" +#include "sockunion.h" /* for inet_aton () */ +#include "plist.h" + +#include "ripd/ripd.h" + +/* Add rip route map rule. */ +int +rip_route_match_add (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_add_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Delete rip route map rule. */ +int +rip_route_match_delete (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_delete_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Add rip route map rule. */ +int +rip_route_set_add (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_add_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Delete rip route map rule. */ +int +rip_route_set_delete (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_delete_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Hook function for updating route_map assignment. */ +void +rip_route_map_update () +{ + int i; + + if (rip) + { + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + { + if (rip->route_map[i].name) + rip->route_map[i].map = + route_map_lookup_by_name (rip->route_map[i].name); + } + } +} + +/* `match metric METRIC' */ +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_metric (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_int32_t *metric; + struct rip_info *rinfo; + + if (type == RMAP_RIP) + { + metric = rule; + rinfo = object; + + if (rinfo->metric == *metric) + return RMAP_MATCH; + else + return RMAP_NOMATCH; + } + return RMAP_NOMATCH; +} + +/* Route map `match metric' match statement. `arg' is METRIC value */ +void * +route_match_metric_compile (char *arg) +{ + u_int32_t *metric; + + metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); + *metric = atoi (arg); + + if(*metric > 0) + return metric; + + XFREE (MTYPE_ROUTE_MAP_COMPILED, metric); + return NULL; +} + +/* Free route map's compiled `match metric' value. */ +void +route_match_metric_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for metric matching. */ +struct route_map_rule_cmd route_match_metric_cmd = +{ + "metric", + route_match_metric, + route_match_metric_compile, + route_match_metric_free +}; + +/* `match interface IFNAME' */ +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_interface (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct rip_info *rinfo; + struct interface *ifp; + char *ifname; + + if (type == RMAP_RIP) + { + ifname = rule; + ifp = if_lookup_by_name(ifname); + + if (!ifp) + return RMAP_NOMATCH; + + rinfo = object; + + if (rinfo->ifindex_out == ifp->ifindex) + return RMAP_MATCH; + else + return RMAP_NOMATCH; + } + return RMAP_NOMATCH; +} + +/* Route map `match interface' match statement. `arg' is IFNAME value */ +/* XXX I don`t know if I need to check does interface exist? */ +void * +route_match_interface_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `match interface' value. */ +void +route_match_interface_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for interface matching. */ +struct route_map_rule_cmd route_match_interface_cmd = +{ + "interface", + route_match_interface, + route_match_interface_compile, + route_match_interface_free +}; + +/* `match ip next-hop IP_ACCESS_LIST' */ + +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_ip_next_hop (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; + struct rip_info *rinfo; + struct prefix_ipv4 p; + + if (type == RMAP_RIP) + { + rinfo = object; + p.family = AF_INET; + p.prefix = rinfo->nexthop; + p.prefixlen = IPV4_MAX_BITLEN; + + alist = access_list_lookup (AFI_IP, (char *) rule); + if (alist == NULL) + return RMAP_NOMATCH; + + return (access_list_apply (alist, &p) == FILTER_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +/* Route map `ip next-hop' match statement. `arg' should be + access-list name. */ +void * +route_match_ip_next_hop_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `. */ +void +route_match_ip_next_hop_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip next-hop matching. */ +struct route_map_rule_cmd route_match_ip_next_hop_cmd = +{ + "ip next-hop", + route_match_ip_next_hop, + route_match_ip_next_hop_compile, + route_match_ip_next_hop_free +}; + +/* `match ip next-hop prefix-list PREFIX_LIST' */ + +route_map_result_t +route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; + struct rip_info *rinfo; + struct prefix_ipv4 p; + + if (type == RMAP_RIP) + { + rinfo = object; + p.family = AF_INET; + p.prefix = rinfo->nexthop; + p.prefixlen = IPV4_MAX_BITLEN; + + plist = prefix_list_lookup (AFI_IP, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, &p) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ip_next_hop_prefix_list_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ip_next_hop_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = +{ + "ip next-hop prefix-list", + route_match_ip_next_hop_prefix_list, + route_match_ip_next_hop_prefix_list_compile, + route_match_ip_next_hop_prefix_list_free +}; + +/* `match ip address IP_ACCESS_LIST' */ + +/* Match function should return 1 if match is success else return + zero. */ +route_map_result_t +route_match_ip_address (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; + + if (type == RMAP_RIP) + { + alist = access_list_lookup (AFI_IP, (char *) rule); + if (alist == NULL) + return RMAP_NOMATCH; + + return (access_list_apply (alist, prefix) == FILTER_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +/* Route map `ip address' match statement. `arg' should be + access-list name. */ +void * +route_match_ip_address_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_ip_address_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip address matching. */ +struct route_map_rule_cmd route_match_ip_address_cmd = +{ + "ip address", + route_match_ip_address, + route_match_ip_address_compile, + route_match_ip_address_free +}; + +/* `match ip address prefix-list PREFIX_LIST' */ + +route_map_result_t +route_match_ip_address_prefix_list (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; + + if (type == RMAP_RIP) + { + plist = prefix_list_lookup (AFI_IP, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ip_address_prefix_list_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ip_address_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = +{ + "ip address prefix-list", + route_match_ip_address_prefix_list, + route_match_ip_address_prefix_list_compile, + route_match_ip_address_prefix_list_free +}; + +/* `set metric METRIC' */ + +/* Set metric to attribute. */ +route_map_result_t +route_set_metric (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_int32_t *metric; + struct rip_info *rinfo; + + if (type == RMAP_RIP) + { + /* Fetch routemap's rule information. */ + metric = rule; + rinfo = object; + + /* Set metric out value. */ + rinfo->metric_out = *metric; + rinfo->metric_set = 1; + } + return RMAP_OKAY; +} + +/* set metric compilation. */ +void * +route_set_metric_compile (char *arg) +{ + u_int32_t *metric; + + metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); + *metric = atoi (arg); + + return metric; + +#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 +}; + +#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 index 00000000..dc2b6212 --- /dev/null +++ b/ripd/rip_snmp.c @@ -0,0 +1,577 @@ +/* RIP SNMP support + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#ifdef HAVE_SNMP +#include +#include +#include + +#include "if.h" +#include "log.h" +#include "prefix.h" +#include "command.h" +#include "table.h" +#include "smux.h" + +#include "ripd/ripd.h" + +/* RIPv2-MIB. */ +#define RIPV2MIB 1,3,6,1,2,1,23 + +/* Zebra enterprise RIP MIB. This variable is used for register + RIPv2-MIB to SNMP agent under SMUX protocol. */ +#define RIPDOID 1,3,6,1,4,1,3317,1,2,3 + +/* RIPv2-MIB rip2Globals values. */ +#define RIP2GLOBALROUTECHANGES 1 +#define RIP2GLOBALQUERIES 2 + +/* RIPv2-MIB rip2IfStatEntry. */ +#define RIP2IFSTATENTRY 1 + +/* RIPv2-MIB rip2IfStatTable. */ +#define RIP2IFSTATADDRESS 1 +#define RIP2IFSTATRCVBADPACKETS 2 +#define RIP2IFSTATRCVBADROUTES 3 +#define RIP2IFSTATSENTUPDATES 4 +#define RIP2IFSTATSTATUS 5 + +/* RIPv2-MIB rip2IfConfTable. */ +#define RIP2IFCONFADDRESS 1 +#define RIP2IFCONFDOMAIN 2 +#define RIP2IFCONFAUTHTYPE 3 +#define RIP2IFCONFAUTHKEY 4 +#define RIP2IFCONFSEND 5 +#define RIP2IFCONFRECEIVE 6 +#define RIP2IFCONFDEFAULTMETRIC 7 +#define RIP2IFCONFSTATUS 8 +#define RIP2IFCONFSRCADDRESS 9 + +/* RIPv2-MIB rip2PeerTable. */ +#define RIP2PEERADDRESS 1 +#define RIP2PEERDOMAIN 2 +#define RIP2PEERLASTUPDATE 3 +#define RIP2PEERVERSION 4 +#define RIP2PEERRCVBADPACKETS 5 +#define RIP2PEERRCVBADROUTES 6 + +/* SNMP value hack. */ +#define COUNTER ASN_COUNTER +#define INTEGER ASN_INTEGER +#define TIMETICKS ASN_TIMETICKS +#define IPADDRESS ASN_IPADDRESS +#define STRING ASN_OCTET_STR + +/* Define SNMP local variables. */ +SNMP_LOCAL_VARIABLES + +/* RIP-MIB instances. */ +oid rip_oid [] = { RIPV2MIB }; +oid ripd_oid [] = { RIPDOID }; + +/* Interface cache table sorted by interface's address. */ +struct route_table *rip_ifaddr_table; + +/* Hook functions. */ +static u_char *rip2Globals (); +static u_char *rip2IfStatEntry (); +static u_char *rip2IfConfAddress (); +static u_char *rip2PeerTable (); + +struct variable rip_variables[] = +{ + /* RIP Global Counters. */ + {RIP2GLOBALROUTECHANGES, COUNTER, RONLY, rip2Globals, + 2, {1, 1}}, + {RIP2GLOBALQUERIES, COUNTER, RONLY, rip2Globals, + 2, {1, 2}}, + /* RIP Interface Tables. */ + {RIP2IFSTATADDRESS, IPADDRESS, RONLY, rip2IfStatEntry, + 3, {2, 1, 1}}, + {RIP2IFSTATRCVBADPACKETS, COUNTER, RONLY, rip2IfStatEntry, + 3, {2, 1, 2}}, + {RIP2IFSTATRCVBADROUTES, COUNTER, RONLY, rip2IfStatEntry, + 3, {2, 1, 3}}, + {RIP2IFSTATSENTUPDATES, COUNTER, RONLY, rip2IfStatEntry, + 3, {2, 1, 4}}, + {RIP2IFSTATSTATUS, COUNTER, RWRITE, rip2IfStatEntry, + 3, {2, 1, 5}}, + {RIP2IFCONFADDRESS, IPADDRESS, RONLY, rip2IfConfAddress, + /* RIP Interface Configuration Table. */ + 3, {3, 1, 1}}, + {RIP2IFCONFDOMAIN, STRING, RONLY, rip2IfConfAddress, + 3, {3, 1, 2}}, + {RIP2IFCONFAUTHTYPE, COUNTER, RONLY, rip2IfConfAddress, + 3, {3, 1, 3}}, + {RIP2IFCONFAUTHKEY, STRING, RONLY, rip2IfConfAddress, + 3, {3, 1, 4}}, + {RIP2IFCONFSEND, COUNTER, RONLY, rip2IfConfAddress, + 3, {3, 1, 5}}, + {RIP2IFCONFRECEIVE, COUNTER, RONLY, rip2IfConfAddress, + 3, {3, 1, 6}}, + {RIP2IFCONFDEFAULTMETRIC, COUNTER, RONLY, rip2IfConfAddress, + 3, {3, 1, 7}}, + {RIP2IFCONFSTATUS, COUNTER, RONLY, rip2IfConfAddress, + 3, {3, 1, 8}}, + {RIP2IFCONFSRCADDRESS, IPADDRESS, RONLY, rip2IfConfAddress, + 3, {3, 1, 9}}, + {RIP2PEERADDRESS, IPADDRESS, RONLY, rip2PeerTable, + /* RIP Peer Table. */ + 3, {4, 1, 1}}, + {RIP2PEERDOMAIN, INTEGER, RONLY, rip2PeerTable, + 3, {4, 1, 2}}, + {RIP2PEERLASTUPDATE, TIMETICKS, RONLY, rip2PeerTable, + 3, {4, 1, 3}}, + {RIP2PEERVERSION, INTEGER, RONLY, rip2PeerTable, + 3, {4, 1, 4}}, + {RIP2PEERRCVBADPACKETS, COUNTER, RONLY, rip2PeerTable, + 3, {4, 1, 5}}, + {RIP2PEERRCVBADROUTES, COUNTER, RONLY, rip2PeerTable, + 3, {4, 1, 6}} +}; + +static u_char * +rip2Globals (struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + if (smux_header_generic(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + /* Retrun global counter. */ + switch (v->magic) + { + case RIP2GLOBALROUTECHANGES: + return SNMP_INTEGER (rip_global_route_changes); + break; + case RIP2GLOBALQUERIES: + return SNMP_INTEGER (rip_global_queries); + break; + default: + return NULL; + break; + } + return NULL; +} + +void +rip_ifaddr_add (struct interface *ifp, struct connected *ifc) +{ + struct prefix *p; + struct route_node *rn; + + p = ifc->address; + + if (p->family != AF_INET) + return; + + rn = route_node_get (rip_ifaddr_table, p); + rn->info = ifp; +} + +void +rip_ifaddr_delete (struct interface *ifp, struct connected *ifc) +{ + struct prefix *p; + struct route_node *rn; + struct interface *i; + + p = ifc->address; + + if (p->family != AF_INET) + return; + + rn = route_node_lookup (rip_ifaddr_table, p); + if (! rn) + return; + i = rn->info; + if (rn && !strncmp(i->name,ifp->name,INTERFACE_NAMSIZ)) + { + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + } +} + +struct interface * +rip_ifaddr_lookup_next (struct in_addr *addr) +{ + struct prefix_ipv4 p; + struct route_node *rn; + struct interface *ifp; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.prefix = *addr; + + rn = route_node_get (rip_ifaddr_table, (struct prefix *) &p); + + for (rn = route_next (rn); rn; rn = route_next (rn)) + if (rn->info) + break; + + if (rn && rn->info) + { + ifp = rn->info; + *addr = rn->p.u.prefix4; + route_unlock_node (rn); + return ifp; + } + return NULL; +} + +static struct interface * +rip2IfLookup (struct variable *v, oid name[], size_t *length, + struct in_addr *addr, int exact) +{ + int len; + struct interface *ifp; + + if (exact) + { + /* Check the length. */ + if (*length - v->namelen != sizeof (struct in_addr)) + return NULL; + + oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); + + return if_lookup_exact_address (*addr); + } + else + { + len = *length - v->namelen; + if (len > 4) len = 4; + + oid2in_addr (name + v->namelen, len, addr); + + ifp = rip_ifaddr_lookup_next (addr); + + if (ifp == NULL) + return NULL; + + oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr)); + + *length = v->namelen + sizeof (struct in_addr); + + return ifp; + } + return NULL; +} + +static struct rip_peer * +rip2PeerLookup (struct variable *v, oid name[], size_t *length, + struct in_addr *addr, int exact) +{ + int len; + struct rip_peer *peer; + + if (exact) + { + /* Check the length. */ + if (*length - v->namelen != sizeof (struct in_addr) + 1) + return NULL; + + oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); + + peer = rip_peer_lookup (addr); + + if (peer->domain == name[v->namelen + sizeof (struct in_addr)]) + return peer; + + return NULL; + } + else + { + len = *length - v->namelen; + if (len > 4) len = 4; + + oid2in_addr (name + v->namelen, len, addr); + + len = *length - v->namelen; + peer = rip_peer_lookup (addr); + if (peer) + { + if ((len < sizeof (struct in_addr) + 1) || + (peer->domain > name[v->namelen + sizeof (struct in_addr)])) + { + oid_copy_addr (name + v->namelen, &peer->addr, + sizeof (struct in_addr)); + name[v->namelen + sizeof (struct in_addr)] = peer->domain; + *length = sizeof (struct in_addr) + v->namelen + 1; + return peer; + } + } + peer = rip_peer_lookup_next (addr); + + if (! peer) + return NULL; + + oid_copy_addr (name + v->namelen, &peer->addr, + sizeof (struct in_addr)); + name[v->namelen + sizeof (struct in_addr)] = peer->domain; + *length = sizeof (struct in_addr) + v->namelen + 1; + + return peer; + } + return NULL; +} + +static u_char * +rip2IfStatEntry (struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + struct interface *ifp; + struct rip_interface *ri; + static struct in_addr addr; + static long valid = SNMP_VALID; + + memset (&addr, 0, sizeof (struct in_addr)); + + /* Lookup interface. */ + ifp = rip2IfLookup (v, name, length, &addr, exact); + if (! ifp) + return NULL; + + /* Fetch rip_interface information. */ + ri = ifp->info; + + switch (v->magic) + { + case RIP2IFSTATADDRESS: + return SNMP_IPADDRESS (addr); + break; + case RIP2IFSTATRCVBADPACKETS: + *var_len = sizeof (long); + return (u_char *) &ri->recv_badpackets; + + case RIP2IFSTATRCVBADROUTES: + *var_len = sizeof (long); + return (u_char *) &ri->recv_badroutes; + + case RIP2IFSTATSENTUPDATES: + *var_len = sizeof (long); + return (u_char *) &ri->sent_updates; + + case RIP2IFSTATSTATUS: + *var_len = sizeof (long); + v->type = ASN_INTEGER; + return (u_char *) &valid; + + default: + return NULL; + + } + return NULL; +} + +static long +rip2IfConfSend (struct rip_interface *ri) +{ +#define doNotSend 1 +#define ripVersion1 2 +#define rip1Compatible 3 +#define ripVersion2 4 +#define ripV1Demand 5 +#define ripV2Demand 6 + + if (! ri->running) + return doNotSend; + + if (ri->ri_send & RIPv2) + return ripVersion2; + else if (ri->ri_send & RIPv1) + return ripVersion1; + else if (rip) + { + if (rip->version == RIPv2) + return ripVersion2; + else if (rip->version == RIPv1) + return ripVersion1; + } + return doNotSend; +} + +static long +rip2IfConfReceive (struct rip_interface *ri) +{ +#define rip1 1 +#define rip2 2 +#define rip1OrRip2 3 +#define doNotReceive 4 + + if (! ri->running) + return doNotReceive; + + if (ri->ri_receive == RI_RIP_VERSION_1_AND_2) + return rip1OrRip2; + else if (ri->ri_receive & RIPv2) + return ripVersion2; + else if (ri->ri_receive & RIPv1) + return ripVersion1; + else + return doNotReceive; +} + +static u_char * +rip2IfConfAddress (struct variable *v, oid name[], size_t *length, + int exact, size_t *val_len, WriteMethod **write_method) +{ + static struct in_addr addr; + static long valid = SNMP_INVALID; + static long domain = 0; + static long config = 0; + static u_int auth = 0; + struct interface *ifp; + struct rip_interface *ri; + + memset (&addr, 0, sizeof (struct in_addr)); + + /* Lookup interface. */ + ifp = rip2IfLookup (v, name, length, &addr, exact); + if (! ifp) + return NULL; + + /* Fetch rip_interface information. */ + ri = ifp->info; + + switch (v->magic) + { + case RIP2IFCONFADDRESS: + *val_len = sizeof (struct in_addr); + return (u_char *) &addr; + + case RIP2IFCONFDOMAIN: + *val_len = 2; + return (u_char *) &domain; + + case RIP2IFCONFAUTHTYPE: + auth = ri->auth_type; + *val_len = sizeof (long); + v->type = ASN_INTEGER; + return (u_char *)&auth; + + case RIP2IFCONFAUTHKEY: + *val_len = 0; + return (u_char *) &domain; + case RIP2IFCONFSEND: + config = rip2IfConfSend (ri); + *val_len = sizeof (long); + v->type = ASN_INTEGER; + return (u_char *) &config; + case RIP2IFCONFRECEIVE: + config = rip2IfConfReceive (ri); + *val_len = sizeof (long); + v->type = ASN_INTEGER; + return (u_char *) &config; + + case RIP2IFCONFDEFAULTMETRIC: + *val_len = sizeof (long); + v->type = ASN_INTEGER; + return (u_char *) &ifp->metric; + case RIP2IFCONFSTATUS: + *val_len = sizeof (long); + v->type = ASN_INTEGER; + return (u_char *) &valid; + case RIP2IFCONFSRCADDRESS: + *val_len = sizeof (struct in_addr); + return (u_char *) &addr; + + default: + return NULL; + + } + return NULL; +} + +static u_char * +rip2PeerTable (struct variable *v, oid name[], size_t *length, + int exact, size_t *val_len, WriteMethod **write_method) +{ + static struct in_addr addr; + static int version; + /* static time_t uptime; */ + + struct rip_peer *peer; + + memset (&addr, 0, sizeof (struct in_addr)); + + /* Lookup interface. */ + peer = rip2PeerLookup (v, name, length, &addr, exact); + if (! peer) + return NULL; + + switch (v->magic) + { + case RIP2PEERADDRESS: + *val_len = sizeof (struct in_addr); + return (u_char *) &peer->addr; + + case RIP2PEERDOMAIN: + *val_len = sizeof (int); + return (u_char *) &peer->domain; + + case RIP2PEERLASTUPDATE: +#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 index 00000000..b6caf3b0 --- /dev/null +++ b/ripd/rip_zebra.c @@ -0,0 +1,691 @@ +/* RIPd and zebra interface. + * Copyright (C) 1997, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "command.h" +#include "prefix.h" +#include "stream.h" +#include "routemap.h" +#include "zclient.h" +#include "log.h" +#include "ripd/ripd.h" +#include "ripd/rip_debug.h" + +/* All information about zebra. */ +struct zclient *zclient = NULL; + +/* Callback prototypes for zebra client service. */ +int rip_interface_add (int, struct zclient *, zebra_size_t); +int rip_interface_delete (int, struct zclient *, zebra_size_t); +int rip_interface_address_add (int, struct zclient *, zebra_size_t); +int rip_interface_address_delete (int, struct zclient *, zebra_size_t); +int rip_interface_up (int, struct zclient *, zebra_size_t); +int rip_interface_down (int, struct zclient *, zebra_size_t); + +/* RIPd to zebra command interface. */ +void +rip_zebra_ipv4_add (struct prefix_ipv4 *p, struct in_addr *nexthop, + u_int32_t metric, u_char distance) +{ + struct zapi_ipv4 api; + + if (zclient->redist[ZEBRA_ROUTE_RIP]) + { + api.type = ZEBRA_ROUTE_RIP; + api.flags = 0; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api.nexthop = &nexthop; + api.ifindex_num = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); + api.metric = metric; + + if (distance && distance != ZEBRA_RIP_DISTANCE_DEFAULT) + { + SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); + api.distance = distance; + } + + zapi_ipv4_add (zclient, p, &api); + + rip_global_route_changes++; + } +} + +void +rip_zebra_ipv4_delete (struct prefix_ipv4 *p, struct in_addr *nexthop, + u_int32_t metric) +{ + struct zapi_ipv4 api; + + if (zclient->redist[ZEBRA_ROUTE_RIP]) + { + api.type = ZEBRA_ROUTE_RIP; + api.flags = 0; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api.nexthop = &nexthop; + api.ifindex_num = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); + api.metric = metric; + + zapi_ipv4_delete (zclient, p, &api); + + rip_global_route_changes++; + } +} + +/* Zebra route add and delete treatment. */ +int +rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) +{ + struct stream *s; + struct zapi_ipv4 api; + unsigned long ifindex; + struct in_addr nexthop; + struct prefix_ipv4 p; + + s = zclient->ibuf; + ifindex = 0; + nexthop.s_addr = 0; + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.flags = stream_getc (s); + api.message = stream_getc (s); + + /* IPv4 prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = stream_getc (s); + stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + { + api.nexthop_num = stream_getc (s); + nexthop.s_addr = stream_get_ipv4 (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) + { + api.ifindex_num = stream_getc (s); + ifindex = stream_getl (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + + /* Then fetch IPv4 prefixes. */ + if (command == ZEBRA_IPV4_ROUTE_ADD) + rip_redistribute_add (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex, &nexthop); + else + rip_redistribute_delete (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex); + + return 0; +} + +void +rip_zclient_reset () +{ + zclient_reset (zclient); +} + +/* RIP route-map set for redistribution */ +void +rip_routemap_set (int type, char *name) +{ + if (rip->route_map[type].name) + free(rip->route_map[type].name); + + rip->route_map[type].name = strdup (name); + rip->route_map[type].map = route_map_lookup_by_name (name); +} + +void +rip_redistribute_metric_set (int type, int metric) +{ + rip->route_map[type].metric_config = 1; + rip->route_map[type].metric = metric; +} + +int +rip_metric_unset (int type,int metric) +{ +#define DONT_CARE_METRIC_RIP 17 + if (metric != DONT_CARE_METRIC_RIP && + rip->route_map[type].metric != metric) + return 1; + rip->route_map[type].metric_config = 0; + rip->route_map[type].metric = 0; + return 0; +} + +/* RIP route-map unset for redistribution */ +int +rip_routemap_unset (int type,char *name) +{ + if (! rip->route_map[type].name || + (name != NULL && strcmp(rip->route_map[type].name,name))) + return 1; + + free (rip->route_map[type].name); + rip->route_map[type].name = NULL; + rip->route_map[type].map = NULL; + + return 0; +} + +/* Redistribution types */ +static struct { + int type; + int str_min_len; + char *str; +} redist_type[] = { + {ZEBRA_ROUTE_KERNEL, 1, "kernel"}, + {ZEBRA_ROUTE_CONNECT, 1, "connected"}, + {ZEBRA_ROUTE_STATIC, 1, "static"}, + {ZEBRA_ROUTE_OSPF, 1, "ospf"}, + {ZEBRA_ROUTE_BGP, 1, "bgp"}, + {0, 0, NULL} +}; + +DEFUN (router_zebra, + router_zebra_cmd, + "router zebra", + "Enable a routing process\n" + "Make connection to zebra daemon\n") +{ + vty->node = ZEBRA_NODE; + zclient->enable = 1; + zclient_start (zclient); + return CMD_SUCCESS; +} + +DEFUN (no_router_zebra, + no_router_zebra_cmd, + "no router zebra", + NO_STR + "Enable a routing process\n" + "Make connection to zebra daemon\n") +{ + zclient->enable = 0; + zclient_stop (zclient); + return CMD_SUCCESS; +} + +int +rip_redistribute_set (int type) +{ + if (zclient->redist[type]) + return CMD_SUCCESS; + + zclient->redist[type] = 1; + + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type); + + return CMD_SUCCESS; +} + +int +rip_redistribute_unset (int type) +{ + if (! zclient->redist[type]) + return CMD_SUCCESS; + + zclient->redist[type] = 0; + + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type); + + /* Remove the routes from RIP table. */ + rip_redistribute_withdraw (type); + + return CMD_SUCCESS; +} + +int +rip_redistribute_check (int type) +{ + return (zclient->redist[type]); +} + +void +rip_redistribute_clean () +{ + int i; + + for (i = 0; redist_type[i].str; i++) + { + if (zclient->redist[redist_type[i].type]) + { + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, + zclient->sock, redist_type[i].type); + + zclient->redist[redist_type[i].type] = 0; + + /* Remove the routes from RIP table. */ + rip_redistribute_withdraw (redist_type[i].type); + } + } +} + +DEFUN (rip_redistribute_rip, + rip_redistribute_rip_cmd, + "redistribute rip", + "Redistribute information from another routing protocol\n" + "Routing Information Protocol (RIP)\n") +{ + zclient->redist[ZEBRA_ROUTE_RIP] = 1; + return CMD_SUCCESS; +} + +DEFUN (no_rip_redistribute_rip, + no_rip_redistribute_rip_cmd, + "no redistribute rip", + NO_STR + "Redistribute information from another routing protocol\n" + "Routing Information Protocol (RIP)\n") +{ + zclient->redist[ZEBRA_ROUTE_RIP] = 0; + return CMD_SUCCESS; +} + +DEFUN (rip_redistribute_type, + rip_redistribute_type_cmd, + "redistribute (kernel|connected|static|ospf|bgp)", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n") +{ + int i; + + for(i = 0; redist_type[i].str; i++) + { + if (strncmp (redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + zclient_redistribute_set (zclient, redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +DEFUN (no_rip_redistribute_type, + no_rip_redistribute_type_cmd, + "no redistribute (kernel|connected|static|ospf|bgp)", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n") +{ + int i; + + for (i = 0; redist_type[i].str; i++) + { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + rip_metric_unset (redist_type[i].type, DONT_CARE_METRIC_RIP); + rip_routemap_unset (redist_type[i].type,NULL); + rip_redistribute_unset (redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +DEFUN (rip_redistribute_type_routemap, + rip_redistribute_type_routemap_cmd, + "redistribute (kernel|connected|static|ospf|bgp) route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int i; + + for (i = 0; redist_type[i].str; i++) { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + rip_routemap_set (redist_type[i].type, argv[1]); + zclient_redistribute_set (zclient, redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +DEFUN (no_rip_redistribute_type_routemap, + no_rip_redistribute_type_routemap_cmd, + "no redistribute (kernel|connected|static|ospf|bgp) route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int i; + + for (i = 0; redist_type[i].str; i++) + { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + if (rip_routemap_unset (redist_type[i].type,argv[1])) + return CMD_WARNING; + rip_redistribute_unset (redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +DEFUN (rip_redistribute_type_metric, + rip_redistribute_type_metric_cmd, + "redistribute (kernel|connected|static|ospf|bgp) metric <0-16>", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n") +{ + int i; + int metric; + + metric = atoi (argv[1]); + + for (i = 0; redist_type[i].str; i++) { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + rip_redistribute_metric_set (redist_type[i].type, metric); + zclient_redistribute_set (zclient, redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +DEFUN (no_rip_redistribute_type_metric, + no_rip_redistribute_type_metric_cmd, + "no redistribute (kernel|connected|static|ospf|bgp) metric <0-16>", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n") +{ + int i; + + for (i = 0; redist_type[i].str; i++) + { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + if (rip_metric_unset (redist_type[i].type, atoi(argv[1]))) + return CMD_WARNING; + rip_redistribute_unset (redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +DEFUN (no_rip_redistribute_type_metric_routemap, + no_rip_redistribute_type_metric_routemap_cmd, + "no redistribute (kernel|connected|static|ospf|bgp) metric <0-16> route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int i; + + for (i = 0; redist_type[i].str; i++) + { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + if (rip_metric_unset (redist_type[i].type, atoi(argv[1]))) + return CMD_WARNING; + if (rip_routemap_unset (redist_type[i].type, argv[2])) + { + rip_redistribute_metric_set(redist_type[i].type, atoi(argv[1])); + return CMD_WARNING; + } + rip_redistribute_unset (redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +/* Default information originate. */ + +DEFUN (rip_default_information_originate, + rip_default_information_originate_cmd, + "default-information originate", + "Control distribution of default route\n" + "Distribute a default route\n") +{ + struct prefix_ipv4 p; + + if (! rip->default_information) + { + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + + rip->default_information = 1; + + rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL); + } + + return CMD_SUCCESS; +} + +DEFUN (no_rip_default_information_originate, + no_rip_default_information_originate_cmd, + "no default-information originate", + NO_STR + "Control distribution of default route\n" + "Distribute a default route\n") +{ + struct prefix_ipv4 p; + + if (rip->default_information) + { + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + + rip->default_information = 0; + + rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0); + } + + return CMD_SUCCESS; +} + +/* RIP configuration write function. */ +int +config_write_zebra (struct vty *vty) +{ + if (! zclient->enable) + { + vty_out (vty, "no router zebra%s", VTY_NEWLINE); + return 1; + } + else if (! zclient->redist[ZEBRA_ROUTE_RIP]) + { + vty_out (vty, "router zebra%s", VTY_NEWLINE); + vty_out (vty, " no redistribute rip%s", VTY_NEWLINE); + return 1; + } + return 0; +} + +int +config_write_rip_redistribute (struct vty *vty, int config_mode) +{ + int i; + char *str[] = { "system", "kernel", "connected", "static", "rip", + "ripng", "ospf", "ospf6", "bgp"}; + + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + if (i != zclient->redist_default && zclient->redist[i]) + { + if (config_mode) + { + if (rip->route_map[i].metric_config) + { + if (rip->route_map[i].name) + vty_out (vty, " redistribute %s metric %d route-map %s%s", + str[i], rip->route_map[i].metric, + rip->route_map[i].name, + VTY_NEWLINE); + else + vty_out (vty, " redistribute %s metric %d%s", + str[i], rip->route_map[i].metric, + VTY_NEWLINE); + } + else + { + if (rip->route_map[i].name) + vty_out (vty, " redistribute %s route-map %s%s", + str[i], rip->route_map[i].name, + VTY_NEWLINE); + else + vty_out (vty, " redistribute %s%s", str[i], + VTY_NEWLINE); + } + } + else + vty_out (vty, " %s", str[i]); + } + return 0; +} + +/* Zebra node structure. */ +struct cmd_node zebra_node = +{ + ZEBRA_NODE, + "%s(config-router)# ", +}; + +void +rip_zclient_init () +{ + /* Set default value to the zebra client structure. */ + zclient = zclient_new (); + zclient_init (zclient, ZEBRA_ROUTE_RIP); + zclient->interface_add = rip_interface_add; + zclient->interface_delete = rip_interface_delete; + zclient->interface_address_add = rip_interface_address_add; + zclient->interface_address_delete = rip_interface_address_delete; + zclient->ipv4_route_add = rip_zebra_read_ipv4; + zclient->ipv4_route_delete = rip_zebra_read_ipv4; + zclient->interface_up = rip_interface_up; + zclient->interface_down = rip_interface_down; + + /* Install zebra node. */ + install_node (&zebra_node, config_write_zebra); + + /* Install command elements to zebra node. */ + install_element (CONFIG_NODE, &router_zebra_cmd); + install_element (CONFIG_NODE, &no_router_zebra_cmd); + install_default (ZEBRA_NODE); + install_element (ZEBRA_NODE, &rip_redistribute_rip_cmd); + install_element (ZEBRA_NODE, &no_rip_redistribute_rip_cmd); + + /* Install command elements to rip node. */ + install_element (RIP_NODE, &rip_redistribute_type_cmd); + install_element (RIP_NODE, &rip_redistribute_type_routemap_cmd); + install_element (RIP_NODE, &rip_redistribute_type_metric_cmd); + install_element (RIP_NODE, &no_rip_redistribute_type_cmd); + install_element (RIP_NODE, &no_rip_redistribute_type_routemap_cmd); + install_element (RIP_NODE, &no_rip_redistribute_type_metric_cmd); + install_element (RIP_NODE, &no_rip_redistribute_type_metric_routemap_cmd); + install_element (RIP_NODE, &rip_default_information_originate_cmd); + install_element (RIP_NODE, &no_rip_default_information_originate_cmd); +} diff --git a/ripd/ripd.c b/ripd/ripd.c new file mode 100644 index 00000000..c017fe56 --- /dev/null +++ b/ripd/ripd.c @@ -0,0 +1,3536 @@ +/* RIP version 1 and 2. + * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "if.h" +#include "command.h" +#include "prefix.h" +#include "table.h" +#include "thread.h" +#include "memory.h" +#include "log.h" +#include "stream.h" +#include "filter.h" +#include "sockunion.h" +#include "routemap.h" +#include "plist.h" +#include "distribute.h" +#include "md5-gnu.h" +#include "keychain.h" + +#include "ripd/ripd.h" +#include "ripd/rip_debug.h" + +/* RIP Structure. */ +struct rip *rip = NULL; + +/* RIP neighbor address table. */ +struct route_table *rip_neighbor_table; + +/* RIP route changes. */ +long rip_global_route_changes = 0; + +/* RIP queries. */ +long rip_global_queries = 0; + +/* Prototypes. */ +void rip_event (enum rip_event, int); + +void rip_output_process (struct interface *, struct sockaddr_in *, + int, u_char); + +/* RIP output routes type. */ +enum +{ + rip_all_route, + rip_changed_route +}; + +/* RIP command strings. */ +struct message rip_msg[] = +{ + {RIP_REQUEST, "REQUEST"}, + {RIP_RESPONSE, "RESPONSE"}, + {RIP_TRACEON, "TRACEON"}, + {RIP_TRACEOFF, "TRACEOFF"}, + {RIP_POLL, "POLL"}, + {RIP_POLL_ENTRY, "POLL ENTRY"}, + {0, NULL} +}; + +/* Each route type's strings and default preference. */ +struct +{ + int key; + char *str; + char *str_long; +} route_info[] = +{ + { ZEBRA_ROUTE_SYSTEM, "X", "system"}, + { ZEBRA_ROUTE_KERNEL, "K", "kernel"}, + { ZEBRA_ROUTE_CONNECT, "C", "connected"}, + { ZEBRA_ROUTE_STATIC, "S", "static"}, + { ZEBRA_ROUTE_RIP, "R", "rip"}, + { ZEBRA_ROUTE_RIPNG, "R", "ripng"}, + { ZEBRA_ROUTE_OSPF, "O", "ospf"}, + { ZEBRA_ROUTE_OSPF6, "O", "ospf6"}, + { ZEBRA_ROUTE_BGP, "B", "bgp"} +}; + +/* Utility function to set boradcast option to the socket. */ +int +sockopt_broadcast (int sock) +{ + int ret; + int on = 1; + + ret = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof on); + if (ret < 0) + { + zlog_warn ("can't set sockopt SO_BROADCAST to socket %d", 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); +} + +int +rip_update_jitter (unsigned long time) +{ + return ((rand () % (time + 1)) - (time / 2)); +} + +void +rip_event (enum rip_event event, int sock) +{ + int jitter = 0; + + switch (event) + { + case RIP_READ: + rip->t_read = thread_add_read (master, rip_read, NULL, sock); + break; + case RIP_UPDATE_EVENT: + if (rip->t_update) + { + thread_cancel (rip->t_update); + rip->t_update = NULL; + } + jitter = rip_update_jitter (rip->update_time); + rip->t_update = + thread_add_timer (master, rip_update, NULL, + sock ? 2 : rip->update_time + jitter); + break; + case RIP_TRIGGERED_UPDATE: + if (rip->t_triggered_interval) + rip->trigger = 1; + else if (! rip->t_triggered_update) + rip->t_triggered_update = + thread_add_event (master, rip_triggered_update, NULL, 0); + break; + default: + break; + } +} + +DEFUN (router_rip, + router_rip_cmd, + "router rip", + "Enable a routing process\n" + "Routing Information Protocol (RIP)\n") +{ + int ret; + + /* If rip is not enabled before. */ + if (! rip) + { + ret = rip_create (); + if (ret < 0) + { + zlog_info ("Can't create RIP"); + return CMD_WARNING; + } + } + vty->node = RIP_NODE; + vty->index = rip; + + return CMD_SUCCESS; +} + +DEFUN (no_router_rip, + no_router_rip_cmd, + "no router rip", + NO_STR + "Enable a routing process\n" + "Routing Information Protocol (RIP)\n") +{ + if (rip) + rip_clean (); + return CMD_SUCCESS; +} + +DEFUN (rip_version, + rip_version_cmd, + "version <1-2>", + "Set routing protocol version\n" + "version\n") +{ + int version; + + version = atoi (argv[0]); + if (version != RIPv1 && version != RIPv2) + { + vty_out (vty, "invalid rip version %d%s", version, + VTY_NEWLINE); + return CMD_WARNING; + } + rip->version = version; + + return CMD_SUCCESS; +} + +DEFUN (no_rip_version, + no_rip_version_cmd, + "no version", + NO_STR + "Set routing protocol version\n") +{ + /* Set RIP version to the default. */ + rip->version = RIPv2; + + return CMD_SUCCESS; +} + +ALIAS (no_rip_version, + no_rip_version_val_cmd, + "no version <1-2>", + NO_STR + "Set routing protocol version\n" + "version\n") + +DEFUN (rip_route, + rip_route_cmd, + "route A.B.C.D/M", + "RIP static route configuration\n" + "IP prefix /\n") +{ + int ret; + struct prefix_ipv4 p; + struct route_node *node; + + ret = str2prefix_ipv4 (argv[0], &p); + if (ret < 0) + { + vty_out (vty, "Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + apply_mask_ipv4 (&p); + + /* For router rip configuration. */ + node = route_node_get (rip->route, (struct prefix *) &p); + + if (node->info) + { + vty_out (vty, "There is already same static route.%s", VTY_NEWLINE); + route_unlock_node (node); + return CMD_WARNING; + } + + node->info = "static"; + + rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL); + + return CMD_SUCCESS; +} + +DEFUN (no_rip_route, + no_rip_route_cmd, + "no route A.B.C.D/M", + NO_STR + "RIP static route configuration\n" + "IP prefix /\n") +{ + int ret; + struct prefix_ipv4 p; + struct route_node *node; + + ret = str2prefix_ipv4 (argv[0], &p); + if (ret < 0) + { + vty_out (vty, "Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + apply_mask_ipv4 (&p); + + /* For router rip configuration. */ + node = route_node_lookup (rip->route, (struct prefix *) &p); + if (! node) + { + vty_out (vty, "Can't find route %s.%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0); + route_unlock_node (node); + + node->info = NULL; + route_unlock_node (node); + + return CMD_SUCCESS; +} + +void +rip_update_default_metric () +{ + struct route_node *np; + struct rip_info *rinfo; + + for (np = route_top (rip->table); np; np = route_next (np)) + if ((rinfo = np->info) != NULL) + if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT) + rinfo->metric = rip->default_metric; +} + +DEFUN (rip_default_metric, + rip_default_metric_cmd, + "default-metric <1-16>", + "Set a metric of redistribute routes\n" + "Default metric\n") +{ + if (rip) + { + rip->default_metric = atoi (argv[0]); + /* rip_update_default_metric (); */ + } + return CMD_SUCCESS; +} + +DEFUN (no_rip_default_metric, + no_rip_default_metric_cmd, + "no default-metric", + NO_STR + "Set a metric of redistribute routes\n" + "Default metric\n") +{ + if (rip) + { + rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT; + /* rip_update_default_metric (); */ + } + return CMD_SUCCESS; +} + +ALIAS (no_rip_default_metric, + no_rip_default_metric_val_cmd, + "no default-metric <1-16>", + NO_STR + "Set a metric of redistribute routes\n" + "Default metric\n") + +DEFUN (rip_timers, + rip_timers_cmd, + "timers basic <5-2147483647> <5-2147483647> <5-2147483647>", + "Adjust routing timers\n" + "Basic routing protocol update timers\n" + "Routing table update timer value in second. Default is 30.\n" + "Routing information timeout timer. Default is 180.\n" + "Garbage collection timer. Default is 120.\n") +{ + unsigned long update; + unsigned long timeout; + unsigned long garbage; + char *endptr = NULL; + unsigned long RIP_TIMER_MAX = 2147483647; + unsigned long RIP_TIMER_MIN = 5; + + update = strtoul (argv[0], &endptr, 10); + if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0') + { + vty_out (vty, "update timer value error%s", VTY_NEWLINE); + return CMD_WARNING; + } + + timeout = strtoul (argv[1], &endptr, 10); + if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0') + { + vty_out (vty, "timeout timer value error%s", VTY_NEWLINE); + return CMD_WARNING; + } + + garbage = strtoul (argv[2], &endptr, 10); + if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0') + { + vty_out (vty, "garbage timer value error%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Set each timer value. */ + rip->update_time = update; + rip->timeout_time = timeout; + rip->garbage_time = garbage; + + /* Reset update timer thread. */ + rip_event (RIP_UPDATE_EVENT, 0); + + return CMD_SUCCESS; +} + +DEFUN (no_rip_timers, + no_rip_timers_cmd, + "no timers basic", + NO_STR + "Adjust routing timers\n" + "Basic routing protocol update timers\n") +{ + /* Set each timer value to the default. */ + rip->update_time = RIP_UPDATE_TIMER_DEFAULT; + rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT; + rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT; + + /* Reset update timer thread. */ + rip_event (RIP_UPDATE_EVENT, 0); + + return CMD_SUCCESS; +} + +struct route_table *rip_distance_table; + +struct rip_distance +{ + /* Distance value for the IP source prefix. */ + u_char distance; + + /* Name of the access-list to be matched. */ + char *access_list; +}; + +struct rip_distance * +rip_distance_new () +{ + struct rip_distance *new; + new = XMALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance)); + memset (new, 0, sizeof (struct rip_distance)); + return new; +} + +void +rip_distance_free (struct rip_distance *rdistance) +{ + XFREE (MTYPE_RIP_DISTANCE, rdistance); +} + +int +rip_distance_set (struct vty *vty, char *distance_str, char *ip_str, + char *access_list_str) +{ + int ret; + struct prefix_ipv4 p; + u_char distance; + struct route_node *rn; + struct rip_distance *rdistance; + + ret = str2prefix_ipv4 (ip_str, &p); + if (ret == 0) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + distance = atoi (distance_str); + + /* Get RIP distance node. */ + rn = route_node_get (rip_distance_table, (struct prefix *) &p); + if (rn->info) + { + rdistance = rn->info; + route_unlock_node (rn); + } + else + { + rdistance = rip_distance_new (); + rn->info = rdistance; + } + + /* Set distance value. */ + rdistance->distance = distance; + + /* Reset access-list configuration. */ + if (rdistance->access_list) + { + free (rdistance->access_list); + rdistance->access_list = NULL; + } + if (access_list_str) + rdistance->access_list = strdup (access_list_str); + + return CMD_SUCCESS; +} + +int +rip_distance_unset (struct vty *vty, char *distance_str, char *ip_str, + char *access_list_str) +{ + int ret; + struct prefix_ipv4 p; + u_char distance; + struct route_node *rn; + struct rip_distance *rdistance; + + ret = str2prefix_ipv4 (ip_str, &p); + if (ret == 0) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + distance = atoi (distance_str); + + rn = route_node_lookup (rip_distance_table, (struct prefix *)&p); + if (! rn) + { + vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rdistance = rn->info; + + if (rdistance->access_list) + free (rdistance->access_list); + rip_distance_free (rdistance); + + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + + return CMD_SUCCESS; +} + +void +rip_distance_reset () +{ + struct route_node *rn; + struct rip_distance *rdistance; + + for (rn = route_top (rip_distance_table); rn; rn = route_next (rn)) + if ((rdistance = rn->info) != NULL) + { + if (rdistance->access_list) + free (rdistance->access_list); + rip_distance_free (rdistance); + rn->info = NULL; + route_unlock_node (rn); + } +} + +/* Apply RIP information to distance method. */ +u_char +rip_distance_apply (struct rip_info *rinfo) +{ + struct route_node *rn; + struct prefix_ipv4 p; + struct rip_distance *rdistance; + struct access_list *alist; + + if (! rip) + return 0; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefix = rinfo->from; + p.prefixlen = IPV4_MAX_BITLEN; + + /* Check source address. */ + rn = route_node_match (rip_distance_table, (struct prefix *) &p); + if (rn) + { + rdistance = rn->info; + route_unlock_node (rn); + + if (rdistance->access_list) + { + alist = access_list_lookup (AFI_IP, rdistance->access_list); + if (alist == NULL) + return 0; + if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY) + return 0; + + return rdistance->distance; + } + else + return rdistance->distance; + } + + if (rip->distance) + return rip->distance; + + return 0; +} + +void +rip_distance_show (struct vty *vty) +{ + struct route_node *rn; + struct rip_distance *rdistance; + int header = 1; + char buf[BUFSIZ]; + + vty_out (vty, " Distance: (default is %d)%s", + rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT, + VTY_NEWLINE); + + for (rn = route_top (rip_distance_table); rn; rn = route_next (rn)) + if ((rdistance = rn->info) != NULL) + { + if (header) + { + vty_out (vty, " Address Distance List%s", + VTY_NEWLINE); + header = 0; + } + sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); + vty_out (vty, " %-20s %4d %s%s", + buf, rdistance->distance, + rdistance->access_list ? rdistance->access_list : "", + VTY_NEWLINE); + } +} + +DEFUN (rip_distance, + rip_distance_cmd, + "distance <1-255>", + "Administrative distance\n" + "Distance value\n") +{ + rip->distance = atoi (argv[0]); + return CMD_SUCCESS; +} + +DEFUN (no_rip_distance, + no_rip_distance_cmd, + "no distance <1-255>", + NO_STR + "Administrative distance\n" + "Distance value\n") +{ + rip->distance = 0; + return CMD_SUCCESS; +} + +DEFUN (rip_distance_source, + rip_distance_source_cmd, + "distance <1-255> A.B.C.D/M", + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n") +{ + rip_distance_set (vty, argv[0], argv[1], NULL); + return CMD_SUCCESS; +} + +DEFUN (no_rip_distance_source, + no_rip_distance_source_cmd, + "no distance <1-255> A.B.C.D/M", + NO_STR + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n") +{ + rip_distance_unset (vty, argv[0], argv[1], NULL); + return CMD_SUCCESS; +} + +DEFUN (rip_distance_source_access_list, + rip_distance_source_access_list_cmd, + "distance <1-255> A.B.C.D/M WORD", + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") +{ + rip_distance_set (vty, argv[0], argv[1], argv[2]); + return CMD_SUCCESS; +} + +DEFUN (no_rip_distance_source_access_list, + no_rip_distance_source_access_list_cmd, + "no distance <1-255> A.B.C.D/M WORD", + NO_STR + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") +{ + rip_distance_unset (vty, argv[0], argv[1], argv[2]); + return CMD_SUCCESS; +} + +/* Print out routes update time. */ +void +rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo) +{ + struct timeval timer_now; + time_t clock; + struct tm *tm; +#define TIME_BUF 25 + char timebuf [TIME_BUF]; + struct thread *thread; + + gettimeofday (&timer_now, NULL); + + if ((thread = rinfo->t_timeout) != NULL) + { + clock = thread->u.sands.tv_sec - timer_now.tv_sec; + tm = gmtime (&clock); + strftime (timebuf, TIME_BUF, "%M:%S", tm); + vty_out (vty, "%5s", timebuf); + } + else if ((thread = rinfo->t_garbage_collect) != NULL) + { + clock = thread->u.sands.tv_sec - timer_now.tv_sec; + tm = gmtime (&clock); + strftime (timebuf, TIME_BUF, "%M:%S", tm); + vty_out (vty, "%5s", timebuf); + } +} + +char * +rip_route_type_print (int sub_type) +{ + switch (sub_type) + { + case RIP_ROUTE_RTE: + return "n"; + case RIP_ROUTE_STATIC: + return "s"; + case RIP_ROUTE_DEFAULT: + return "d"; + case RIP_ROUTE_REDISTRIBUTE: + return "r"; + case RIP_ROUTE_INTERFACE: + return "i"; + default: + return "?"; + } +} + +DEFUN (show_ip_rip, + show_ip_rip_cmd, + "show ip rip", + SHOW_STR + IP_STR + "Show RIP routes\n") +{ + struct route_node *np; + struct rip_info *rinfo; + + if (! rip) + return CMD_SUCCESS; + + vty_out (vty, "Codes: R - RIP, C - connected, O - OSPF, B - BGP%s" + " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s" + " (i) - interface%s%s" + " Network Next Hop Metric From Time%s", + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + + for (np = route_top (rip->table); np; np = route_next (np)) + if ((rinfo = np->info) != NULL) + { + int len; + + len = vty_out (vty, "%s(%s) %s/%d", + /* np->lock, For debugging. */ + route_info[rinfo->type].str, + rip_route_type_print (rinfo->sub_type), + inet_ntoa (np->p.u.prefix4), np->p.prefixlen); + + len = 24 - len; + + if (len > 0) + vty_out (vty, "%*s", len, " "); + + if (rinfo->nexthop.s_addr) + vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop), + rinfo->metric); + else + vty_out (vty, "0.0.0.0 %2d ", rinfo->metric); + + /* Route which exist in kernel routing table. */ + if ((rinfo->type == ZEBRA_ROUTE_RIP) && + (rinfo->sub_type == RIP_ROUTE_RTE)) + { + vty_out (vty, "%-15s ", inet_ntoa (rinfo->from)); + rip_vty_out_uptime (vty, rinfo); + } + else if (rinfo->metric == RIP_METRIC_INFINITY) + { + vty_out (vty, "self "); + rip_vty_out_uptime (vty, rinfo); + } + else + vty_out (vty, "self"); + + vty_out (vty, "%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +/* Return next event time. */ +int +rip_next_thread_timer (struct thread *thread) +{ + struct timeval timer_now; + + gettimeofday (&timer_now, NULL); + + return thread->u.sands.tv_sec - timer_now.tv_sec; +} + +DEFUN (show_ip_protocols_rip, + show_ip_protocols_rip_cmd, + "show ip protocols", + SHOW_STR + IP_STR + "IP routing protocol process parameters and statistics\n") +{ + listnode node; + struct interface *ifp; + struct rip_interface *ri; + extern struct message ri_version_msg[]; + char *send_version; + char *receive_version; + + if (! rip) + return CMD_SUCCESS; + + vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE); + vty_out (vty, " Sending updates every %ld seconds with +/-50%%,", + rip->update_time); + vty_out (vty, " next due in %d seconds%s", + rip_next_thread_timer (rip->t_update), + VTY_NEWLINE); + vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time); + vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time, + VTY_NEWLINE); + + /* Filtering status show. */ + config_show_distribute (vty); + + /* Default metric information. */ + vty_out (vty, " Default redistribution metric is %d%s", + rip->default_metric, VTY_NEWLINE); + + /* Redistribute information. */ + vty_out (vty, " Redistributing:"); + config_write_rip_redistribute (vty, 0); + vty_out (vty, "%s", VTY_NEWLINE); + + vty_out (vty, " Default version control: send version %d,", rip->version); + vty_out (vty, " receive version %d %s", rip->version, + VTY_NEWLINE); + + vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE); + + for (node = listhead (iflist); node; node = nextnode (node)) + { + ifp = getdata (node); + ri = ifp->info; + + if (ri->enable_network || ri->enable_interface) + { + if (ri->ri_send == RI_RIP_UNSPEC) + send_version = lookup (ri_version_msg, rip->version); + else + send_version = lookup (ri_version_msg, ri->ri_send); + + if (ri->ri_receive == RI_RIP_UNSPEC) + receive_version = lookup (ri_version_msg, rip->version); + else + receive_version = lookup (ri_version_msg, ri->ri_receive); + + vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name, + send_version, + receive_version, + ri->key_chain ? ri->key_chain : "", + VTY_NEWLINE); + } + } + + vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE); + config_write_rip_network (vty, 0); + + vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE); + vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE); + rip_peer_display (vty); + + rip_distance_show (vty); + + return CMD_SUCCESS; +} + +/* RIP configuration write function. */ +int +config_write_rip (struct vty *vty) +{ + int write = 0; + struct route_node *rn; + struct rip_distance *rdistance; + + if (rip) + { + /* Router RIP statement. */ + vty_out (vty, "router rip%s", VTY_NEWLINE); + write++; + + /* RIP version statement. Default is RIP version 2. */ + if (rip->version != RIPv2) + vty_out (vty, " version %d%s", rip->version, + VTY_NEWLINE); + + /* RIP timer configuration. */ + if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT + || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT + || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT) + vty_out (vty, " timers basic %lu %lu %lu%s", + rip->update_time, + rip->timeout_time, + rip->garbage_time, + VTY_NEWLINE); + + /* Default information configuration. */ + if (rip->default_information) + { + if (rip->default_information_route_map) + vty_out (vty, " default-information originate route-map %s%s", + rip->default_information_route_map, VTY_NEWLINE); + else + vty_out (vty, " default-information originate%s", + VTY_NEWLINE); + } + + /* Redistribute configuration. */ + config_write_rip_redistribute (vty, 1); + + /* RIP offset-list configuration. */ + config_write_rip_offset_list (vty); + + /* RIP enabled network and interface configuration. */ + config_write_rip_network (vty, 1); + + /* RIP default metric configuration */ + if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT) + vty_out (vty, " default-metric %d%s", + rip->default_metric, VTY_NEWLINE); + + /* Distribute configuration. */ + write += config_write_distribute (vty); + + /* Distance configuration. */ + if (rip->distance) + vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE); + + /* RIP source IP prefix distance configuration. */ + for (rn = route_top (rip_distance_table); rn; rn = route_next (rn)) + if ((rdistance = rn->info) != NULL) + vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance, + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, + rdistance->access_list ? rdistance->access_list : "", + VTY_NEWLINE); + + /* RIP static route configuration. */ + for (rn = route_top (rip->route); rn; rn = route_next (rn)) + if (rn->info) + vty_out (vty, " route %s/%d%s", + inet_ntoa (rn->p.u.prefix4), + rn->p.prefixlen, + VTY_NEWLINE); + + } + return write; +} + +/* RIP node structure. */ +struct cmd_node rip_node = +{ + RIP_NODE, + "%s(config-router)# ", + 1 +}; + +/* Distribute-list update functions. */ +void +rip_distribute_update (struct distribute *dist) +{ + struct interface *ifp; + struct rip_interface *ri; + struct access_list *alist; + struct prefix_list *plist; + + if (! dist->ifname) + return; + + ifp = if_lookup_by_name (dist->ifname); + if (ifp == NULL) + return; + + ri = ifp->info; + + if (dist->list[DISTRIBUTE_IN]) + { + alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]); + if (alist) + ri->list[RIP_FILTER_IN] = alist; + else + ri->list[RIP_FILTER_IN] = NULL; + } + else + ri->list[RIP_FILTER_IN] = NULL; + + if (dist->list[DISTRIBUTE_OUT]) + { + alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]); + if (alist) + ri->list[RIP_FILTER_OUT] = alist; + else + ri->list[RIP_FILTER_OUT] = NULL; + } + else + ri->list[RIP_FILTER_OUT] = NULL; + + if (dist->prefix[DISTRIBUTE_IN]) + { + plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]); + if (plist) + ri->prefix[RIP_FILTER_IN] = plist; + else + ri->prefix[RIP_FILTER_IN] = NULL; + } + else + ri->prefix[RIP_FILTER_IN] = NULL; + + if (dist->prefix[DISTRIBUTE_OUT]) + { + plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]); + if (plist) + ri->prefix[RIP_FILTER_OUT] = plist; + else + ri->prefix[RIP_FILTER_OUT] = NULL; + } + else + ri->prefix[RIP_FILTER_OUT] = NULL; +} + +void +rip_distribute_update_interface (struct interface *ifp) +{ + struct distribute *dist; + + dist = distribute_lookup (ifp->name); + if (dist) + rip_distribute_update (dist); +} + +/* Update all interface's distribute list. */ +void +rip_distribute_update_all () +{ + struct interface *ifp; + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + rip_distribute_update_interface (ifp); + } +} + +/* Delete all added rip route. */ +void +rip_clean () +{ + int i; + struct route_node *rp; + struct rip_info *rinfo; + + if (rip) + { + /* Clear RIP routes */ + for (rp = route_top (rip->table); rp; rp = route_next (rp)) + if ((rinfo = rp->info) != NULL) + { + if (rinfo->type == ZEBRA_ROUTE_RIP && + rinfo->sub_type == RIP_ROUTE_RTE) + rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, + &rinfo->nexthop, rinfo->metric); + + RIP_TIMER_OFF (rinfo->t_timeout); + RIP_TIMER_OFF (rinfo->t_garbage_collect); + + rp->info = NULL; + route_unlock_node (rp); + + rip_info_free (rinfo); + } + + /* Cancel RIP related timers. */ + RIP_TIMER_OFF (rip->t_update); + RIP_TIMER_OFF (rip->t_triggered_update); + RIP_TIMER_OFF (rip->t_triggered_interval); + + /* Cancel read thread. */ + if (rip->t_read) + { + thread_cancel (rip->t_read); + rip->t_read = NULL; + } + + /* Close RIP socket. */ + if (rip->sock >= 0) + { + close (rip->sock); + rip->sock = -1; + } + + /* Static RIP route configuration. */ + for (rp = route_top (rip->route); rp; rp = route_next (rp)) + if (rp->info) + { + rp->info = NULL; + route_unlock_node (rp); + } + + /* RIP neighbor configuration. */ + for (rp = route_top (rip->neighbor); rp; rp = route_next (rp)) + if (rp->info) + { + rp->info = NULL; + route_unlock_node (rp); + } + + /* Redistribute related clear. */ + if (rip->default_information_route_map) + free (rip->default_information_route_map); + + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + if (rip->route_map[i].name) + free (rip->route_map[i].name); + + XFREE (MTYPE_ROUTE_TABLE, rip->table); + XFREE (MTYPE_ROUTE_TABLE, rip->route); + XFREE (MTYPE_ROUTE_TABLE, rip->neighbor); + + XFREE (MTYPE_RIP, rip); + rip = NULL; + } + + rip_clean_network (); + rip_passive_interface_clean (); + rip_offset_clean (); + rip_interface_clean (); + rip_distance_reset (); + rip_redistribute_clean (); +} + +/* Reset all values to the default settings. */ +void +rip_reset () +{ + /* Reset global counters. */ + rip_global_route_changes = 0; + rip_global_queries = 0; + + /* Call ripd related reset functions. */ + rip_debug_reset (); + rip_route_map_reset (); + + /* Call library reset functions. */ + vty_reset (); + access_list_reset (); + prefix_list_reset (); + + distribute_list_reset (); + + rip_interface_reset (); + rip_distance_reset (); + + rip_zclient_reset (); +} + +/* Allocate new rip structure and set default value. */ +void +rip_init () +{ + /* Randomize for triggered update random(). */ + srand (time (NULL)); + + /* Install top nodes. */ + install_node (&rip_node, config_write_rip); + + /* Install rip commands. */ + install_element (VIEW_NODE, &show_ip_rip_cmd); + install_element (VIEW_NODE, &show_ip_protocols_rip_cmd); + install_element (ENABLE_NODE, &show_ip_rip_cmd); + install_element (ENABLE_NODE, &show_ip_protocols_rip_cmd); + install_element (CONFIG_NODE, &router_rip_cmd); + install_element (CONFIG_NODE, &no_router_rip_cmd); + + install_default (RIP_NODE); + install_element (RIP_NODE, &rip_version_cmd); + install_element (RIP_NODE, &no_rip_version_cmd); + install_element (RIP_NODE, &no_rip_version_val_cmd); + install_element (RIP_NODE, &rip_default_metric_cmd); + install_element (RIP_NODE, &no_rip_default_metric_cmd); + install_element (RIP_NODE, &no_rip_default_metric_val_cmd); + install_element (RIP_NODE, &rip_timers_cmd); + install_element (RIP_NODE, &no_rip_timers_cmd); + install_element (RIP_NODE, &rip_route_cmd); + install_element (RIP_NODE, &no_rip_route_cmd); + install_element (RIP_NODE, &rip_distance_cmd); + install_element (RIP_NODE, &no_rip_distance_cmd); + install_element (RIP_NODE, &rip_distance_source_cmd); + install_element (RIP_NODE, &no_rip_distance_source_cmd); + install_element (RIP_NODE, &rip_distance_source_access_list_cmd); + install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd); + + /* Debug related init. */ + rip_debug_init (); + + /* Filter related init. */ + rip_route_map_init (); + rip_offset_init (); + + /* SNMP init. */ +#ifdef HAVE_SNMP + rip_snmp_init (); +#endif /* HAVE_SNMP */ + + /* Access list install. */ + access_list_init (); + access_list_add_hook (rip_distribute_update_all); + access_list_delete_hook (rip_distribute_update_all); + + /* Prefix list initialize.*/ + prefix_list_init (); + prefix_list_add_hook (rip_distribute_update_all); + prefix_list_delete_hook (rip_distribute_update_all); + + /* Distribute list install. */ + distribute_list_init (RIP_NODE); + distribute_list_add_hook (rip_distribute_update); + distribute_list_delete_hook (rip_distribute_update); + + /* Distance control. */ + rip_distance_table = route_table_init (); +} diff --git a/ripd/ripd.conf.sample b/ripd/ripd.conf.sample new file mode 100644 index 00000000..2902ff9c --- /dev/null +++ b/ripd/ripd.conf.sample @@ -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 index 00000000..2545db04 --- /dev/null +++ b/ripd/ripd.h @@ -0,0 +1,408 @@ +/* RIP related values and structures. + * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RIP_H +#define _ZEBRA_RIP_H + +/* RIP version number. */ +#define RIPv1 1 +#define RIPv2 2 + +/* RIP command list. */ +#define RIP_REQUEST 1 +#define RIP_RESPONSE 2 +#define RIP_TRACEON 3 /* Obsolete */ +#define RIP_TRACEOFF 4 /* Obsolete */ +#define RIP_POLL 5 +#define RIP_POLL_ENTRY 6 +#define RIP_COMMAND_MAX 7 + +/* RIP metric infinity value.*/ +#define RIP_METRIC_INFINITY 16 + +/* Normal RIP packet min 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 index 00000000..cd9e0832 --- /dev/null +++ b/ripngd/.cvsignore @@ -0,0 +1,7 @@ +Makefile +*.o +ripngd +ripngd.conf +tags +TAGS +.deps diff --git a/ripngd/ChangeLog b/ripngd/ChangeLog new file mode 100644 index 00000000..07e3d761 --- /dev/null +++ b/ripngd/ChangeLog @@ -0,0 +1,216 @@ +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2001-08-28 NOGUCHI Kay + + * ripngd.c (no_ripng_route): route_unlock_node () is not needed. + +2001-08-26 NOGUCHI Kay + + * ripngd.h (struct ripng_interface): Add passive interface option. + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-08-07 Akira Kato + + * ripngd.c (ripng_timers): "timers basic" argument is fixed. + +2001-02-01 Kunihiro Ishiguro + + * zebra-0.91 is released. + +2001-01-09 Kunihiro Ishiguro + + * zebra-0.90 is released. + +2001-01-01 Kunihiro Ishiguro + + * ripngd.h (RIPNG_VTYSH_PATH): Change "/tmp/ripngd" to + "/tmp/.ripngd". + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 is released. + +2000-09-20 Kunihiro Ishiguro + + * ripngd.c (ripng_send_packet): Use CMSG_SPACE instead of sizeof + hack. Revert privious alignment patch. + +2000-09-20 URA Hiroshi + + * ripngd.c (ripng_send_packet): Fix an alignment bug. Thus ripngd + can't send packets. + +2000-09-10 Kunihiro Ishiguro + + * ripng_interface.c (ripng_interface_address_delete): Connected + address delete treatment added. + +2000-08-22 Kunihiro Ishiguro + + * ripng_routemap.c (route_set_metric_compile): When checking '-' + character, argv[1] should be argv[0]. Reported by SHIRASAKI + Yasuhiro . + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 is released. + +2000-06-06 Kunihiro Ishiguro + + * ripngd.c (ripng_route_process): Clear prefix_ipv6 before using + it. + (ripng_redistribute_delete): Fix bug of missing + route_unlock_node() when redistribute route is not found. + (ripng_redistribute_delete): Make it sure that timers are off. + (ripng_redistribute_delete): Likewise. + +2000-01-19 Kunihiro Ishiguro + + * ripngd.c (ripng_route_process): Fix bug of mis-checking of same + route. + (show_ipv6_ripng): Include ifindex to "show ipv6 ripng" output. + +1999-11-12 Kunihiro Ishiguro + + * ripngd.c (ripng_output_process): Use MINMTU when mtu value is + not available. + +1999-11-05 Kunihiro Ishiguro + + * ripngd.c (ripng_output_process): Calculate max RTE count from + interface MTU value. + +1999-09-29 Kunihiro Ishiguro + + * ripngd.c (ripng_distribute_update): Fix bug of updating + access-list and prefix-list. + +1999-09-07 URA Hiroshi + + * ripngd.c (ripng_recv_packet): Change CMSG_DATA cast from (u_char + *) to (int *). (u_char *) does not work for NetBSD-currnet on + SparcStation 10. + +1999-08-15 Kunihiro Ishiguro + + * ripngd.c (ripng_request_process): When request packet comes, + check RIPng process is enabled on the interface. + (ripng_redistribute_withdraw): Delete routes when `no + redistribute' is executed. + +1999-08-13 Yasuhiro Ohara + + * ripng_zebra.c (ripng_redistribute_ospf6_cmd): Add OSPF6 + redistribute command. + +1999-07-21 Kunihiro Ishiguro + + * ripngd.c (default_information_originate): Add + default-information command. + +1999-07-19 Kunihiro Ishiguro + + * ripngd.c (ripng_route_process): rip_add_route() and + rip_delete_route() are deleted. Both functions are integrated + into ripng_route_process(). + (ripng_request_process): Proper reply for request message. + + * ripng_routemap.c: New file added. + +1999-07-18 Kunihiro Ishiguro + + * ripngd.c (ripng_nexthop_rte): RIPng next hop routine is + rewritten. + (show_ipv6_ripng): Change `show ip ripng' to `show ipv6 ripng'. + (ripng_response_process): RIPng incoming packet's hop count check + added. + (ripng_response_process): Add strict RTE checking. + +1999-07-03 Kunihiro Ishiguro + + * ripngd.c (ripng_add_route): Fix metric compare bug. + +1999-06-25 itojun@iijlab.net + + * ripngd.c (ripng_distribute_in): "distribute in" filter in ripngd + actually work. + +1999-05-25 Kunihiro Ishiguro + + * ripngd.c (ripng_zebra): Send each ripng information by separate + zebra packet. + +1999-05-15 Kunihiro Ishiguro + + * ripng_interface.c (if_add_multicast): Change log to zlog. + +1999-05-10 Kunihiro Ishiguro + + * ripng_interface.c (ripng_zebra_get_interface): Add function. + + * ripng_zebra.c (redistribute_ripng): Delete function because + redistirbute the routes to the zebra daemon is now default + behavior. + +1999-05-09 Kunihiro Ishiguro + + * ripngd.conf.sample: Change network to route statement. + +1999-03-25 Kunihiro Ishiguro + + * ripngd.c: Old non Advanced API version ripng_send_packet and + ripng_recv_packet is removed. + * ripng_radix.c: File removed. + +1998-12-15 Kunihiro Ishiguro + + * Now I assume KAME support Advanced API and use sendmsg/recvmsg. + +1998-12-13 Kunihiro Ishiguro + + * ripng_interface.c: Delete old ifa (interface address) related + functions. + +1998-12-10 Kunihiro Ishiguro + + * ripng_debug.[ch]: New file. + + * ripngd.c (ripng_supply): Do not send header only RIPng packet. + Change `network' statement to `route' statement. + (ripng_request_process): Reply to RIPng REQUEST packet. + +1998-12-09 Kunihiro Ishiguro + + * ripngd.c (ripng_config_write): Delete vector v argument. + * ripng_zebra.c (zebra_config_write): Likewise. + * ripng_interface.c (interface_config_write): Likewise. + +1998-12-07 Kunihiro Ishiguro + + * ripng_route.h: New file. + + * ripng_interface.c: Delete #include . + ripng_main.c: likewise. + ripng_radix.c: likewise. + ripng_route.c: likewise. + ripng_zebra.c: likewise. + ripngd.c: likewise. + +1998-12-06 Yasuhiro Ohara + + * ripngd.h (IPV6_ADD_MEMBERSHIP): If IPV6_ADD_MEMBERSHIP is not + defined. Define IPV6_ADD_MEMBERSHIP as IPV6_JOIN_GROUP. + +1998-09-15 HEO SeonMeyong + + * all Hydrangea define is changed to KAME. + diff --git a/ripngd/Makefile.am b/ripngd/Makefile.am new file mode 100644 index 00000000..2835aa24 --- /dev/null +++ b/ripngd/Makefile.am @@ -0,0 +1,37 @@ +## Process this file with automake to produce Makefile.in. + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 + +noinst_LIBRARIES = libripng.a +sbin_PROGRAMS = ripngd + +libripng_a_SOURCES = \ + ripng_interface.c ripngd.c ripng_zebra.c ripng_route.c ripng_debug.c \ + ripng_routemap.c + +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 index 00000000..61e0df21 --- /dev/null +++ b/ripngd/Makefile.in @@ -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 index 00000000..51314bc2 --- /dev/null +++ b/ripngd/ripng_debug.c @@ -0,0 +1,292 @@ +/* + * RIPng debug output routines + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include +#include "command.h" +#include "ripngd/ripng_debug.h" + +/* For debug statement. */ +unsigned long ripng_debug_event = 0; +unsigned long ripng_debug_packet = 0; +unsigned long ripng_debug_zebra = 0; + +DEFUN (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 index 00000000..6713a151 --- /dev/null +++ b/ripngd/ripng_debug.h @@ -0,0 +1,52 @@ +/* + * RIPng debug output routines + * Copyright (C) 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RIPNG_DEBUG_H +#define _ZEBRA_RIPNG_DEBUG_H + +/* Debug flags. */ +#define RIPNG_DEBUG_EVENT 0x01 + +#define RIPNG_DEBUG_PACKET 0x01 +#define RIPNG_DEBUG_SEND 0x20 +#define RIPNG_DEBUG_RECV 0x40 +#define RIPNG_DEBUG_DETAIL 0x80 + +#define RIPNG_DEBUG_ZEBRA 0x01 + +/* Debug related macro. */ +#define IS_RIPNG_DEBUG_EVENT (ripng_debug_event & RIPNG_DEBUG_EVENT) + +#define IS_RIPNG_DEBUG_PACKET (ripng_debug_packet & RIPNG_DEBUG_PACKET) +#define IS_RIPNG_DEBUG_SEND (ripng_debug_packet & RIPNG_DEBUG_SEND) +#define IS_RIPNG_DEBUG_RECV (ripng_debug_packet & RIPNG_DEBUG_RECV) +#define IS_RIPNG_DEBUG_DETAIL (ripng_debug_packet & RIPNG_DEBUG_DETAIL) + +#define IS_RIPNG_DEBUG_ZEBRA (ripng_debug_zebra & RIPNG_DEBUG_ZEBRA) + +extern unsigned long ripng_debug_event; +extern unsigned long ripng_debug_packet; +extern unsigned long ripng_debug_zebra; + +void ripng_debug_init (); + +#endif /* _ZEBRA_RIPNG_DEBUG_H */ diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c new file mode 100644 index 00000000..c177381a --- /dev/null +++ b/ripngd/ripng_interface.c @@ -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 + +#include "linklist.h" +#include "if.h" +#include "prefix.h" +#include "memory.h" +#include "network.h" +#include "filter.h" +#include "log.h" +#include "stream.h" +#include "zclient.h" +#include "command.h" +#include "table.h" +#include "thread.h" + +#include "ripngd/ripngd.h" +#include "ripngd/ripng_debug.h" + +/* If RFC2133 definition is used. */ +#ifndef IPV6_JOIN_GROUP +#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP +#endif +#ifndef IPV6_LEAVE_GROUP +#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP +#endif + +/* Static utility function. */ +static void ripng_enable_apply (struct interface *); +static void ripng_passive_interface_apply (struct interface *); + +/* Join to the all rip routers multicast group. */ +int +ripng_multicast_join (struct interface *ifp) +{ + int ret; + struct ipv6_mreq mreq; + + memset (&mreq, 0, sizeof (mreq)); + inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); + mreq.ipv6mr_interface = ifp->ifindex; + + ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, + (char *) &mreq, sizeof (mreq)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", strerror (errno)); + + if (IS_RIPNG_DEBUG_EVENT) + zlog_info ("RIPng %s join to all-rip-routers multicast group", ifp->name); + + return ret; +} + +/* Leave from the all rip routers multicast group. */ +int +ripng_multicast_leave (struct interface *ifp) +{ + int ret; + struct ipv6_mreq mreq; + + memset (&mreq, 0, sizeof (mreq)); + inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); + mreq.ipv6mr_interface = ifp->ifindex; + + ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, + (char *) &mreq, sizeof (mreq)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s\n", strerror (errno)); + + if (IS_RIPNG_DEBUG_EVENT) + zlog_info ("RIPng %s leave from all-rip-routers multicast group", + ifp->name); + + return ret; +} + +/* Check max mtu size. */ +int +ripng_check_max_mtu () +{ + listnode node; + struct interface *ifp; + int mtu; + + mtu = 0; + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + if (mtu < ifp->mtu) + mtu = ifp->mtu; + } + return mtu; +} + +int +ripng_if_down (struct interface *ifp) +{ + struct route_node *rp; + struct ripng_info *rinfo; + struct ripng_interface *ri; + + if (ripng->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; +} + +/* 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); + } +} + +/* Vector to store passive-interface name. */ +vector Vripng_passive_interface; + +/* Utility function for looking up passive interface settings. */ +int +ripng_passive_interface_lookup (char *ifname) +{ + int i; + char *str; + + for (i = 0; i < vector_max (Vripng_passive_interface); i++) + if ((str = vector_slot (Vripng_passive_interface, i)) != NULL) + if (strcmp (str, ifname) == 0) + return i; + return -1; +} + +void +ripng_passive_interface_apply (struct interface *ifp) +{ + int ret; + struct ripng_interface *ri; + + ri = ifp->info; + + ret = ripng_passive_interface_lookup (ifp->name); + if (ret < 0) + ri->passive = 0; + else + ri->passive = 1; +} + +void +ripng_passive_interface_apply_all (void) +{ + struct interface *ifp; + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + ripng_passive_interface_apply (ifp); + } +} + +/* Passive interface. */ +int +ripng_passive_interface_set (struct vty *vty, char *ifname) +{ + if (ripng_passive_interface_lookup (ifname) >= 0) + return CMD_WARNING; + + vector_set (Vripng_passive_interface, strdup (ifname)); + + ripng_passive_interface_apply_all (); + + return CMD_SUCCESS; +} + +int +ripng_passive_interface_unset (struct vty *vty, char *ifname) +{ + int i; + char *str; + + i = ripng_passive_interface_lookup (ifname); + if (i < 0) + return CMD_WARNING; + + str = vector_slot (Vripng_passive_interface, i); + free (str); + vector_unset (Vripng_passive_interface, i); + + ripng_passive_interface_apply_all (); + + return CMD_SUCCESS; +} + +/* Free all configured RIP passive-interface settings. */ +void +ripng_passive_interface_clean (void) +{ + int i; + char *str; + + for (i = 0; i < vector_max (Vripng_passive_interface); i++) + if ((str = vector_slot (Vripng_passive_interface, i)) != NULL) + { + free (str); + vector_slot (Vripng_passive_interface, i) = NULL; + } + ripng_passive_interface_apply_all (); +} + +/* Write RIPng enable network and interface to the vty. */ +int +ripng_network_write (struct vty *vty) +{ + int i; + char *str; + char *ifname; + struct route_node *node; + char buf[BUFSIZ]; + + /* Write enable network. */ + for (node = route_top (ripng_enable_network); node; node = route_next (node)) + if (node->info) + { + struct prefix *p = &node->p; + vty_out (vty, " network %s/%d%s", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen, + VTY_NEWLINE); + + } + + /* Write enable interface. */ + for (i = 0; i < vector_max (ripng_enable_if); i++) + if ((str = vector_slot (ripng_enable_if, i)) != NULL) + vty_out (vty, " network %s%s", str, + VTY_NEWLINE); + + /* Write passive interface. */ + for (i = 0; i < vector_max (Vripng_passive_interface); i++) + if ((ifname = vector_slot (Vripng_passive_interface, i)) != NULL) + vty_out (vty, " passive-interface %s%s", ifname, VTY_NEWLINE); + + return 0; +} + +/* RIPng enable on specified interface or matched network. */ +DEFUN (ripng_network, + ripng_network_cmd, + "network IF_OR_ADDR", + "RIPng enable on specified interface or network.\n" + "Interface or address") +{ + int ret; + struct prefix p; + + ret = str2prefix (argv[0], &p); + + /* Given string is IPv6 network or interface name. */ + if (ret) + ret = ripng_enable_network_add (&p); + else + ret = ripng_enable_if_add (argv[0]); + + if (ret < 0) + { + vty_out (vty, "There is same network configuration %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + ripng_enable_apply_all (); + + return CMD_SUCCESS; +} + +/* RIPng enable on specified interface or matched network. */ +DEFUN (no_ripng_network, + no_ripng_network_cmd, + "no network IF_OR_ADDR", + NO_STR + "RIPng enable on specified interface or network.\n" + "Interface or address") +{ + int ret; + struct prefix p; + + ret = str2prefix (argv[0], &p); + + /* Given string is interface name. */ + if (ret) + ret = ripng_enable_network_delete (&p); + else + ret = ripng_enable_if_delete (argv[0]); + + if (ret < 0) + { + vty_out (vty, "can't find network %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + ripng_enable_apply_all (); + + return CMD_SUCCESS; +} + +DEFUN (ripng_passive_interface, + ripng_passive_interface_cmd, + "passive-interface IFNAME", + "Suppress routing updates on an interface\n" + "Interface name\n") +{ + return ripng_passive_interface_set (vty, argv[0]); +} + +DEFUN (no_ripng_passive_interface, + no_ripng_passive_interface_cmd, + "no passive-interface IFNAME", + NO_STR + "Suppress routing updates on an interface\n" + "Interface name\n") +{ + return ripng_passive_interface_unset (vty, argv[0]); +} + +struct ripng_interface * +ri_new () +{ + struct ripng_interface *ri; + ri = XCALLOC (MTYPE_IF, sizeof (struct ripng_interface)); + return ri; +} + +int +ripng_if_new_hook (struct interface *ifp) +{ + ifp->info = ri_new (); + return 0; +} + +/* Configuration write function for ripngd. */ +int +interface_config_write (struct vty *vty) +{ + listnode node; + struct interface *ifp; + struct ripng_interface *ri; + int write = 0; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + ri = ifp->info; + + vty_out (vty, "interface %s%s", ifp->name, + VTY_NEWLINE); + if (ifp->desc) + vty_out (vty, " description %s%s", ifp->desc, + VTY_NEWLINE); + + vty_out (vty, "!%s", VTY_NEWLINE); + + write++; + } + return write; +} + +/* ripngd's interface node. */ +struct cmd_node interface_node = +{ + INTERFACE_NODE, + "%s(config-if)# ", +}; + +/* Initialization of interface. */ +void +ripng_if_init () +{ + /* Interface initialize. */ + iflist = list_new (); + if_add_hook (IF_NEW_HOOK, ripng_if_new_hook); + + /* RIPng enable network init. */ + ripng_enable_network = route_table_init (); + + /* RIPng enable interface init. */ + ripng_enable_if = vector_init (1); + + /* RIPng passive interface. */ + Vripng_passive_interface = vector_init (1); + + /* Install interface node. */ + install_node (&interface_node, interface_config_write); + + install_element (CONFIG_NODE, &interface_cmd); + install_element (INTERFACE_NODE, &config_end_cmd); + install_element (INTERFACE_NODE, &config_exit_cmd); + install_element (INTERFACE_NODE, &config_help_cmd); + install_element (INTERFACE_NODE, &interface_desc_cmd); + install_element (INTERFACE_NODE, &no_interface_desc_cmd); + + install_element (RIPNG_NODE, &ripng_network_cmd); + install_element (RIPNG_NODE, &no_ripng_network_cmd); + install_element (RIPNG_NODE, &ripng_passive_interface_cmd); + install_element (RIPNG_NODE, &no_ripng_passive_interface_cmd); +} diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c new file mode 100644 index 00000000..aec74bb4 --- /dev/null +++ b/ripngd/ripng_main.c @@ -0,0 +1,252 @@ +/* + * RIPngd main routine. + * Copyright (C) 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "version.h" +#include "getopt.h" +#include "vector.h" +#include "vty.h" +#include "command.h" +#include "thread.h" +#include "log.h" +#include "prefix.h" +#include "if.h" + +#include "ripngd/ripngd.h" + +/* Configuration filename and directory. */ +char config_current[] = RIPNG_DEFAULT_CONFIG; +char config_default[] = SYSCONFDIR RIPNG_DEFAULT_CONFIG; + +/* RIPngd options. */ +struct option longopts[] = +{ + { "daemon", no_argument, NULL, 'd'}, + { "config_file", required_argument, NULL, 'f'}, + { "pid_file", required_argument, NULL, 'i'}, + { "log_mode", no_argument, NULL, 'l'}, + { "help", no_argument, NULL, 'h'}, + { "vty_addr", required_argument, NULL, 'A'}, + { "vty_port", required_argument, NULL, 'P'}, + { "retain", no_argument, NULL, 'r'}, + { "version", no_argument, NULL, 'v'}, + { 0 } +}; + +/* RIPngd program name */ + +/* Route retain mode flag. */ +int retain_mode = 0; + +/* Master of threads. */ +struct thread_master *master; + +/* Process ID saved for use by init system */ +char *pid_file = PATH_RIPNGD_PID; + +/* Help information display. */ +static void +usage (char *progname, int status) +{ + if (status != 0) + fprintf (stderr, "Try `%s --help' for more information.\n", progname); + else + { + printf ("Usage : %s [OPTION...]\n\ +Daemon which manages RIPng.\n\n\ +-d, --daemon Runs in daemon mode\n\ +-f, --config_file Set configuration file name\n\ +-i, --pid_file Set process identifier file name\n\ +-l. --log_mode Set verbose log mode flag\n\ +-A, --vty_addr Set vty's bind address\n\ +-P, --vty_port Set vty's port number\n\ +-r, --retain When program terminates, retain added route by ripngd.\n\ +-v, --version Print program version\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); + } + exit (status); +} + +/* SIGHUP handler. */ +void +sighup (int sig) +{ + zlog (NULL, LOG_INFO, "SIGHUP received"); +} + +/* SIGINT handler. */ +void +sigint (int sig) +{ + zlog (NULL, LOG_INFO, "Terminating on signal"); + + if (! retain_mode) + ripng_terminate (); + + exit (0); +} + +/* SIGUSR1 handler. */ +void +sigusr1 (int sig) +{ + zlog_rotate (NULL); +} + +/* Signale wrapper. */ +RETSIGTYPE * +signal_set (int signo, void (*func)(int)) +{ + int ret; + struct sigaction sig; + struct sigaction osig; + + sig.sa_handler = func; + sigemptyset (&sig.sa_mask); + sig.sa_flags = 0; +#ifdef SA_RESTART + sig.sa_flags |= SA_RESTART; +#endif /* SA_RESTART */ + + ret = sigaction (signo, &sig, &osig); + + if (ret < 0) + return (SIG_ERR); + else + return (osig.sa_handler); +} + +/* Initialization of signal handles. */ +void +signal_init () +{ + signal_set (SIGHUP, sighup); + signal_set (SIGINT, sigint); + signal_set (SIGTERM, sigint); + signal_set (SIGPIPE, SIG_IGN); + signal_set (SIGUSR1, sigusr1); +} + +/* RIPngd main routine. */ +int +main (int argc, char **argv) +{ + char *p; + char *vty_addr = NULL; + int vty_port = 0; + int daemon_mode = 0; + char *config_file = NULL; + char *progname; + struct thread thread; + + /* Set umask before anything for security */ + umask (0027); + + /* get program name */ + progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + + zlog_default = openzlog(progname, ZLOG_NOLOG, ZLOG_RIPNG, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + + while (1) + { + int opt; + + opt = getopt_long (argc, argv, "dlf:hA:P:v", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + case 'd': + daemon_mode = 1; + break; + case 'l': + /* log_mode = 1; */ + break; + case 'f': + config_file = optarg; + break; + case 'A': + vty_addr = optarg; + break; + case 'i': + pid_file = optarg; + break; + case 'P': + vty_port = atoi (optarg); + break; + case 'r': + retain_mode = 1; + break; + case 'v': + print_version (progname); + exit (0); + break; + case 'h': + usage (progname, 0); + break; + default: + usage (progname, 1); + break; + } + } + + master = thread_master_create (); + + /* Library inits. */ + signal_init (); + cmd_init (1); + vty_init (); + + /* RIPngd inits. */ + ripng_init (); + zebra_init (); + sort_node (); + + /* Get configuration file. */ + vty_read_config (config_file, config_current, config_default); + + /* Change to the daemon program. */ + if (daemon_mode) + daemon (0, 0); + + /* Create VTY socket */ + vty_serv_sock (vty_addr, + vty_port ? vty_port : RIPNG_VTY_PORT, RIPNG_VTYSH_PATH); + + /* Process id file create. */ + pid_output (pid_file); + + /* Fetch next active thread. */ + while (thread_fetch (master, &thread)) + thread_call (&thread); + + /* Not reached. */ + exit (0); +} diff --git a/ripngd/ripng_route.c b/ripngd/ripng_route.c new file mode 100644 index 00000000..27475f05 --- /dev/null +++ b/ripngd/ripng_route.c @@ -0,0 +1,157 @@ +/* + * RIPng routes function. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "table.h" +#include "memory.h" +#include "if.h" + +#include "ripngd/ripngd.h" +#include "ripngd/ripng_route.h" + +struct ripng_aggregate * +ripng_aggregate_new () +{ + struct ripng_aggregate *new; + + new = XCALLOC (MTYPE_RIPNG_AGGREGATE, sizeof (struct ripng_aggregate)); + return new; +} + +void +ripng_aggregate_free (struct ripng_aggregate *aggregate) +{ + XFREE (MTYPE_RIPNG_AGGREGATE, aggregate); +} + +/* Aggregate count increment check. */ +void +ripng_aggregate_increment (struct route_node *child, struct ripng_info *rinfo) +{ + struct route_node *np; + struct ripng_aggregate *aggregate; + + for (np = child; np; np = np->parent) + if ((aggregate = np->aggregate) != NULL) + { + aggregate->count++; + rinfo->suppress++; + } +} + +/* Aggregate count decrement check. */ +void +ripng_aggregate_decrement (struct route_node *child, struct ripng_info *rinfo) +{ + struct route_node *np; + struct ripng_aggregate *aggregate; + + for (np = child; np; np = np->parent) + if ((aggregate = np->aggregate) != NULL) + { + aggregate->count--; + rinfo->suppress--; + } +} + +/* RIPng routes treatment. */ +int +ripng_aggregate_add (struct prefix *p) +{ + struct route_node *top; + struct route_node *rp; + struct ripng_info *rinfo; + struct ripng_aggregate *aggregate; + struct ripng_aggregate *sub; + + /* Get top node for aggregation. */ + top = route_node_get (ripng->table, p); + + /* Allocate new aggregate. */ + aggregate = ripng_aggregate_new (); + aggregate->metric = 1; + + top->aggregate = aggregate; + + /* Suppress routes match to the aggregate. */ + for (rp = route_lock_node (top); rp; rp = route_next_until (rp, top)) + { + /* Suppress normal route. */ + if ((rinfo = rp->info) != NULL) + { + aggregate->count++; + rinfo->suppress++; + } + /* Suppress aggregate route. This may not need. */ + if (rp != top && (sub = rp->aggregate) != NULL) + { + aggregate->count++; + sub->suppress++; + } + } + + return 0; +} + +/* Delete RIPng static route. */ +int +ripng_aggregate_delete (struct prefix *p) +{ + struct route_node *top; + struct route_node *rp; + struct ripng_info *rinfo; + struct ripng_aggregate *aggregate; + struct ripng_aggregate *sub; + + /* Get top node for aggregation. */ + top = route_node_get (ripng->table, p); + + /* Allocate new aggregate. */ + aggregate = top->aggregate; + + /* Suppress routes match to the aggregate. */ + for (rp = route_lock_node (top); rp; rp = route_next_until (rp, top)) + { + /* Suppress normal route. */ + if ((rinfo = rp->info) != NULL) + { + aggregate->count--; + rinfo->suppress--; + } + + if (rp != top && (sub = rp->aggregate) != NULL) + { + aggregate->count--; + sub->suppress--; + } + } + + top->aggregate = NULL; + ripng_aggregate_free (aggregate); + + route_unlock_node (top); + route_unlock_node (top); + + return 0; +} diff --git a/ripngd/ripng_route.h b/ripngd/ripng_route.h new file mode 100644 index 00000000..283d8268 --- /dev/null +++ b/ripngd/ripng_route.h @@ -0,0 +1,53 @@ +/* + * RIPng daemon + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RIPNG_ROUTE_H +#define _ZEBRA_RIPNG_ROUTE_H + +struct ripng_aggregate +{ + /* Aggregate route count. */ + unsigned int count; + + /* Suppressed route count. */ + unsigned int suppress; + + /* Metric of this route. */ + u_char metric; + + /* Tag field of RIPng packet.*/ + u_short tag; +}; + +void +ripng_aggregate_increment (struct route_node *rp, struct ripng_info *rinfo); + +void +ripng_aggregate_decrement (struct route_node *rp, struct ripng_info *rinfo); + +int +ripng_aggregate_add (struct prefix *p); + +int +ripng_aggregate_delete (struct prefix *p); + +#endif /* _ZEBRA_RIPNG_ROUTE_H */ diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c new file mode 100644 index 00000000..f237e6b6 --- /dev/null +++ b/ripngd/ripng_routemap.c @@ -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 + +#include "if.h" +#include "memory.h" +#include "prefix.h" +#include "routemap.h" +#include "command.h" + +#include "ripngd/ripngd.h" + +#if 0 +/* `match interface IFNAME' */ +route_map_result_t +route_match_interface (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct ripng_info *rinfo; + struct interface *ifp; + char *ifname; + + if (type == ROUTE_MAP_RIPNG) + { + ifname = rule; + ifp = if_lookup_by_name(ifname); + + if (!ifp) + return RM_NOMATCH; + + rinfo = object; + + if (rinfo->ifindex == ifp->ifindex) + return RM_MATCH; + else + return RM_NOMATCH; + } + return RM_NOMATCH; +} + +void * +route_match_interface_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_interface_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_interface_cmd = +{ + "interface", + route_match_interface, + route_match_interface_compile, + route_match_interface_free +}; +#endif /* 0 */ + +struct rip_metric_modifier +{ + enum + { + metric_increment, + metric_decrement, + metric_absolute + } type; + + u_char metric; +}; + +route_map_result_t +route_set_metric (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + if (type == RMAP_RIPNG) + { + struct rip_metric_modifier *mod; + struct ripng_info *rinfo; + + mod = rule; + rinfo = object; + + if (mod->type == metric_increment) + rinfo->metric += mod->metric; + else if (mod->type == metric_decrement) + rinfo->metric -= mod->metric; + else if (mod->type == metric_absolute) + rinfo->metric = mod->metric; + + if (rinfo->metric < 1) + rinfo->metric = 1; + if (rinfo->metric > RIPNG_METRIC_INFINITY) + rinfo->metric = RIPNG_METRIC_INFINITY; + + rinfo->metric_set = 1; + } + return RMAP_OKAY; +} + +void * +route_set_metric_compile (char *arg) +{ + int len; + char *pnt; + int type; + long metric; + char *endptr = NULL; + struct rip_metric_modifier *mod; + + len = strlen (arg); + pnt = arg; + + if (len == 0) + return NULL; + + /* Examine first character. */ + if (arg[0] == '+') + { + type = metric_increment; + pnt++; + } + else if (arg[0] == '-') + { + type = metric_decrement; + pnt++; + } + else + type = metric_absolute; + + /* Check beginning with digit string. */ + if (*pnt < '0' || *pnt > '9') + return NULL; + + /* Convert string to integer. */ + metric = strtol (pnt, &endptr, 10); + + if (metric == LONG_MAX || *endptr != '\0') + return NULL; + 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, +}; + +int +ripng_route_match_add (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_add_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +int +ripng_route_match_delete (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_delete_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +int +ripng_route_set_add (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_add_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +int +ripng_route_set_delete (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_delete_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +#if 0 +DEFUN (match_interface, + match_interface_cmd, + "match interface WORD", + "Match value\n" + "Interface\n" + "Interface name\n") +{ + return ripng_route_match_add (vty, vty->index, "interface", argv[0]); +} + +DEFUN (no_match_interface, + no_match_interface_cmd, + "no match interface WORD", + NO_STR + "Match value\n" + "Interface\n" + "Interface name\n") +{ + return ripng_route_match_delete (vty, vty->index, "interface", argv[0]); +} +#endif /* 0 */ + +DEFUN (set_metric, + set_metric_cmd, + "set metric <0-4294967295>", + "Set value\n" + "Metric\n" + "METRIC value\n") +{ + return ripng_route_set_add (vty, vty->index, "metric", argv[0]); +} + +DEFUN (no_set_metric, + no_set_metric_cmd, + "no set metric <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 index 00000000..4d8a48d3 --- /dev/null +++ b/ripngd/ripng_zebra.c @@ -0,0 +1,877 @@ +/* + * RIPngd and zebra interface. + * Copyright (C) 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "command.h" +#include "prefix.h" +#include "stream.h" +#include "routemap.h" +#include "zclient.h" +#include "log.h" + +#include "ripngd/ripngd.h" + +/* All information about zebra. */ +struct zclient *zclient = NULL; + +/* Callback prototypes for zebra client service. */ +int ripng_interface_up (int, struct zclient *, zebra_size_t); +int ripng_interface_down (int, struct zclient *, zebra_size_t); +int ripng_interface_add (int, struct zclient *, zebra_size_t); +int ripng_interface_delete (int, struct zclient *, zebra_size_t); +int ripng_interface_address_add (int, struct zclient *, zebra_size_t); +int ripng_interface_address_delete (int, struct zclient *, zebra_size_t); + +void +ripng_zebra_ipv6_add (struct prefix_ipv6 *p, struct in6_addr *nexthop, + unsigned int ifindex) +{ + struct zapi_ipv6 api; + + if (zclient->redist[ZEBRA_ROUTE_RIPNG]) + { + api.type = ZEBRA_ROUTE_RIPNG; + api.flags = 0; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api.nexthop = &nexthop; + SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); + api.ifindex_num = 1; + api.ifindex = &ifindex; + + zapi_ipv6_add (zclient, p, &api); + } +} + +void +ripng_zebra_ipv6_delete (struct prefix_ipv6 *p, struct in6_addr *nexthop, + unsigned int ifindex) +{ + struct zapi_ipv6 api; + + if (zclient->redist[ZEBRA_ROUTE_RIPNG]) + { + api.type = ZEBRA_ROUTE_RIPNG; + api.flags = 0; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api.nexthop = &nexthop; + SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); + api.ifindex_num = 1; + api.ifindex = &ifindex; + + zapi_ipv6_delete (zclient, p, &api); + } +} + +/* Zebra route add and delete treatment. */ +int +ripng_zebra_read_ipv6 (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct stream *s; + struct zapi_ipv6 api; + unsigned long ifindex; + struct in6_addr nexthop; + struct prefix_ipv6 p; + + s = zclient->ibuf; + ifindex = 0; + memset (&nexthop, 0, sizeof (struct in6_addr)); + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.flags = stream_getc (s); + api.message = stream_getc (s); + + /* IPv6 prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = stream_getc (s); + stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + { + api.nexthop_num = stream_getc (s); + stream_get (&nexthop, s, 16); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) + { + api.ifindex_num = stream_getc (s); + ifindex = stream_getl (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + else + api.distance = 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + else + api.metric = 0; + + if (command == ZEBRA_IPV6_ROUTE_ADD) + ripng_redistribute_add (api.type, 0, &p, ifindex); + else + ripng_redistribute_delete (api.type, 0, &p, ifindex); + + return 0; +} + +int +ripng_redistribute_unset (int type) +{ + if (! zclient->redist[type]) + return CMD_SUCCESS; + + zclient->redist[type] = 0; + + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type); + + ripng_redistribute_withdraw (type); + + return CMD_SUCCESS; +} + +void +ripng_redistribute_metric_set (int type, int metric) +{ + ripng->route_map[type].metric_config = 1; + ripng->route_map[type].metric = metric; +} + +void +ripng_redistribute_metric_unset (int type) +{ + ripng->route_map[type].metric_config = 0; + ripng->route_map[type].metric = 0; +} + +void +ripng_redistribute_routemap_set (int type, char *name) +{ + if (ripng->route_map[type].name) + free (ripng->route_map[type].name); + + ripng->route_map[type].name = strdup (name); + ripng->route_map[type].map = route_map_lookup_by_name (name); +} + +void +ripng_redistribute_routemap_unset (int type) +{ + if (ripng->route_map[type].name) + free (ripng->route_map[type].name); + + ripng->route_map[type].name = NULL; + ripng->route_map[type].map = NULL; +} + + +DEFUN (router_zebra, + router_zebra_cmd, + "router zebra", + "Enable a routing process\n" + "Make connection to zebra daemon\n") +{ + vty->node = ZEBRA_NODE; + zclient->enable = 1; + zclient_start (zclient); + return CMD_SUCCESS; +} + +DEFUN (no_router_zebra, + no_router_zebra_cmd, + "no router zebra", + NO_STR + "Disable a routing process\n" + "Stop connection to zebra daemon\n") +{ + zclient->enable = 0; + zclient_stop (zclient); + return CMD_SUCCESS; +} + +DEFUN (ripng_redistribute_ripng, + ripng_redistribute_ripng_cmd, + "redistribute ripng", + "Redistribute information from another routing protocol\n" + "RIPng route\n") +{ + zclient->redist[ZEBRA_ROUTE_RIPNG] = 1; + return CMD_SUCCESS; +} + +DEFUN (no_ripng_redistribute_ripng, + no_ripng_redistribute_ripng_cmd, + "no redistribute ripng", + NO_STR + "Redistribute information from another routing protocol\n" + "RIPng route\n") +{ + zclient->redist[ZEBRA_ROUTE_RIPNG] = 0; + return CMD_SUCCESS; +} + +DEFUN (ripng_redistribute_static, + ripng_redistribute_static_cmd, + "redistribute static", + "Redistribute information from another routing protocol\n" + "Static routes\n") +{ + zclient_redistribute_set (zclient, ZEBRA_ROUTE_STATIC); + return CMD_SUCCESS; +} + +DEFUN (no_ripng_redistribute_static, + no_ripng_redistribute_static_cmd, + "no redistribute static", + NO_STR + "Redistribute information from another routing protocol\n" + "Static routes\n") +{ + ripng_redistribute_metric_unset (ZEBRA_ROUTE_STATIC); + ripng_redistribute_routemap_unset (ZEBRA_ROUTE_STATIC); + return ripng_redistribute_unset (ZEBRA_ROUTE_STATIC); +} + +DEFUN (ripng_redistribute_kernel, + ripng_redistribute_kernel_cmd, + "redistribute kernel", + "Redistribute information from another routing protocol\n" + "Kernel routes\n") +{ + zclient_redistribute_set (zclient, ZEBRA_ROUTE_KERNEL); + return CMD_SUCCESS; +} + +DEFUN (no_ripng_redistribute_kernel, + no_ripng_redistribute_kernel_cmd, + "no redistribute kernel", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n") +{ + ripng_redistribute_metric_unset (ZEBRA_ROUTE_KERNEL); + ripng_redistribute_routemap_unset (ZEBRA_ROUTE_KERNEL); + return ripng_redistribute_unset (ZEBRA_ROUTE_KERNEL); +} + +DEFUN (ripng_redistribute_connected, + ripng_redistribute_connected_cmd, + "redistribute connected", + "Redistribute information from another routing protocol\n" + "Connected\n") +{ + zclient_redistribute_set (zclient, ZEBRA_ROUTE_CONNECT); + return CMD_SUCCESS; +} + +DEFUN (no_ripng_redistribute_connected, + no_ripng_redistribute_connected_cmd, + "no redistribute connected", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n") +{ + ripng_redistribute_metric_unset (ZEBRA_ROUTE_CONNECT); + ripng_redistribute_routemap_unset (ZEBRA_ROUTE_CONNECT); + return ripng_redistribute_unset (ZEBRA_ROUTE_CONNECT); +} + +DEFUN (ripng_redistribute_bgp, + ripng_redistribute_bgp_cmd, + "redistribute bgp", + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n") +{ + zclient_redistribute_set (zclient, ZEBRA_ROUTE_BGP); + return CMD_SUCCESS; +} + +DEFUN (no_ripng_redistribute_bgp, + no_ripng_redistribute_bgp_cmd, + "no redistribute bgp", + NO_STR + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n") +{ + ripng_redistribute_metric_unset (ZEBRA_ROUTE_BGP); + ripng_redistribute_routemap_unset (ZEBRA_ROUTE_BGP); + return ripng_redistribute_unset (ZEBRA_ROUTE_BGP); +} + +DEFUN (ripng_redistribute_ospf6, + ripng_redistribute_ospf6_cmd, + "redistribute ospf6", + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n") +{ + zclient_redistribute_set (zclient, ZEBRA_ROUTE_OSPF6); + return CMD_SUCCESS; +} + +DEFUN (no_ripng_redistribute_ospf6, + no_ripng_redistribute_ospf6_cmd, + "no redistribute ospf6", + NO_STR + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n") +{ + ripng_redistribute_metric_unset (ZEBRA_ROUTE_OSPF6); + ripng_redistribute_routemap_unset (ZEBRA_ROUTE_OSPF6); + return ripng_redistribute_unset (ZEBRA_ROUTE_OSPF6); +} + +DEFUN (ripng_redistribute_kernel_metric, + ripng_redistribute_kernel_metric_cmd, + "redistribute kernel metric <0-16>", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Metric\n" + "Metric value\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_KERNEL, atoi (argv[0])); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_KERNEL); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_kernel, + no_ripng_redistribute_kernel_metric_cmd, + "no redistribute kernel metric", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Metric\n") + +ALIAS (no_ripng_redistribute_kernel, + no_ripng_redistribute_kernel_metric_val_cmd, + "no redistribute kernel metric <0-16>", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Metric\n" + "Metric value\n") + +DEFUN (ripng_redistribute_connected_metric, + ripng_redistribute_connected_metric_cmd, + "redistribute connected metric <0-16>", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Metric\n" + "Metric value\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_CONNECT, atoi (argv[0])); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_CONNECT); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_connected, + no_ripng_redistribute_connected_metric_cmd, + "no redistribute connected metric", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Metric\n") + +ALIAS (no_ripng_redistribute_connected, + no_ripng_redistribute_connected_metric_val_cmd, + "no redistribute connected metric <0-16>", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Metric\n" + "Metric value\n") + +DEFUN (ripng_redistribute_static_metric, + ripng_redistribute_static_metric_cmd, + "redistribute static metric <0-16>", + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Metric\n" + "Metric value\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_STATIC, atoi (argv[0])); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_STATIC); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_static, + no_ripng_redistribute_static_metric_cmd, + "no redistribute static metric", + NO_STR + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Metric\n") + +ALIAS (no_ripng_redistribute_static, + no_ripng_redistribute_static_metric_val_cmd, + "no redistribute static metric <0-16>", + NO_STR + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Metric\n" + "Metric value\n") + +DEFUN (ripng_redistribute_ospf6_metric, + ripng_redistribute_ospf6_metric_cmd, + "redistribute ospf6 metric <0-16>", + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Metric\n" + "Metric value\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_OSPF6, atoi (argv[0])); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_OSPF6); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_ospf6, + no_ripng_redistribute_ospf6_metric_cmd, + "no redistribute ospf6 metric", + NO_STR + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Metric\n") + +ALIAS (no_ripng_redistribute_ospf6, + no_ripng_redistribute_ospf6_metric_val_cmd, + "no redistribute ospf6 metric <0-16>", + NO_STR + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Metric\n" + "Metric value\n") + +DEFUN (ripng_redistribute_bgp_metric, + ripng_redistribute_bgp_metric_cmd, + "redistribute bgp metric <0-16>", + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_BGP, atoi (argv[0])); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_BGP); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_bgp, + no_ripng_redistribute_bgp_metric_cmd, + "no redistribute bgp metric", + NO_STR + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n") + +ALIAS (no_ripng_redistribute_bgp, + no_ripng_redistribute_bgp_metric_val_cmd, + "no redistribute bgp metric <0-16>", + NO_STR + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n") + +DEFUN (ripng_redistribute_kernel_routemap, + ripng_redistribute_kernel_routemap_cmd, + "redistribute kernel route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_routemap_set (ZEBRA_ROUTE_KERNEL, argv[0]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_KERNEL); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_kernel, + no_ripng_redistribute_kernel_routemap_cmd, + "no redistribute kernel route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFUN (ripng_redistribute_connected_routemap, + ripng_redistribute_connected_routemap_cmd, + "redistribute connected route-map WORD", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_routemap_set (ZEBRA_ROUTE_CONNECT, argv[0]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_CONNECT); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_connected, + no_ripng_redistribute_connected_routemap_cmd, + "no redistribute connected route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFUN (ripng_redistribute_static_routemap, + ripng_redistribute_static_routemap_cmd, + "redistribute static route-map WORD", + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_routemap_set (ZEBRA_ROUTE_STATIC, argv[0]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_STATIC); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_static, + no_ripng_redistribute_static_routemap_cmd, + "no redistribute static route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFUN (ripng_redistribute_ospf6_routemap, + ripng_redistribute_ospf6_routemap_cmd, + "redistribute ospf6 route-map WORD", + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_routemap_set (ZEBRA_ROUTE_OSPF6, argv[0]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_OSPF6); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_ospf6, + no_ripng_redistribute_ospf6_routemap_cmd, + "no redistribute ospf6 route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFUN (ripng_redistribute_bgp_routemap, + ripng_redistribute_bgp_routemap_cmd, + "redistribute bgp route-map WORD", + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_routemap_set (ZEBRA_ROUTE_BGP, argv[0]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_BGP); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_bgp, + no_ripng_redistribute_bgp_routemap_cmd, + "no redistribute bgp route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFUN (ripng_redistribute_kernel_metric_routemap, + ripng_redistribute_kernel_metric_routemap_cmd, + "redistribute kernel metric <0-16> route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_KERNEL, atoi (argv[0])); + ripng_redistribute_routemap_set (ZEBRA_ROUTE_KERNEL, argv[1]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_KERNEL); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_kernel, + no_ripng_redistribute_kernel_metric_routemap_cmd, + "no redistribute kernel metric <0-16> route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFUN (ripng_redistribute_connected_metric_routemap, + ripng_redistribute_connected_metric_routemap_cmd, + "redistribute connected metric <0-16> route-map WORD", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_CONNECT, atoi (argv[0])); + ripng_redistribute_routemap_set (ZEBRA_ROUTE_CONNECT, argv[1]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_CONNECT); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_connected, + no_ripng_redistribute_connected_metric_routemap_cmd, + "no redistribute connected metric <0-16> route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFUN (ripng_redistribute_static_metric_routemap, + ripng_redistribute_static_metric_routemap_cmd, + "redistribute static metric <0-16> route-map WORD", + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_STATIC, atoi (argv[0])); + ripng_redistribute_routemap_set (ZEBRA_ROUTE_STATIC, argv[1]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_STATIC); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_static, + no_ripng_redistribute_static_metric_routemap_cmd, + "no redistribute static metric <0-16> route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFUN (ripng_redistribute_ospf6_metric_routemap, + ripng_redistribute_ospf6_metric_routemap_cmd, + "redistribute ospf6 metric <0-16> route-map WORD", + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_OSPF6, atoi (argv[0])); + ripng_redistribute_routemap_set (ZEBRA_ROUTE_OSPF6, argv[1]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_OSPF6); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_ospf6, + no_ripng_redistribute_ospf6_metric_routemap_cmd, + "no redistribute ospf6 metric <0-16> route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFUN (ripng_redistribute_bgp_metric_routemap, + ripng_redistribute_bgp_metric_routemap_cmd, + "redistribute bgp metric <0-16> route-map WORD", + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_BGP, atoi (argv[0])); + ripng_redistribute_routemap_set (ZEBRA_ROUTE_BGP, argv[1]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_BGP); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_bgp, + no_ripng_redistribute_bgp_metric_routemap_cmd, + "no redistribute bgp metric <0-16> route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +void +ripng_redistribute_write (struct vty *vty) +{ + int i; + char *str[] = { "system", "kernel", "connected", "static", "rip", + "ripng", "ospf", "ospf6", "bgp"}; + + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + if (i != zclient->redist_default && zclient->redist[i]) + { + if (ripng->route_map[i].metric_config) + { + if (ripng->route_map[i].name) + vty_out (vty, " redistribute %s metric %d route-map %s%s", + str[i], ripng->route_map[i].metric, + ripng->route_map[i].name, VTY_NEWLINE); + else + vty_out (vty, " redistribute %s metric %d%s", + str[i], ripng->route_map[i].metric, VTY_NEWLINE); + } + else + { + if (ripng->route_map[i].name) + vty_out (vty, " redistribute %s route-map %s%s", + str[i], ripng->route_map[i].name, VTY_NEWLINE); + else + vty_out (vty, " redistribute %s%s", str[i], VTY_NEWLINE); + } + } +} + +/* RIPng configuration write function. */ +int +zebra_config_write (struct vty *vty) +{ + if (! zclient->enable) + { + vty_out (vty, "no router zebra%s", VTY_NEWLINE); + return 1; + } + else if (! zclient->redist[ZEBRA_ROUTE_RIPNG]) + { + vty_out (vty, "router zebra%s", VTY_NEWLINE); + vty_out (vty, " no redistribute ripng%s", VTY_NEWLINE); + return 1; + } + return 0; +} + +/* Zebra node structure. */ +struct cmd_node zebra_node = +{ + ZEBRA_NODE, + "%s(config-router)# ", +}; + +/* Initialize zebra structure and it's commands. */ +void +zebra_init () +{ + /* Allocate zebra structure. */ + zclient = zclient_new (); + zclient_init (zclient, ZEBRA_ROUTE_RIPNG); + + zclient->interface_up = ripng_interface_up; + zclient->interface_down = ripng_interface_down; + zclient->interface_add = ripng_interface_add; + zclient->interface_delete = ripng_interface_delete; + zclient->interface_address_add = ripng_interface_address_add; + zclient->interface_address_delete = ripng_interface_address_delete; + zclient->ipv6_route_add = ripng_zebra_read_ipv6; + zclient->ipv6_route_delete = ripng_zebra_read_ipv6; + + /* Install zebra node. */ + install_node (&zebra_node, zebra_config_write); + + /* Install command element for zebra node. */ + install_element (CONFIG_NODE, &router_zebra_cmd); + install_element (CONFIG_NODE, &no_router_zebra_cmd); + install_default (ZEBRA_NODE); + install_element (ZEBRA_NODE, &ripng_redistribute_ripng_cmd); + install_element (ZEBRA_NODE, &no_ripng_redistribute_ripng_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_static_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_static_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_kernel_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_connected_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_connected_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_bgp_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_ospf6_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_kernel_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_metric_val_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_connected_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_connected_metric_cmd); + install_element (RIPNG_NODE, + &no_ripng_redistribute_connected_metric_val_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_static_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_static_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_static_metric_val_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_ospf6_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_metric_val_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_bgp_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_val_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_kernel_routemap_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_routemap_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_connected_routemap_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_connected_routemap_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_static_routemap_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_static_routemap_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_ospf6_routemap_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_routemap_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_bgp_routemap_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_routemap_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_kernel_metric_routemap_cmd); + install_element (RIPNG_NODE, + &no_ripng_redistribute_kernel_metric_routemap_cmd); + install_element (RIPNG_NODE, + &ripng_redistribute_connected_metric_routemap_cmd); + install_element (RIPNG_NODE, + &no_ripng_redistribute_connected_metric_routemap_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_static_metric_routemap_cmd); + install_element (RIPNG_NODE, + &no_ripng_redistribute_static_metric_routemap_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_ospf6_metric_routemap_cmd); + install_element (RIPNG_NODE, + &no_ripng_redistribute_ospf6_metric_routemap_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_bgp_metric_routemap_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_routemap_cmd); +} diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c new file mode 100644 index 00000000..81f0ecad --- /dev/null +++ b/ripngd/ripngd.c @@ -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 + +/* For struct udphdr. */ +#include + +#include "prefix.h" +#include "filter.h" +#include "log.h" +#include "thread.h" +#include "memory.h" +#include "if.h" +#include "stream.h" +#include "table.h" +#include "command.h" +#include "sockopt.h" +#include "distribute.h" +#include "plist.h" +#include "routemap.h" +#include "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; +}; + +/* Utility function for making IPv6 address string. */ +const char * +inet6_ntop (struct in6_addr *p) +{ + static char buf[INET6_ADDRSTRLEN]; + + inet_ntop (AF_INET6, p, buf, INET6_ADDRSTRLEN); + + return buf; +} + +/* Allocate new ripng information. */ +struct ripng_info * +ripng_info_new () +{ + struct ripng_info *new; + + new = XCALLOC (MTYPE_RIPNG_ROUTE, sizeof (struct ripng_info)); + return new; +} + +/* Free ripng information. */ +void +ripng_info_free (struct ripng_info *rinfo) +{ + XFREE (MTYPE_RIPNG_ROUTE, rinfo); +} + +static int +setsockopt_so_recvbuf (int sock, int size) +{ + int ret; + + ret = setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof (int)); + if (ret < 0) + zlog (NULL, LOG_ERR, "can't setsockopt SO_RCVBUF"); + return ret; +} + +/* Create ripng socket. */ +int +ripng_make_socket (void) +{ + int ret; + int sock; + struct sockaddr_in6 ripaddr; + + sock = socket (AF_INET6, SOCK_DGRAM, 0); + if (sock < 0) + { + zlog (NULL, LOG_ERR, "Can't make ripng socket"); + return sock; + } + + ret = setsockopt_so_recvbuf (sock, 8096); + if (ret < 0) + return ret; + ret = setsockopt_ipv6_pktinfo (sock, 1); + if (ret < 0) + return ret; + ret = setsockopt_ipv6_multicast_hops (sock, 255); + if (ret < 0) + return ret; + ret = setsockopt_ipv6_multicast_loop (sock, 0); + if (ret < 0) + return ret; + ret = setsockopt_ipv6_hoplimit (sock, 1); + if (ret < 0) + return ret; + + memset (&ripaddr, 0, sizeof (ripaddr)); + ripaddr.sin6_family = AF_INET6; +#ifdef SIN6_LEN + ripaddr.sin6_len = sizeof (struct sockaddr_in6); +#endif /* SIN6_LEN */ + ripaddr.sin6_port = htons (RIPNG_PORT_DEFAULT); + + ret = bind (sock, (struct sockaddr *) &ripaddr, sizeof (ripaddr)); + if (ret < 0) + { + zlog (NULL, LOG_ERR, "Can't bind ripng socket: %s.", strerror (errno)); + return ret; + } + return sock; +} + +/* Send RIPng packet. */ +int +ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to, + struct interface *ifp) +{ + int ret; + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsgptr; + char adata [256]; + struct in6_pktinfo *pkt; + struct sockaddr_in6 addr; + +#ifdef DEBUG + if (to) + zlog_info ("DEBUG RIPng: send to %s", inet6_ntop (&to->sin6_addr)); + zlog_info ("DEBUG RIPng: send if %s", ifp->name); + zlog_info ("DEBUG RIPng: send packet size %d", bufsize); +#endif /* DEBUG */ + + memset (&addr, 0, sizeof (struct sockaddr_in6)); + addr.sin6_family = AF_INET6; +#ifdef SIN6_LEN + addr.sin6_len = sizeof (struct sockaddr_in6); +#endif /* SIN6_LEN */ + addr.sin6_flowinfo = htonl (RIPNG_PRIORITY_DEFAULT); + + /* When destination is specified. */ + if (to != NULL) + { + addr.sin6_addr = to->sin6_addr; + addr.sin6_port = to->sin6_port; + } + else + { + inet_pton(AF_INET6, RIPNG_GROUP, &addr.sin6_addr); + addr.sin6_port = htons (RIPNG_PORT_DEFAULT); + } + + msg.msg_name = (void *) &addr; + msg.msg_namelen = sizeof (struct sockaddr_in6); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = (void *) adata; + msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); + + iov.iov_base = buf; + iov.iov_len = bufsize; + + cmsgptr = (struct cmsghdr *)adata; + cmsgptr->cmsg_len = CMSG_LEN(sizeof (struct in6_pktinfo)); + cmsgptr->cmsg_level = IPPROTO_IPV6; + cmsgptr->cmsg_type = IPV6_PKTINFO; + + pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr); + memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr)); + pkt->ipi6_ifindex = ifp->ifindex; + + ret = sendmsg (ripng->sock, &msg, 0); + + if (ret < 0) + zlog_warn ("RIPng send fail on %s: %s", ifp->name, strerror (errno)); + + return ret; +} + +/* Receive UDP RIPng packet from socket. */ +int +ripng_recv_packet (int sock, u_char *buf, int bufsize, + struct sockaddr_in6 *from, unsigned int *ifindex, + int *hoplimit) +{ + int ret; + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsgptr; + struct in6_addr dst; + + /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this + point I can't determine size of cmsghdr */ + char adata[1024]; + + /* Fill in message and iovec. */ + msg.msg_name = (void *) from; + msg.msg_namelen = sizeof (struct sockaddr_in6); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = (void *) adata; + msg.msg_controllen = sizeof adata; + iov.iov_base = buf; + iov.iov_len = bufsize; + + /* If recvmsg fail return minus value. */ + ret = recvmsg (sock, &msg, 0); + if (ret < 0) + return ret; + + for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; + cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) + { + /* I want interface index which this packet comes from. */ + if (cmsgptr->cmsg_level == IPPROTO_IPV6 && + cmsgptr->cmsg_type == IPV6_PKTINFO) + { + struct in6_pktinfo *ptr; + + ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr); + *ifindex = ptr->ipi6_ifindex; + dst = ptr->ipi6_addr; + + if (*ifindex == 0) + zlog_warn ("Interface index returned by IPV6_PKTINFO is zero"); + } + + /* Incoming packet's multicast hop limit. */ + if (cmsgptr->cmsg_level == IPPROTO_IPV6 && + cmsgptr->cmsg_type == IPV6_HOPLIMIT) + *hoplimit = *((int *) CMSG_DATA (cmsgptr)); + } + + /* Hoplimit check shold be done when destination address is + multicast address. */ + if (! IN6_IS_ADDR_MULTICAST (&dst)) + *hoplimit = -1; + + return ret; +} + +/* Dump rip packet */ +void +ripng_packet_dump (struct ripng_packet *packet, int size, char *sndrcv) +{ + caddr_t lim; + struct rte *rte; + char *command_str; + + /* Set command string. */ + if (packet->command == RIPNG_REQUEST) + command_str = "request"; + else if (packet->command == RIPNG_RESPONSE) + command_str = "response"; + else + command_str = "unknown"; + + /* Dump packet header. */ + zlog_info ("%s %s version %d packet size %d", + sndrcv, command_str, packet->version, size); + + /* Dump each routing table entry. */ + rte = packet->rte; + + for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++) + { + if (rte->metric == RIPNG_METRIC_NEXTHOP) + zlog_info (" nexthop %s/%d", inet6_ntop (&rte->addr), rte->prefixlen); + else + zlog_info (" %s/%d metric %d tag %d", + inet6_ntop (&rte->addr), rte->prefixlen, + rte->metric, ntohs (rte->tag)); + } +} + +/* RIPng next hop address RTE (Route Table Entry). */ +void +ripng_nexthop_rte (struct rte *rte, + struct sockaddr_in6 *from, + struct ripng_nexthop *nexthop) +{ + char buf[INET6_BUFSIZ]; + + /* Logging before checking RTE. */ + if (IS_RIPNG_DEBUG_RECV) + zlog_info ("RIPng nexthop RTE address %s tag %d prefixlen %d", + inet6_ntop (&rte->addr), ntohs (rte->tag), rte->prefixlen); + + /* RFC2080 2.1.1 Next Hop: + The route tag and prefix length in the next hop RTE must be + set to zero on sending and ignored on receiption. */ + if (ntohs (rte->tag) != 0) + zlog_warn ("RIPng nexthop RTE with non zero tag value %d from %s", + ntohs (rte->tag), inet6_ntop (&from->sin6_addr)); + + if (rte->prefixlen != 0) + zlog_warn ("RIPng nexthop RTE with non zero prefixlen value %d from %s", + rte->prefixlen, inet6_ntop (&from->sin6_addr)); + + /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a + next hop RTE indicates that the next hop address should be the + originator of the RIPng advertisement. An address specified as a + next hop must be a link-local address. */ + if (IN6_IS_ADDR_UNSPECIFIED (&rte->addr)) + { + nexthop->flag = RIPNG_NEXTHOP_UNSPEC; + memset (&nexthop->address, 0, sizeof (struct in6_addr)); + return; + } + + if (IN6_IS_ADDR_LINKLOCAL (&rte->addr)) + { + nexthop->flag = RIPNG_NEXTHOP_ADDRESS; + IPV6_ADDR_COPY (&nexthop->address, &rte->addr); + return; + } + + /* The purpose of the next hop RTE is to eliminate packets being + routed through extra hops in the system. It is particularly useful + when RIPng is not being run on all of the routers on a network. + Note that next hop RTE is "advisory". That is, if the provided + information is ignored, a possibly sub-optimal, but absolutely + valid, route may be taken. If the received next hop address is not + a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */ + zlog_warn ("RIPng nexthop RTE with non link-local address %s from %s", + inet6_ntop (&rte->addr), + inet_ntop (AF_INET6, &from->sin6_addr, buf, INET6_BUFSIZ)); + + nexthop->flag = RIPNG_NEXTHOP_UNSPEC; + memset (&nexthop->address, 0, sizeof (struct in6_addr)); + + return; +} + +/* If ifp has same link-local address then return 1. */ +int +ripng_lladdr_check (struct interface *ifp, struct in6_addr *addr) +{ + listnode listnode; + struct connected *connected; + struct prefix *p; + + for (listnode = listhead (ifp->connected); listnode; nextnode (listnode)) + if ((connected = getdata (listnode)) != NULL) + { + p = connected->address; + + if (p->family == AF_INET6 && + IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6) && + IN6_ARE_ADDR_EQUAL (&p->u.prefix6, addr)) + return 1; + } + return 0; +} + +/* RIPng route garbage collect timer. */ +int +ripng_garbage_collect (struct thread *t) +{ + struct ripng_info *rinfo; + struct route_node *rp; + + rinfo = THREAD_ARG (t); + rinfo->t_garbage_collect = NULL; + + /* Off timeout timer. */ + RIPNG_TIMER_OFF (rinfo->t_timeout); + + /* Get route_node pointer. */ + rp = rinfo->rp; + + /* Delete this route from the kernel. */ + ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, + &rinfo->nexthop, rinfo->ifindex); + rinfo->flags &= ~RIPNG_RTF_FIB; + + /* Aggregate count decrement. */ + ripng_aggregate_decrement (rp, rinfo); + + /* Unlock route_node. */ + rp->info = NULL; + route_unlock_node (rp); + + /* Free RIPng routing information. */ + ripng_info_free (rinfo); + + return 0; +} + +/* Timeout RIPng routes. */ +int +ripng_timeout (struct thread *t) +{ + struct ripng_info *rinfo; + struct route_node *rp; + + rinfo = THREAD_ARG (t); + rinfo->t_timeout = NULL; + + /* Get route_node pointer. */ + rp = rinfo->rp; + + /* - The garbage-collection timer is set for 120 seconds. */ + RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect, + ripng->garbage_time); + + /* - The metric for the route is set to 16 (infinity). This causes + the route to be removed from service. */ + rinfo->metric = RIPNG_METRIC_INFINITY; + + /* - The route change flag is to indicate that this entry has been + changed. */ + rinfo->flags |= RIPNG_RTF_CHANGED; + + /* - The output process is signalled to trigger a response. */ + ripng_event (RIPNG_TRIGGERED_UPDATE, 0); + + return 0; +} + +void +ripng_timeout_update (struct ripng_info *rinfo) +{ + if (rinfo->metric != RIPNG_METRIC_INFINITY) + { + RIPNG_TIMER_OFF (rinfo->t_timeout); + RIPNG_TIMER_ON (rinfo->t_timeout, ripng_timeout, ripng->timeout_time); + } +} + +/* Process RIPng route according to RFC2080. */ +void +ripng_route_process (struct rte *rte, struct sockaddr_in6 *from, + struct ripng_nexthop *ripng_nexthop, + struct interface *ifp) +{ + struct prefix_ipv6 p; + struct route_node *rp; + struct ripng_info *rinfo; + struct ripng_interface *ri; + struct in6_addr *nexthop; + u_char oldmetric; + int same = 0; + + /* Make prefix structure. */ + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + /* p.prefix = rte->addr; */ + IPV6_ADDR_COPY (&p.prefix, &rte->addr); + p.prefixlen = rte->prefixlen; + + /* Make sure mask is applied. */ + /* XXX We have to check the prefix is valid or not before call + apply_mask_ipv6. */ + apply_mask_ipv6 (&p); + + /* Apply input filters. */ + ri = ifp->info; + + if (ri->list[RIPNG_FILTER_IN]) + { + if (access_list_apply (ri->list[RIPNG_FILTER_IN], &p) == FILTER_DENY) + { + if (IS_RIPNG_DEBUG_PACKET) + zlog_info ("RIPng %s/%d is filtered by distribute in", + inet6_ntop (&p.prefix), p.prefixlen); + return; + } + } + if (ri->prefix[RIPNG_FILTER_IN]) + { + if (prefix_list_apply (ri->prefix[RIPNG_FILTER_IN], &p) == PREFIX_DENY) + { + if (IS_RIPNG_DEBUG_PACKET) + zlog_info ("RIPng %s/%d is filtered by prefix-list in", + inet6_ntop (&p.prefix), p.prefixlen); + return; + } + } + + /* Modify entry. */ + if (ri->routemap[RIPNG_FILTER_IN]) + { + int ret; + struct ripng_info newinfo; + + memset (&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); + } +} + +int +ripng_update_jitter (int time) +{ + return ((rand () % (time + 1)) - (time / 2)); +} + +void +ripng_event (enum ripng_event event, int sock) +{ + int ripng_request_all (struct thread *); + int jitter = 0; + + switch (event) + { + case RIPNG_READ: + if (!ripng->t_read) + ripng->t_read = thread_add_read (master, ripng_read, NULL, sock); + break; + case RIPNG_UPDATE_EVENT: + if (ripng->t_update) + { + thread_cancel (ripng->t_update); + ripng->t_update = NULL; + } + /* Update timer jitter. */ + jitter = ripng_update_jitter (ripng->update_time); + + ripng->t_update = + thread_add_timer (master, ripng_update, NULL, + sock ? 2 : ripng->update_time + jitter); + break; + case RIPNG_TRIGGERED_UPDATE: + if (ripng->t_triggered_interval) + ripng->trigger = 1; + else if (! ripng->t_triggered_update) + ripng->t_triggered_update = + thread_add_event (master, ripng_triggered_update, NULL, 0); + break; + default: + break; + } +} + +/* Each route type's strings and default preference. */ +struct +{ + int key; + char *str; + char *str_long; + int distance; +} route_info[] = +{ + { ZEBRA_ROUTE_SYSTEM, "X", "system", 10}, + { ZEBRA_ROUTE_KERNEL, "K", "kernel", 20}, + { ZEBRA_ROUTE_CONNECT, "C", "connected", 30}, + { ZEBRA_ROUTE_STATIC, "S", "static", 40}, + { ZEBRA_ROUTE_RIP, "R", "rip", 50}, + { ZEBRA_ROUTE_RIPNG, "R", "ripng", 50}, + { ZEBRA_ROUTE_OSPF, "O", "ospf", 60}, + { ZEBRA_ROUTE_OSPF6, "O", "ospf6", 60}, + { ZEBRA_ROUTE_BGP, "B", "bgp", 70}, +}; + +/* For messages. */ +struct message ripng_route_info[] = +{ + { RIPNG_ROUTE_RTE, " "}, + { RIPNG_ROUTE_STATIC, "S"}, + { RIPNG_ROUTE_AGGREGATE, "a"} +}; + +/* Print out routes update time. */ +static void +ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo) +{ + struct timeval timer_now; + time_t clock; + struct tm *tm; +#define TIME_BUF 25 + char timebuf [TIME_BUF]; + struct thread *thread; + + gettimeofday (&timer_now, NULL); + + if ((thread = rinfo->t_timeout) != NULL) + { + clock = thread->u.sands.tv_sec - timer_now.tv_sec; + tm = gmtime (&clock); + strftime (timebuf, TIME_BUF, "%M:%S", tm); + vty_out (vty, "%5s", timebuf); + } + else if ((thread = rinfo->t_garbage_collect) != NULL) + { + clock = thread->u.sands.tv_sec - timer_now.tv_sec; + tm = gmtime (&clock); + strftime (timebuf, TIME_BUF, "%M:%S", tm); + vty_out (vty, "%5s", timebuf); + } +} + +DEFUN (show_ipv6_ripng, + show_ipv6_ripng_cmd, + "show ipv6 ripng", + SHOW_STR + IP_STR + "Show RIPng routes\n") +{ + struct route_node *rp; + struct ripng_info *rinfo; + struct ripng_aggregate *aggregate; + struct prefix_ipv6 *p; + int len; + + /* Header of display. */ + vty_out (vty, "%sCodes: R - RIPng%s%s" + " Network " + "Next Hop If Met Tag Time%s", VTY_NEWLINE, + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + + for (rp = route_top (ripng->table); rp; rp = route_next (rp)) + { + if ((aggregate = rp->aggregate) != NULL) + { + p = (struct prefix_ipv6 *) &rp->p; + +#ifdef DEBUG + len = vty_out (vty, "Ra %d/%d %s/%d ", + aggregate->count, aggregate->suppress, + inet6_ntop (&p->prefix), p->prefixlen); +#else + len = vty_out (vty, "Ra %s/%d ", + inet6_ntop (&p->prefix), p->prefixlen); +#endif /* DEBUG */ + + len = 37 - len; + if (len > 0) + vty_out (vty, "%*s", len, " "); + + vty_out (vty, "%*s", 26, " "); + vty_out (vty, "%4d %3d%s", aggregate->metric, + aggregate->tag, + VTY_NEWLINE); + } + + if ((rinfo = rp->info) != NULL) + { + p = (struct prefix_ipv6 *) &rp->p; + +#ifdef DEBUG + len = vty_out (vty, "%s%s 0/%d %s/%d ", + route_info[rinfo->type].str, + rinfo->suppress ? "s" : " ", + rinfo->suppress, + inet6_ntop (&p->prefix), p->prefixlen); +#else + len = vty_out (vty, "%s%s %s/%d ", + route_info[rinfo->type].str, + rinfo->suppress ? "s" : " ", + inet6_ntop (&p->prefix), p->prefixlen); +#endif /* DEBUG */ + len = 37 - len; + if (len > 0) + vty_out (vty, "%*s", len, " "); + + len = vty_out (vty, "%s", inet6_ntop (&rinfo->nexthop)); + + len = 26 - len; + if (len > 0) + vty_out (vty, "%*s", len, " "); + + vty_out (vty, "%2d %2d %3d ", + rinfo->ifindex, rinfo->metric, rinfo->tag); + + if (rinfo->sub_type == RIPNG_ROUTE_RTE) + ripng_vty_out_uptime (vty, rinfo); + + vty_out (vty, "%s", VTY_NEWLINE); + } + } + + return CMD_SUCCESS; +} + +DEFUN (router_ripng, + router_ripng_cmd, + "router ripng", + "Enable a routing process\n" + "Make RIPng instance command\n") +{ + int ret; + + vty->node = RIPNG_NODE; + + if (!ripng) + { + ret = ripng_create (); + + /* Notice to user we couldn't create RIPng. */ + if (ret < 0) + { + zlog_warn ("can't create RIPng"); + return CMD_WARNING; + } + } + + return CMD_SUCCESS; +} + +DEFUN (ripng_route, + ripng_route_cmd, + "route IPV6ADDR", + "Static route setup\n" + "Set static RIPng route announcement\n") +{ + int ret; + struct prefix_ipv6 p; + struct route_node *rp; + + ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p); + if (ret <= 0) + { + vty_out (vty, "Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + apply_mask_ipv6 (&p); + + rp = route_node_get (ripng->route, (struct prefix *) &p); + if (rp->info) + { + vty_out (vty, "There is already same static route.%s", VTY_NEWLINE); + route_unlock_node (rp); + return CMD_WARNING; + } + rp->info = (void *)1; + + ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0); + + return CMD_SUCCESS; +} + +DEFUN (no_ripng_route, + no_ripng_route_cmd, + "no route IPV6ADDR", + NO_STR + "Static route setup\n" + "Delete static RIPng route announcement\n") +{ + int ret; + struct prefix_ipv6 p; + struct route_node *rp; + + ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p); + if (ret <= 0) + { + vty_out (vty, "Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + apply_mask_ipv6 (&p); + + rp = route_node_lookup (ripng->route, (struct prefix *) &p); + if (! rp) + { + vty_out (vty, "Can't find static route.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0); + route_unlock_node (rp); + + rp->info = NULL; + route_unlock_node (rp); + + return CMD_SUCCESS; +} + +DEFUN (ripng_aggregate_address, + ripng_aggregate_address_cmd, + "aggregate-address X:X::X:X/M", + "Set aggregate RIPng route announcement\n" + "Aggregate network\n") +{ + int ret; + struct prefix p; + struct route_node *node; + + ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p); + if (ret <= 0) + { + vty_out (vty, "Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check aggregate alredy exist or not. */ + node = route_node_get (ripng->aggregate, &p); + if (node->info) + { + vty_out (vty, "There is already same aggregate route.%s", VTY_NEWLINE); + route_unlock_node (node); + return CMD_WARNING; + } + node->info = (void *)1; + + ripng_aggregate_add (&p); + + return CMD_SUCCESS; +} + +DEFUN (no_ripng_aggregate_address, + no_ripng_aggregate_address_cmd, + "no aggregate-address X:X::X:X/M", + NO_STR + "Delete aggregate RIPng route announcement\n" + "Aggregate network") +{ + int ret; + struct prefix p; + struct route_node *rn; + + ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &p); + if (ret <= 0) + { + vty_out (vty, "Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rn = route_node_lookup (ripng->aggregate, &p); + if (! rn) + { + vty_out (vty, "Can't find aggregate route.%s", VTY_NEWLINE); + return CMD_WARNING; + } + route_unlock_node (rn); + rn->info = NULL; + route_unlock_node (rn); + + ripng_aggregate_delete (&p); + + return CMD_SUCCESS; +} + +DEFUN (ripng_default_metric, + ripng_default_metric_cmd, + "default-metric <1-16>", + "Set a metric of redistribute routes\n" + "Default metric\n") +{ + if (ripng) + { + ripng->default_metric = atoi (argv[0]); + } + return CMD_SUCCESS; +} + +DEFUN (no_ripng_default_metric, + no_ripng_default_metric_cmd, + "no default-metric", + NO_STR + "Set a metric of redistribute routes\n" + "Default metric\n") +{ + if (ripng) + { + ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT; + } + return CMD_SUCCESS; +} + +ALIAS (no_ripng_default_metric, + no_ripng_default_metric_val_cmd, + "no default-metric <1-16>", + NO_STR + "Set a metric of redistribute routes\n" + "Default metric\n") + +#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 index 00000000..ad673e57 --- /dev/null +++ b/ripngd/ripngd.conf.sample @@ -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 index 00000000..2509bdd5 --- /dev/null +++ b/ripngd/ripngd.h @@ -0,0 +1,318 @@ +/* + * RIPng related value and structure. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RIPNG_RIPNGD_H +#define _ZEBRA_RIPNG_RIPNGD_H + +/* RIPng version and port number. */ +#define RIPNG_V1 1 +#define RIPNG_PORT_DEFAULT 521 +#define RIPNG_VTY_PORT 2603 +#define RIPNG_VTYSH_PATH "/tmp/.ripngd" +#define RIPNG_MAX_PACKET_SIZE 1500 +#define RIPNG_PRIORITY_DEFAULT 0 + +/* RIPng commands. */ +#define RIPNG_REQUEST 1 +#define RIPNG_RESPONSE 2 + +/* RIPng metric and multicast group address. */ +#define RIPNG_METRIC_INFINITY 16 +#define RIPNG_METRIC_NEXTHOP 0xff +#define RIPNG_GROUP "ff02::9" + +/* RIPng timers. */ +#define RIPNG_UPDATE_TIMER_DEFAULT 30 +#define RIPNG_TIMEOUT_TIMER_DEFAULT 180 +#define RIPNG_GARBAGE_TIMER_DEFAULT 120 + +/* Default config file name. */ +#define RIPNG_DEFAULT_CONFIG "ripngd.conf" + +/* RIPng route types. */ +#define RIPNG_ROUTE_RTE 0 +#define RIPNG_ROUTE_STATIC 1 +#define RIPNG_ROUTE_AGGREGATE 2 + +/* Interface send/receive configuration. */ +#define RIPNG_SEND_UNSPEC 0 +#define RIPNG_SEND_OFF 1 +#define RIPNG_RECEIVE_UNSPEC 0 +#define RIPNG_RECEIVE_OFF 1 + +/* Split horizon definitions. */ +#define RIPNG_SPLIT_HORIZON_UNSPEC 0 +#define RIPNG_SPLIT_HORIZON_NONE 1 +#define RIPNG_SPLIT_HORIZON 2 +#define RIPNG_SPLIT_HORIZON_POISONED 3 + +/* RIP default route's accept/announce methods. */ +#define RIPNG_DEFAULT_ADVERTISE_UNSPEC 0 +#define RIPNG_DEFAULT_ADVERTISE_NONE 1 +#define RIPNG_DEFAULT_ADVERTISE 2 + +#define RIPNG_DEFAULT_ACCEPT_UNSPEC 0 +#define RIPNG_DEFAULT_ACCEPT_NONE 1 +#define RIPNG_DEFAULT_ACCEPT 2 + +/* Default value for "default-metric" command. */ +#define RIPNG_DEFAULT_METRIC_DEFAULT 1 + +/* For max RTE calculation. */ +#ifndef IPV6_HDRLEN +#define IPV6_HDRLEN 40 +#endif /* IPV6_HDRLEN */ + +#ifndef IFMINMTU +#define IFMINMTU 576 +#endif /* IFMINMTU */ + +/* RIPng structure. */ +struct ripng +{ + /* RIPng socket. */ + int sock; + + /* RIPng Parameters.*/ + u_char command; + u_char version; + unsigned long update_time; + unsigned long timeout_time; + unsigned long garbage_time; + int max_mtu; + int default_metric; + int default_information; + + /* Input/output buffer of RIPng. */ + struct stream *ibuf; + struct stream *obuf; + + /* RIPng routing information base. */ + struct route_table *table; + + /* RIPng only static route information. */ + struct route_table *route; + + /* RIPng aggregate route information. */ + struct route_table *aggregate; + + /* RIPng threads. */ + struct thread *t_read; + struct thread *t_write; + struct thread *t_update; + struct thread *t_garbage; + struct thread *t_zebra; + + /* Triggered update hack. */ + int trigger; + struct thread *t_triggered_update; + struct thread *t_triggered_interval; + + /* For redistribute route map. */ + struct + { + char *name; + struct route_map *map; + int metric_config; + u_int32_t metric; + } route_map[ZEBRA_ROUTE_MAX]; +}; + +/* Routing table entry. */ +struct rte +{ + struct in6_addr addr; + u_short tag; + u_char prefixlen; + u_char metric; +}; + +/* RIPNG send packet. */ +struct ripng_packet +{ + u_char command; + u_char version; + u_int16_t zero; + struct rte rte[1]; +}; + +/* Each route's information. */ +struct ripng_info +{ + /* This route's type. Static, ripng or aggregate. */ + u_char type; + + /* Sub type for static route. */ + u_char sub_type; + + /* RIPng specific information */ + struct in6_addr nexthop; + struct in6_addr from; + + /* Which interface does this route come from. */ + unsigned int ifindex; + + /* Metric of this route. */ + u_char metric; + + /* Tag field of RIPng packet.*/ + u_int16_t tag; + + /* For aggregation. */ + unsigned int suppress; + + /* Flags of RIPng route. */ +#define RIPNG_RTF_FIB 1 +#define RIPNG_RTF_CHANGED 2 + u_char flags; + + /* Garbage collect timer. */ + struct thread *t_timeout; + struct thread *t_garbage_collect; + + /* Route-map features - this variables can be changed. */ + u_char metric_set; + + struct route_node *rp; +}; + +/* RIPng tag structure. */ +struct ripng_tag +{ + /* Tag value. */ + u_int16_t tag; + + /* Port. */ + u_int16_t port; + + /* Multicast group. */ + struct in6_addr maddr; + + /* Table number. */ + int table; + + /* Distance. */ + int distance; + + /* Split horizon. */ + u_char split_horizon; + + /* Poison reverse. */ + u_char poison_reverse; +}; + +/* RIPng specific interface configuration. */ +struct ripng_interface +{ + /* RIPng is enabled on this interface. */ + int enable_network; + int enable_interface; + + /* RIPng is running on this interface. */ + int running; + + /* For filter type slot. */ +#define RIPNG_FILTER_IN 0 +#define RIPNG_FILTER_OUT 1 +#define RIPNG_FILTER_MAX 2 + + /* Access-list. */ + struct access_list *list[RIPNG_FILTER_MAX]; + + /* Prefix-list. */ + struct prefix_list *prefix[RIPNG_FILTER_MAX]; + + /* Route-map. */ + struct route_map *routemap[RIPNG_FILTER_MAX]; + + /* RIPng tag configuration. */ + struct ripng_tag *rtag; + + /* Default information originate. */ + u_char default_originate; + + /* Default information only. */ + u_char default_only; + + /* Wake up thread. */ + struct thread *t_wakeup; + + /* Passive interface. */ + int passive; +}; + +/* All RIPng events. */ +enum ripng_event +{ + RIPNG_READ, + RIPNG_ZEBRA, + RIPNG_REQUEST_EVENT, + RIPNG_UPDATE_EVENT, + RIPNG_TRIGGERED_UPDATE, +}; + +/* RIPng timer on/off macro. */ +#define RIPNG_TIMER_ON(T,F,V) \ +do { \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), rinfo, (V)); \ +} while (0) + +#define RIPNG_TIMER_OFF(T) \ +do { \ + if (T) \ + { \ + thread_cancel(T); \ + (T) = NULL; \ + } \ +} while (0) + +/* Count prefix size from mask length */ +#define PSIZE(a) (((a) + 7) / (8)) + +/* Extern variables. */ +extern struct ripng *ripng; + +extern struct thread_master *master; + +/* Prototypes. */ +void ripng_init (); +void ripng_if_init (); +void ripng_terminate (); +void ripng_zclient_start (); +void zebra_init (); +struct ripng_info * ripng_info_new (); +void ripng_info_free (struct ripng_info *rinfo); +void ripng_event (enum ripng_event, int); +int ripng_request (struct interface *ifp); +void ripng_redistribute_add (int, int, struct prefix_ipv6 *, unsigned int); +void ripng_redistribute_delete (int, int, struct prefix_ipv6 *, unsigned int); +void ripng_redistribute_withdraw (int type); + +void ripng_distribute_update_interface (struct interface *); +void ripng_if_rmap_update_interface (struct interface *); + +void ripng_zebra_ipv6_add (struct prefix_ipv6 *p, struct in6_addr *nexthop, unsigned int ifindex); +void ripng_zebra_ipv6_delete (struct prefix_ipv6 *p, struct in6_addr *nexthop, unsigned int ifindex); +void ripng_route_map_init (); + +#endif /* _ZEBRA_RIPNG_RIPNGD_H */ diff --git a/stamp-h.in b/stamp-h.in new file mode 100644 index 00000000..9788f702 --- /dev/null +++ b/stamp-h.in @@ -0,0 +1 @@ +timestamp diff --git a/tools/mrlg.cgi b/tools/mrlg.cgi new file mode 100755 index 00000000..ac468eef --- /dev/null +++ b/tools/mrlg.cgi @@ -0,0 +1,395 @@ +#!/usr/bin/perl +## +## Zebra Looking Glass version 1.0 +## 01 FEB 2000 +## Copyright (C) 2000 John W. Fraizer III +## *All* copyright notices must remain in place to use this code. +## +## The latest version of this code is available at: +## ftp://ftp.enterzone.net/looking-glass/ +## +## +## This file is part of GNU Zebra. +## +## GNU Zebra is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## GNU Zebra is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with GNU Zebra; see the file COPYING. If not, write to the +## Free Software Foundation, Inc., 59 Temple Place - Suite 330, +## Boston, MA 02111-1307, USA. + +require 5.002; +use POSIX; +use Net::Telnet (); + + + +## Set the URL for your site. +$url="http://www.sample.com/mrlg.cgi"; + +## Set your router variables in sub set_router and modify the selections in Main to match. + + +############################################################ +#Main +############################################################ +{ + +## Set the router default +@Form{'router'} = "router1"; + +## Get the form results now so we can override the default router +get_form(); + +print "Content-type: text/html\n\n"; + +print ' + + +Multi-Router Looking Glass for Zebra + + + + +

Multi-Router Looking Glass for Zebra

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

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

+
+ +Multi-Router Looking Glass for Zebra version 1.0
+Written by: John Fraizer - +EnterZone, Inc
+Source code: ftp://ftp.enterzone.net/looking-glass/ + + +'; + +## All done! + +exit (0); +} + + +############################################################ +sub get_form +############################################################ +{ + + #read STDIN + read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); + + # Split the name-value pairs + @pairs = split(/&/, $buffer); + + # For each name-value pair: + foreach $pair (@pairs) + { + + # Split the pair up into individual variables. + local($name, $value) = split(/=/, $pair); + + # Decode the form encoding on the name and value variables. + $name =~ tr/+/ /; + $name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; + + $value =~ tr/+/ /; + $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; + + # If they try to include server side includes, erase them, so they + # aren't a security risk if the html gets returned. Another + # security hole plugged up. + $value =~ s///g; + + @Form{$name} = $value ; + + } + +} + +############################################################ +sub set_router +############################################################ + +## $server is the IP address of the router running zebra +## $login_pass is the password of the router +## $bgpd is the port that bgpd will answer on +## $zebra is the port that zebra will answer on +## if $zebra is "", it will disable sh ip route and sh int for that router. +## if $full_tables is set to "1" for a router, full BGP and IP ROUTE table dumps will be allowed via the looking glass. +## This is a BAD thing to do if you have multiple full views on a router. That's why the option is there. + +{ +if ($Form{'router'} eq 'router1') + { +$server = '10.1.1.1'; +$login_pass = 'zebra'; +$bgpd = "2605"; +$zebra = ""; +$full_tables=1; + + } + +elsif ($Form{'router'} eq 'router2') + { +$server = '10.1.1.2'; +$login_pass = 'zebra'; +$bgpd = "2605"; +$zebra = "2601"; + } + +elsif ($Form{'router'} eq 'router3') + { +$server = '10.1.1.3'; +$login_pass = 'zebra'; +$bgpd = "2605"; +$zebra = "2601"; +$full_tables=1; + } + +elsif ($Form{'router'} eq 'router4') + { +$server = '10.1.1.4'; +$login_pass = 'zebra'; +$bgpd = "2605"; +$zebra = "2601"; + } + + +} + + +############################################################ +sub set_command +############################################################ +{ +if ($Form{'query'} eq '1') + { + sh_ip_bgp('ip'); + } + +elsif ($Form{'query'} eq '2') + { + sh_ip_bgp_sum('ip'); + } + +if ($Form{'query'} eq '3') + { + sh_ip_route('ip'); + } + +if ($Form{'query'} eq '4') + { + sh_int(); + } +if ($Form{'query'} eq '5') + { + sh_ip_bgp('ipv6'); + } +if ($Form{'query'} eq '6') + { + sh_ip_bgp_sum('ipv6'); + } +if ($Form{'query'} eq '7') + { + sh_ip_route('ipv6'); + } +} +############################################################ +sub sh_ip_bgp +############################################################ +{ +my $protocol = shift(@_); +$port = $bgpd; +if ($protocol ne 'ip' && $protocol ne 'ipv6') + { + print "Invalid protocol: $protocol\n"; + print "protocol must be 'ip' or 'ipv6'\n\n"; + return; + } +$command = "show $protocol bgp $Form{'arg'}"; +if ($Form{'arg'} eq '') + { + if ($full_tables eq '1') + { + execute_command(); + } + else + { + print "Sorry. Displaying the FULL routing table would put too much load on the router!\n\n"; + } + } +else + { + execute_command(); + } +} + +############################################################ +sub sh_ip_bgp_sum +############################################################ +{ + my $protocol = shift(@_); + $port = $bgpd; + if ($protocol ne 'ip' && $protocol ne 'ipv6') + { + print "Invalid protocol: $protocol\n"; + print "protocol must be 'ip' or 'ipv6'\n\n"; + return; + } + $command = "show $protocol bgp summary"; + execute_command(); +} + +############################################################ +sub sh_ip_route +############################################################ +{ + +if ($zebra eq '') + { + print "Sorry. The show ip route command is disabled for this router." + } +else + { + + $port = $zebra; + my $protocol = shift(@_); + if ($protocol ne 'ip' && $protocol ne 'ipv6') + { + print "Invalid protocol: $protocol\n"; + print "protocol must be 'ip' or 'ipv6'\n\n"; + return; + } + $command = "show $protocol route $Form{'arg'}"; + if ($Form{'arg'} eq '') + { + if ($full_tables eq '1') + { + execute_command(); + } + else + { + print "Sorry. Displaying the FULL routing table would put too much load on the router!\n\n"; + } + } + else + { + execute_command(); + } + } +} + +############################################################ +sub sh_int +############################################################ +{ +if ($zebra eq '') + { + print "Sorry. The show interface command is disabled for this router." + } +else + { + $port = $zebra; + $command = "show interface $Form{'arg'}"; + execute_command(); + } +} + + + +############################################################ +sub execute_command +############################################################ +## This code is based on: +## +## Zebra interactive console +## Copyright (C) 2000 Vladimir B. Grebenschikov +## + + +{ + +print "Executing command = $command"; + +# my $port = ($opt_z ? 'zebra' : 0) || +# ($opt_b ? 'bgpd' : 0) || +# ($opt_o ? 'ospfd' : 0) || +# ($opt_r ? 'ripd' : 0) || 'bgpd'; + +my $cmd = $command; + + + my $t = new Net::Telnet (Timeout => 10, + Prompt => '/[\>\#] $/', + Port => $port); + + $t->open ($server); + + $t->cmd ($login_pass); + + if ($cmd) + { + docmd ($t, $cmd); + } + +} + +############################################################ +sub docmd +############################################################ +{ + my ($t, $cmd) = @_; + my @lines = $t->cmd ($cmd); + print "
\n";
+  print join ('', grep (!/[\>\#] $/, @lines)), "\n";
+  print "
"; +} + + + diff --git a/tools/rrcheck.pl b/tools/rrcheck.pl new file mode 100644 index 00000000..5e5a983c --- /dev/null +++ b/tools/rrcheck.pl @@ -0,0 +1,135 @@ +#! /bin/perl +## +## Read BGPd logfile and lookup RR's whois database. +## +## Copyright (c) 1997 Kunihiro Ishiguro +## +use Socket; + +## Configuration variables +$whois_host = "whois.jpix.ad.jp"; + +#$logfile = "/usr/local/sbin/logfile" +$logfile = shift || die "Please specify filename"; + +## mail routine +{ + local ($prefix, $origin); + + open (LOG, $logfile) || die "can't open $logfile"; + + $index = ''; + while ($index) { + $index = ; + if ($index =~ /[bgpd]/) { + break; + } + } + + while () { + if (/([\d\.\/]+)\s+([\d\.]+)\s+(\d+)\s+(\d+)\s+([\d ]+)\s+[ie\?]/) { + $prefix = $1; + $nexthop = $2; + $med = $3; + $dummy = $4; + $aspath = $5; + ($origin) = ($aspath =~ /([\d]+)$/); + + print "$nexthop [$origin] $prefix $aspath "; + + $ret = &whois_check ($prefix, $origin); + if ($ret == 0) { + print "Check OK\n"; + } elsif ($ret == 1){ + print "AS orgin mismatch\n"; + } else { + print "prefix doesn't exist \n"; + } + } + } +} + +sub whois_check +{ + local ($prefix, $origin) = @_; + local ($rr_prefix, $rr_origin) = (); + local (@result); + + $origin = "AS" . $origin; + + @result = &whois ($prefix); + + $prefix_match = 0; + foreach (@result) { + if (/^route:.*\s([\d\.\/]+)$/) { + $rr_prefix = $1; + } + if (/^origin:.*\s(AS[\d]+)$/) { + $rr_origin = $1; + + if ($prefix eq $rr_prefix and $origin eq $rr_origin) { + return 0; + } elsif ($prefix eq $rr_prefix) { + $prefix_match = 1; + } + } + } +# alarm_mail ($prefix, $origin, @result); + if ($prefix_match) { + return 1; + } else { + return 2; + } +} + +## get port of whois +sub get_whois_port +{ + local ($name, $aliases, $port, $proto) = getservbyname ("whois", "tcp"); + return ($port, $proto); +} + +## whois lookup +sub whois +{ + local ($query) = @_; + local ($port, $proto) = &get_whois_port; + local (@result); + + if ($whois_host=~ /^\s*\d+\.\d+\.\d+\.\d+\s*$/) { + $address = pack ("C4",split(/\./,$host)); + } else { + $address = (gethostbyname ($whois_host))[4]; + } + + socket (SOCKET, PF_INET, SOCK_STREAM, $proto); + + if (connect (SOCKET, sockaddr_in ($port, $address))) { + local ($oldhandle) = select (SOCKET); + $| = 1; + select($oldhandle); + + print SOCKET "$query\r\n"; + + @result = ; + return @result; + } +} + +## +sub alarm_mail +{ + local ($prefix, $origin, @result) = @_; + + open (MAIL, "|$mailer -t $mail_address") || die "can't open $mailer"; + + print MAIL "From: root\@rr1.jpix.ad.jp\n"; + print MAIL "Subject: RR $origin $prefix\n"; + print MAIL "MIME-Version: 1.0\n"; + print MAIL "Content-Type: text/plain; charset=us-ascii \n\n"; + print MAIL "RR Lookup Error Report\n"; + print MAIL "======================\n"; + print MAIL "Announced route : $prefix from $origin\n\n"; + print MAIL "@result"; + close MAIL; +} diff --git a/tools/rrlookup.pl b/tools/rrlookup.pl new file mode 100644 index 00000000..2c14e73e --- /dev/null +++ b/tools/rrlookup.pl @@ -0,0 +1,123 @@ +#! /usr/local/bin/perl +## +## Read BGPd logfile and lookup RR's whois database. +## +## Copyright (c) 1997 Kunihiro Ishiguro +## +use Socket; + +## Configuration variables +$whois_host = "whois.jpix.ad.jp"; + +#$mail_address = "toshio\@iri.co.jp"; +$mail_address = "kunihiro\@zebra.org"; +$mailer = "/usr/sbin/sendmail -oi"; + +#$logfile = "/usr/local/sbin/logfile" +$logfile = "logfile"; +$lookuplog = "lookuplog"; + +## mail routine +{ + local ($prefix, $origin); + + open (LOG, $logfile) || die "can't open $logfile"; + open (LOOKUP, ">$lookuplog") || die "can't open $lookuplog"; + + for (;;) { + while () { + if (/Update\S+ ([\d\.\/]+) .* (\d+) [ie\?]/) { + $prefix = $1; + $origin = $2; + $ret = &whois_check ($prefix, $origin); + if ($ret) { + print LOOKUP "$prefix AS$origin : Check OK\n"; + } else { + print LOOKUP "$prefix AS$origin : Error\n"; + } +# fflush (LOOKUP); + } + } + sleep (3); + } +} + +sub whois_check +{ + local ($prefix, $origin) = @_; + local ($rr_prefix, $rr_origin) = (); + local (@result); + + $origin = "AS" . $origin; + +# print "$prefix $origin\n"; + + @result = &whois ($prefix); + + foreach (@result) { + if (/^route:.*\s([\d\.\/]+)$/) { + $rr_prefix = $1; + } + if (/^origin:.*\s(AS[\d]+)$/) { + $rr_origin = $1; + + if ($prefix eq $rr_prefix and $origin eq $rr_origin) { + return 1; + } + } + } + alarm_mail ($prefix, $origin, @result); + return 0; +} + +## get port of whois +sub get_whois_port +{ + local ($name, $aliases, $port, $proto) = getservbyname ("whois", "tcp"); + return ($port, $proto); +} + +## whois lookup +sub whois +{ + local ($query) = @_; + local ($port, $proto) = &get_whois_port; + local (@result); + + if ($whois_host=~ /^\s*\d+\.\d+\.\d+\.\d+\s*$/) { + $address = pack ("C4",split(/\./,$host)); + } else { + $address = (gethostbyname ($whois_host))[4]; + } + + socket (SOCKET, PF_INET, SOCK_STREAM, $proto); + + if (connect (SOCKET, sockaddr_in ($port, $address))) { + local ($oldhandle) = select (SOCKET); + $| = 1; + select($oldhandle); + + print SOCKET "$query\r\n"; + + @result = ; + return @result; + } +} + +## +sub alarm_mail +{ + local ($prefix, $origin, @result) = @_; + + open (MAIL, "|$mailer -t $mail_address") || die "can't open $mailer"; + + print MAIL "From: root\@rr1.jpix.ad.jp\n"; + print MAIL "Subject: RR $origin $prefix\n"; + print MAIL "MIME-Version: 1.0\n"; + print MAIL "Content-Type: text/plain; charset=us-ascii \n\n"; + print MAIL "RR Lookup Error Report\n"; + print MAIL "======================\n"; + print MAIL "Announced route : $prefix from $origin\n\n"; + print MAIL "@result"; + close MAIL; +} diff --git a/tools/zc.pl b/tools/zc.pl new file mode 100755 index 00000000..026e8fe5 --- /dev/null +++ b/tools/zc.pl @@ -0,0 +1,111 @@ +#! /usr/bin/perl +## +## Zebra interactive console +## Copyright (C) 2000 Vladimir B. Grebenschikov +## +## This file is part of GNU Zebra. +## +## GNU Zebra is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## GNU Zebra is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with GNU Zebra; see the file COPYING. If not, write to the +## Free Software Foundation, Inc., 59 Temple Place - Suite 330, +## Boston, MA 02111-1307, USA. + +use Net::Telnet (); +use Getopt::Std; + +#use strict; + +my $host = `hostname -s`; $host =~ s/\s//g; +my $port = 'zebra'; +my $server = 'localhost'; + +# Check arguments +&getopts ('l:e:czborh'); + +&usage () if $opt_h; + +# main +{ + my $login_pass = $opt_l || $ENV{ZEBRA_PASSWORD} || 'zebra'; + my $enable_pass = $opt_e || $ENV{ZEBRA_ENABLE} || ''; + + my $port = ($opt_z ? 'zebra' : 0) || + ($opt_b ? 'bgpd' : 0) || + ($opt_o ? 'ospfd' : 0) || + ($opt_r ? 'ripd' : 0) || 'zebra'; + + my $cmd = join (' ', @ARGV); + + my $t = new Net::Telnet (Timeout => 10, + Prompt => '/[\>\#] $/', + Port => $port); + + $t->open ($server); + + $t->cmd ($login_pass); + if ($enable_pass) { + $t->cmd (String => 'en', + Prompt => '/Password: /'); + $t->cmd ($enable_pass); + } + $t->cmd ('conf t') if "$opt_c"; + + if ($cmd) + { + docmd ($t, $cmd); + exit (0); + } + + my $prompt = sprintf ("%s%s# ", $host, + ($port eq 'zebra') ? '' : "/$port"); + + print "\nZEBRA interactive console ($port)\n\n" if -t STDIN; + + while (1) + { + $| = 1; + print $prompt if -t STDIN; + chomp ($cmd = <>); + if (!defined ($cmd)) + { + print "\n" if -t STDIN; + exit(0); + } + exit (0) if ($cmd eq 'q' || $cmd eq 'quit'); + + docmd ($t, $cmd) if $cmd !~ /^\s*$/; + } + + exit(0); +} + +sub docmd +{ + my ($t, $cmd) = @_; + my @lines = $t->cmd ($cmd); + print join ('', grep (!/[\>\#] $/, @lines)), "\n"; +} + +sub usage +{ + print "USAGE: $0 [-l LOGIN_PASSWORD] [-e ENABLE_PASSWORD] [-z|-b|-o|-r|-h] []\n", + "\t-l - specify login password\n", + "\t-e - specify enable password\n", + "\t-c - execute command in configure mode\n", + "\t-z - connect to zebra daemon\n", + "\t-b - connect to bgpd daemon\n", + "\t-o - connect to ospfd daemon\n", + "\t-r - connect to ripd daemon\n", + "\t-h - help\n"; + exit (1); +} diff --git a/tools/zebra.el b/tools/zebra.el new file mode 100644 index 00000000..01ff09fd --- /dev/null +++ b/tools/zebra.el @@ -0,0 +1,108 @@ +;; -*- lisp -*- +;;; zebra-mode.el -- major mode for editing zebra configuration file. + +;; Copyright (C) 1998 Kunihiro Ishiguro + +;; Author: 1998 Kunihiro Ishiguro +;; SeonMeyong HEO +;; Maintainer: kunihiro@zebra.org +;; seirios@Matrix.IRI.Co.JP +;; Created: Jan 28 1998 +;; Version: Alpha 0.2 +;; Keywords: zebra bgpd ripd ripngd languages + +;; You can get the latest version of zebra from +;; +;; http://www.zebra.org/ +;; +;; Install this Emacs Lisp code +;; +;; Compile zebra.el +;; % $(EMACS) -batch -f batch-byte-compile zebra.el +;; Install zebra.el,zebra.elc to Emacs-load-path +;; % cp zebra.el zebra.elc $(emacs-load-path) +;; Add .emacs or (site-load.el | site-start.el) +;; (auto-load 'zebra-mode "zebra" nil t) +;; (auto-load 'bgp-mode "zebra" nil t) +;; (auto-load 'rip-mode "zebra" nil t) +;; + +;;; Code: + +;; Set keywords + +(defvar zebra-font-lock-keywords + (list + '("#.*$" . font-lock-comment-face) + '("!.*$" . font-lock-comment-face) + '("no\\|interface" . font-lock-type-face) + '("ip6\\|ip\\|route\\|address" . font-lock-function-name-face) + '("ipforward\\|ipv6forward" . font-lock-keyword-face) + '("hostname\\|password\\|enable\\|logfile\\|no" . font-lock-keyword-face)) + "Default value to highlight in zebra mode.") + +(defvar bgp-font-lock-keywords + (list + '("#.*$" . font-lock-comment-face) + '("!.*$" . font-lock-comment-face) + '("no\\|router" . font-lock-type-face) + '("bgp\\|router-id\\|neighbor\\|network" . font-lock-function-name-face) + '("ebgp\\|multihop\\|next\\|zebra\\|remote-as" . font-lock-keyword-face) + '("hostname\\|password\\|enable\\|logfile\\|no" . font-lock-keyword-face)) + "Default value to highlight in bgp mode.") + +(defvar rip-font-lock-keywords + (list + '("#.*$" . font-lock-comment-face) + '("!.*$" . font-lock-comment-face) + '("no\\|router\\|interface\\|ipv6\\|ip6\\|ip" . font-lock-type-face) + '("ripng\\|rip\\|recive\\|advertize\\|accept" . font-lock-function-name-face) + '("version\\|network" . font-lock-function-name-face) + '("default\\|none\\|zebra" . font-lock-keyword-face) + '("hostname\\|password\\|enable\\|logfile\\|no" . font-lock-keyword-face)) + "Default value to highlight in bgp mode.") + +;; set font-lock-mode + +(defun zebra-font-lock () + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults '(zebra-font-lock-keywords nil t))) + +(defun bgp-font-lock () + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults '(bgp-font-lock-keywords nil t))) + +(defun rip-font-lock () + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults '(rip-font-lock-keywords nil t))) + +;; define Major mode + +(defun major-mode-define () + (interactive) + (progn + (setq comment-start "[#!]" + comment-end "" + comment-start-skip "!+ ") + (run-hooks 'zebra-mode-hook) + (cond + ((string< "20" emacs-version) + (font-lock-mode))))) + +(defun zebra-mode () + (progn + (setq mode-name "zebra") + (zebra-font-lock)) + (major-mode-define)) + +(defun bgp-mode () + (progn + (setq mode-name "bgp") + (bgp-font-lock)) + (major-mode-define)) + +(defun rip-mode () + (progn + (setq mode-name "rip") + (rip-font-lock)) + (major-mode-define)) diff --git a/update-autotools b/update-autotools new file mode 100755 index 00000000..1eaeb390 --- /dev/null +++ b/update-autotools @@ -0,0 +1,14 @@ +#! /bin/sh +# +# When local system does not have the latest autoconf/automake +# -- Kunihiro Ishiguro +# +rm -f config.cache +rm -f Makefile.in +rm -f aclocal.m4 +rm -f config.h.in +rm -f configure +aclocal +autoheader +autoconf +automake --foreign diff --git a/vtysh/.cvsignore b/vtysh/.cvsignore new file mode 100644 index 00000000..a71b4c5f --- /dev/null +++ b/vtysh/.cvsignore @@ -0,0 +1,6 @@ +Makefile +*.o +vtysh +tags +TAGS +.deps diff --git a/vtysh/ChangeLog b/vtysh/ChangeLog new file mode 100644 index 00000000..5818d5c0 --- /dev/null +++ b/vtysh/ChangeLog @@ -0,0 +1,173 @@ +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-02-20 Kunihiro Ishiguro + + * vtysh.c (vtysh_client_config): Do not set bufsz to 120. + Suggested by: Matthew Grant . + +2001-02-15 Hideto Yamakawa + + * vtysh.c (vtysh_client_execute): Call fflush after fprintf. + + * vtysh_config.c (vtysh_config_dump): Use VTYSH_PAGER if defined. + +2001-02-14 Kunihiro Ishiguro + + * vtysh.c (vtysh_execute_func): Add fflush before pclose. + +2001-02-10 Kunihiro Ishiguro + + * vtysh.c: VTY shell pager name. When environment variable + VTYSH_PAGER is defined, use it as VTY shell pager. + +2001-02-09 Kunihiro Ishiguro + + * vtysh.c (vtysh_execute_func): Add pager argument for test of + pager invocation. + +2001-02-08 Kunihiro Ishiguro + + * extract.pl: Add -DHAVE_CONFIG_H option to cpp. + +2001-02-08 Matthew Grant + + * vtysh.c (vtysh_client_config): Use sysconf to determine output + buffer size. + (vtysh_write_memory): Set umask 0077. + (vtysh_connect): Check permission to the socket. + +2001-02-01 Kunihiro Ishiguro + + * zebra-0.91 is released. + +2001-01-31 Michael Rozhavsky + + * vtysh.c (new_completion): Fix problem of appending space when + completion is executed. + +2001-01-23 Akihiro Mizutani + + * vtysh.c (vtysh_write_terminal): "write terminal" to all node. + +2001-01-15 Kunihiro Ishiguro + + * vtysh.c (vtysh_execute): Fix unconditional lock by other VTY. + Suggested by Hideto Yamakawa . + +2001-01-09 Kunihiro Ishiguro + + * zebra-0.90 is released. + +2001-01-07 Kunihiro Ishiguro + + * vtysh.h (ZEBRA_PATH): Fix new vtysh path. Reported by "Matt + Ranney" + +2000-11-06 Kunihiro Ishiguro + + * vtysh.c (DEFUNSH): Add "address-family vpnv4" DEFUNSH. + +2000-10-23 Kunihiro Ishiguro + + * vtysh.c (execute_command): Add two arguemnt support for + executing child process. + (vtysh_telnet_port): New command "telnet WORD PORT" is added. + +2000-10-23 Akihiro Mizutani + + * vtysh.c (vtysh_write_memory): Display [OK] when configuration is + saved without problem. + +2000-10-20 Kunihiro Ishiguro + + * vtysh.c (vtysh_config_from_file): "key chain" command with -b + flag problem is fixed. + +2000-10-17 Kunihiro Ishiguro + + * vtysh_user.c: Change to use linklist.c. + +2000-10-02 Kunihiro Ishiguro + + * Makefile.am (noinst_HEADERS): Add vtysh_user.h. + + * zebra-0.89 is released. + +2000-09-22 Kunihiro Ishiguro + + * vtysh_main.c: Declare thread master. + +2000-08-25 Kunihiro Ishiguro + + * vtysh_main.c (main): Add missing --help procudure. Reported by + Patrick Rother . + +2000-08-22 Kunihiro Ishiguro + + * vtysh.c (DEFUNSH): "interface IFNAME" works. + +2000-08-20 Kunihiro Ishiguro + + * vtysh_user.c: Change name from vtysh_pam.c. + + * vtysh.conf.sample: New file for vtysh configuration. + +2000-08-19 Kunihiro Ishiguro + + * vtysh_pam.c (vtysh_pam): New file for PAM. + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 is released. + +2000-08-02 Kunihiro Ishiguro + + * Makefile.am (vtysh_LDADD): Remove -lreadline and -lncurses. + + * vtysh.c (vtysh_connect): Use AF_UNIX instead of AF_LOCAL for + backward compatibility. + +2000-07-09 Kunihiro Ishiguro + + * extract.pl: Change regexp to match DEFUN and ALIAS at the same + time. + +2000-07-05 Kunihiro Ishiguro + + * vtysh.c (signal_init): Ignore SIGPIPE signal. + +2000-07-04 Kunihiro Ishiguro + + * extract.pl: ALIAS command can be extracted by extract.pl. + +2000-07-03 Kunihiro Ishiguro + + * extract.pl: Fix scalar and array semantics. + + * vtysh.c (vtysh_telnet): Add "telnet" client command. + +2000-07-02 Kunihiro Ishiguro + + * vtysh.c (main): Add -e flag for passing command from arugment. + (vtysh_ping): Add "ping" command for test of command execution. + (init_node): Add "traceroute" command. + (vtysh_start_shell): Add "start-shell", "start-shell bash", + "start-shell zsh". + (sigint): Add check for execute_flag for avoid duplicate prompt. + +2000-06-28 Kunihiro Ishiguro + + * vtysh.c: New file for vty shell. + * vtysh.h: Likewise. + * extract.pl: Likewise. + * vtysh_cmd.c: Generate by extract.pl. diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am new file mode 100644 index 00000000..4327379b --- /dev/null +++ b/vtysh/Makefile.am @@ -0,0 +1,22 @@ +## Process this file with Automake to create Makefile.in + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" + +LIBS = @LIBS@ @CURSES@ @LIBPAM@ + +bin_PROGRAMS = vtysh + +vtysh_SOURCES = vtysh_main.c vtysh.c vtysh_cmd.c vtysh_user.c vtysh_config.c +noinst_HEADERS = vtysh.h vtysh_user.h +vtysh_LDADD = ../lib/libzebra.a + +sysconf_DATA = vtysh.conf.sample + +EXTRA_DIST = extract.pl vtysh.conf.sample + +rebuild4: + ./extract.pl ../zebra/*.c ../ripd/*.c ../ospfd/*.c ../bgpd/*.c ../lib/keychain.c ../lib/routemap.c ../lib/filter.c ../lib/plist.c >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 index 00000000..71eb6b49 --- /dev/null +++ b/vtysh/Makefile.in @@ -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 index 00000000..4a459013 --- /dev/null +++ b/vtysh/extract.pl @@ -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 < +#include "command.h" +#include "vtysh.h" + +EOF + +$ignore{'"interface IFNAME"'} = "ignore"; +$ignore{'"ip vrf NAME"'} = "ignore"; +$ignore{'"router rip"'} = "ignore"; +$ignore{'"router ripng"'} = "ignore"; +$ignore{'"router ospf"'} = "ignore"; +$ignore{'"router ospf <0-65535>"'} = "ignore"; +$ignore{'"router ospf6"'} = "ignore"; +$ignore{'"router bgp <1-65535>"'} = "ignore"; +$ignore{'"router bgp <1-65535> view WORD"'} = "ignore"; +$ignore{'"address-family ipv4"'} = "ignore"; +$ignore{'"address-family ipv4 (unicast|multicast)"'} = "ignore"; +$ignore{'"address-family ipv6"'} = "ignore"; +$ignore{'"address-family ipv6 unicast"'} = "ignore"; +$ignore{'"address-family vpnv4"'} = "ignore"; +$ignore{'"address-family vpnv4 unicast"'} = "ignore"; +$ignore{'"address-family ipv4 vrf NAME"'} = "ignore"; +$ignore{'"exit-address-family"'} = "ignore"; +$ignore{'"key chain WORD"'} = "ignore"; +$ignore{'"key <0-2147483647>"'} = "ignore"; +$ignore{'"route-map WORD (deny|permit) <1-65535>"'} = "ignore"; +$ignore{'"show route-map"'} = "ignore"; + +foreach (@ARGV) { + $file = $_; + + open (FH, "cpp -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -I. -I.. -I../lib $file |"); + local $/; undef $/; + $line = ; + close (FH); + + @defun = ($line =~ /(?:DEFUN|ALIAS)\s*\((.+?)\);?\s?\s?\n/sg); + @install = ($line =~ /install_element \(\s*[0-9A-Z_]+,\s*&[^;]*;\s*\n/sg); + + # $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 < + +#include +#include +#include +#include +#include + +#include +#include + +#include "command.h" +#include "memory.h" +#include "vtysh/vtysh.h" + +/* Struct VTY. */ +struct vty *vty; + +/* VTY shell pager name. */ +char *vtysh_pager_name = NULL; + +/* VTY shell client structure. */ +struct vtysh_client +{ + int fd; +} vtysh_client[VTYSH_INDEX_MAX]; + +/* When '^Z' is received from vty, move down to the enable mode. */ +int +vtysh_end () +{ + switch (vty->node) + { + case VIEW_NODE: + case ENABLE_NODE: + /* Nothing to do. */ + break; + default: + vty->node = ENABLE_NODE; + break; + } + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + vtysh_end_all, + vtysh_end_all_cmd, + "end", + "End current mode and down to previous mode\n") +{ + return vtysh_end (vty); +} + +DEFUNSH (VTYSH_ALL, + vtysh_log_stdout, + vtysh_log_stdout_cmd, + "log stdout", + "Logging control\n" + "Logging goes to stdout\n") +{ + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + no_vtysh_log_stdout, + no_vtysh_log_stdout_cmd, + "no log stdout", + NO_STR + "Logging control\n" + "Logging goes to stdout\n") +{ + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + vtysh_log_file, + vtysh_log_file_cmd, + "log file FILENAME", + "Logging control\n" + "Logging to file\n" + "Logging filename\n") +{ + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + no_vtysh_log_file, + no_vtysh_log_file_cmd, + "no log file [FILENAME]", + NO_STR + "Logging control\n" + "Cancel logging to file\n" + "Logging file name\n") +{ + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + vtysh_log_syslog, + vtysh_log_syslog_cmd, + "log syslog", + "Logging control\n" + "Logging goes to syslog\n") +{ + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + no_vtysh_log_syslog, + no_vtysh_log_syslog_cmd, + "no log syslog", + NO_STR + "Logging control\n" + "Cancel logging to syslog\n") +{ + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + vtysh_log_trap, + vtysh_log_trap_cmd, + "log trap (emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)", + "Logging control\n" + "Limit logging to specifed level\n") +{ + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + no_vtysh_log_trap, + no_vtysh_log_trap_cmd, + "no log trap", + NO_STR + "Logging control\n" + "Permit all logging information\n") +{ + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + vtysh_log_record_priority, + vtysh_log_record_priority_cmd, + "log record-priority", + "Logging control\n" + "Log the priority of the message within the message\n") +{ + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + no_vtysh_log_record_priority, + no_vtysh_log_record_priority_cmd, + "no log record-priority", + NO_STR + "Logging control\n" + "Do not log the priority of the message within the message\n") +{ + return CMD_SUCCESS; +} + +void +vclient_close (struct vtysh_client *vclient) +{ + if (vclient->fd > 0) + close (vclient->fd); + vclient->fd = -1; +} + + +/* Following filled with debug code to trace a problematic condition + under load - it SHOULD handle it. +*/ +#define ERR_WHERE_STRING "vtysh(): vtysh_client_config(): " +int +vtysh_client_config (struct vtysh_client *vclient, char *line) +{ + int ret; + char *buf; + size_t bufsz; + char *pbuf; + size_t left; + char *eoln; + int nbytes; + int i; + int readln; + + if (vclient->fd < 0) + return CMD_SUCCESS; + + ret = write (vclient->fd, line, strlen (line) + 1); + if (ret <= 0) + { + vclient_close (vclient); + return CMD_SUCCESS; + } + + /* Allow enough room for buffer to read more than a few pages from socket + */ + bufsz = 5 * sysconf(_SC_PAGESIZE) + 1; + buf = XMALLOC(MTYPE_TMP, bufsz); + memset(buf, 0, bufsz); + pbuf = buf; + + while (1) + { + if (pbuf >= ((buf + bufsz) -1)) + { + fprintf (stderr, ERR_WHERE_STRING \ + "warning - pbuf beyond buffer end.\n"); + return CMD_WARNING; + } + + readln = (buf + bufsz) - pbuf - 1; + nbytes = read (vclient->fd, pbuf, readln); + + if (nbytes <= 0) + { + + if (errno == EINTR) + continue; + + fprintf(stderr, ERR_WHERE_STRING "(%u)", errno); + perror(""); + + if (errno == EAGAIN || errno == EIO) + continue; + + vclient_close (vclient); + XFREE(MTYPE_TMP, buf); + return CMD_SUCCESS; + } + + pbuf[nbytes] = '\0'; + + if (nbytes >= 4) + { + i = nbytes - 4; + if (pbuf[i] == '\0' && pbuf[i + 1] == '\0' && pbuf[i + 2] == '\0') + { + ret = pbuf[i + 3]; + break; + } + } + pbuf += nbytes; + + /* See if a line exists in buffer, if so parse and consume it, and + reset read position */ + if ((eoln = strrchr(buf, '\n')) == NULL) + continue; + + if (eoln >= ((buf + bufsz) - 1)) + { + fprintf (stderr, ERR_WHERE_STRING \ + "warning - eoln beyond buffer end.\n"); + } + vtysh_config_parse(buf); + + eoln++; + left = (size_t)(buf + bufsz - eoln); + memmove(buf, eoln, left); + buf[bufsz-1] = '\0'; + pbuf = buf + strlen(buf); + } + + /* parse anything left in the buffer */ + vtysh_config_parse (buf); + + XFREE(MTYPE_TMP, buf); + return ret; +} + +int +vtysh_client_execute (struct vtysh_client *vclient, char *line, FILE *fp) +{ + int ret; + char buf[1001]; + int nbytes; + int i; + + if (vclient->fd < 0) + return CMD_SUCCESS; + + ret = write (vclient->fd, line, strlen (line) + 1); + if (ret <= 0) + { + vclient_close (vclient); + return CMD_SUCCESS; + } + + while (1) + { + nbytes = read (vclient->fd, buf, sizeof(buf)-1); + + if (nbytes <= 0 && errno != EINTR) + { + vclient_close (vclient); + return CMD_SUCCESS; + } + + if (nbytes > 0) + { + buf[nbytes] = '\0'; + fprintf (fp, "%s", buf); + fflush (fp); + + if (nbytes >= 4) + { + i = nbytes - 4; + if (buf[i] == '\0' && buf[i + 1] == '\0' && buf[i + 2] == '\0') + { + ret = buf[i + 3]; + break; + } + } + } + } + return ret; +} + +void +vtysh_exit_ripd_only () +{ + vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIP], "exit", stdout); +} + + +void +vtysh_pager_init () +{ + vtysh_pager_name = getenv ("VTYSH_PAGER"); + if (! vtysh_pager_name) + vtysh_pager_name = "more"; +} + +/* Command execution over the vty interface. */ +void +vtysh_execute_func (char *line, int pager) +{ + int ret, cmd_stat; + vector vline; + struct cmd_element *cmd; + FILE *fp = NULL; + + /* Split readline string up into the vector */ + vline = cmd_make_strvec (line); + + if (vline == NULL) + return; + + ret = cmd_execute_command (vline, vty, &cmd); + + cmd_free_strvec (vline); + + switch (ret) + { + case CMD_WARNING: + if (vty->type == VTY_FILE) + printf ("Warning...\n"); + break; + case CMD_ERR_AMBIGUOUS: + printf ("%% Ambiguous command.\n"); + break; + case CMD_ERR_NO_MATCH: + printf ("%% Unknown command.\n"); + break; + case CMD_ERR_INCOMPLETE: + printf ("%% Command incomplete.\n"); + break; + case CMD_SUCCESS_DAEMON: + { + if (pager && vtysh_pager_name) + { + fp = popen ("more", "w"); + if (fp == NULL) + { + perror ("popen"); + exit (1); + } + } + else + fp = stdout; + + if (! strcmp(cmd->string,"configure terminal")) + { + cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_ZEBRA], + line, fp); + if (cmd_stat != CMD_WARNING) + cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIP], + line, fp); + if (cmd_stat != CMD_WARNING) + cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIPNG], line, fp); + if (cmd_stat != CMD_WARNING) + cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF], + line, fp); + if (cmd_stat != CMD_WARNING) + cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF6], line, fp); + if (cmd_stat != CMD_WARNING) + cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_BGP], + line, fp); + if (cmd_stat) + { + line = "end"; + vline = cmd_make_strvec (line); + + if (vline == NULL) + { + if (pager && vtysh_pager_name && fp) + { + if (pclose (fp) == -1) + { + perror ("pclose"); + exit (1); + } + fp = NULL; + } + return; + } + + ret = cmd_execute_command (vline, vty, &cmd); + cmd_free_strvec (vline); + if (ret != CMD_SUCCESS_DAEMON) + break; + } + else + if (cmd->func) + { + (*cmd->func) (cmd, vty, 0, NULL); + break; + } + } + + if (cmd->daemon & VTYSH_ZEBRA) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_ZEBRA], line, fp) + != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_RIPD) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIP], line, fp) + != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_RIPNGD) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIPNG], line, fp) + != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_OSPFD) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF], line, fp) + != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_OSPF6D) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF6], line, fp) + != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_BGPD) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_BGP], line, fp) + != CMD_SUCCESS) + break; + if (cmd->func) + (*cmd->func) (cmd, vty, 0, NULL); + } + } + if (pager && vtysh_pager_name && fp) + { + if (pclose (fp) == -1) + { + perror ("pclose"); + exit (1); + } + fp = NULL; + } +} + +void +vtysh_execute_no_pager (char *line) +{ + vtysh_execute_func (line, 0); +} + +void +vtysh_execute (char *line) +{ + vtysh_execute_func (line, 1); +} + +/* Configration make from file. */ +int +vtysh_config_from_file (struct vty *vty, FILE *fp) +{ + int ret; + vector vline; + struct cmd_element *cmd; + + while (fgets (vty->buf, VTY_BUFSIZ, fp)) + { + if (vty->buf[0] == '!' || vty->buf[1] == '#') + continue; + + vline = cmd_make_strvec (vty->buf); + + /* In case of comment line */ + if (vline == NULL) + continue; + + /* Execute configuration command : this is strict match */ + ret = cmd_execute_command_strict (vline, vty, &cmd); + + /* Try again with setting node to CONFIG_NODE */ + if (ret != CMD_SUCCESS + && ret != CMD_SUCCESS_DAEMON + && ret != CMD_WARNING) + { + if (vty->node == KEYCHAIN_KEY_NODE) + { + vty->node = KEYCHAIN_NODE; + vtysh_exit_ripd_only (); + ret = cmd_execute_command_strict (vline, vty, &cmd); + + if (ret != CMD_SUCCESS + && ret != CMD_SUCCESS_DAEMON + && ret != CMD_WARNING) + { + vtysh_exit_ripd_only (); + vty->node = CONFIG_NODE; + ret = cmd_execute_command_strict (vline, vty, &cmd); + } + } + else + { + vtysh_execute ("end"); + vtysh_execute ("configure terminal"); + vty->node = CONFIG_NODE; + ret = cmd_execute_command_strict (vline, vty, &cmd); + } + } + + cmd_free_strvec (vline); + + switch (ret) + { + case CMD_WARNING: + if (vty->type == VTY_FILE) + printf ("Warning...\n"); + break; + case CMD_ERR_AMBIGUOUS: + printf ("%% Ambiguous command.\n"); + break; + case CMD_ERR_NO_MATCH: + printf ("%% Unknown command: %s", vty->buf); + break; + case CMD_ERR_INCOMPLETE: + printf ("%% Command incomplete.\n"); + break; + case CMD_SUCCESS_DAEMON: + { + if (cmd->daemon & VTYSH_ZEBRA) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_ZEBRA], + vty->buf, stdout) != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_RIPD) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIP], + vty->buf, stdout) != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_RIPNGD) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIPNG], + vty->buf, stdout) != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_OSPFD) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF], + vty->buf, stdout) != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_OSPF6D) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF6], + vty->buf, stdout) != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_BGPD) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_BGP], + vty->buf, stdout) != CMD_SUCCESS) + break; + if (cmd->func) + (*cmd->func) (cmd, vty, 0, NULL); + } + } + } + return CMD_SUCCESS; +} + +/* We don't care about the point of the cursor when '?' is typed. */ +int +vtysh_rl_describe () +{ + int ret; + int i; + vector vline; + vector describe; + int width; + struct desc *desc; + + vline = cmd_make_strvec (rl_line_buffer); + + /* In case of '> ?'. */ + if (vline == NULL) + { + vline = vector_init (1); + vector_set (vline, '\0'); + } + else + if (rl_end && isspace ((int) rl_line_buffer[rl_end - 1])) + vector_set (vline, '\0'); + + describe = cmd_describe_command (vline, vty, &ret); + + printf ("\n"); + + /* Ambiguous and no match error. */ + switch (ret) + { + case CMD_ERR_AMBIGUOUS: + cmd_free_strvec (vline); + printf ("%% Ambiguous command.\n"); + rl_on_new_line (); + return 0; + break; + case CMD_ERR_NO_MATCH: + cmd_free_strvec (vline); + printf ("%% There is no matched command.\n"); + rl_on_new_line (); + return 0; + break; + } + + /* Get width of command string. */ + width = 0; + for (i = 0; i < vector_max (describe); i++) + if ((desc = vector_slot (describe, i)) != NULL) + { + int len; + + if (desc->cmd[0] == '\0') + continue; + + len = strlen (desc->cmd); + if (desc->cmd[0] == '.') + len--; + + if (width < len) + width = len; + } + + for (i = 0; i < vector_max (describe); i++) + if ((desc = vector_slot (describe, i)) != NULL) + { + if (desc->cmd[0] == '\0') + continue; + + if (! desc->str) + printf (" %-s\n", + desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd); + else + printf (" %-*s %s\n", + width, + desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, + desc->str); + } + + cmd_free_strvec (vline); + vector_free (describe); + + rl_on_new_line(); + + return 0; +} + +/* result of cmd_complete_command() call will be stored here + and used in new_completion() in order to put the space in + correct places only */ +int complete_status; + +char * +command_generator (char *text, int state) +{ + vector vline; + static char **matched = NULL; + static int index = 0; + + /* First call. */ + if (! state) + { + index = 0; + + if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) + return NULL; + + vline = cmd_make_strvec (rl_line_buffer); + if (vline == NULL) + return NULL; + + if (rl_end && isspace ((int) rl_line_buffer[rl_end - 1])) + vector_set (vline, '\0'); + + matched = cmd_complete_command (vline, vty, &complete_status); + } + + if (matched && matched[index]) + return matched[index++]; + + return NULL; +} + +char ** +new_completion (char *text, int start, int end) +{ + char **matches; + + matches = completion_matches (text, command_generator); + + if (matches) + { + rl_point = rl_end; + if (complete_status == CMD_COMPLETE_FULL_MATCH) + rl_pending_input = ' '; + } + + return matches; +} + +char ** +vtysh_completion (char *text, int start, int end) +{ + int ret; + vector vline; + char **matched = NULL; + + if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) + return NULL; + + vline = cmd_make_strvec (rl_line_buffer); + if (vline == NULL) + return NULL; + + /* In case of 'help \t'. */ + if (rl_end && isspace ((int) rl_line_buffer[rl_end - 1])) + vector_set (vline, '\0'); + + matched = cmd_complete_command (vline, vty, &ret); + + cmd_free_strvec (vline); + + return (char **) matched; +} + +/* BGP node structure. */ +struct cmd_node bgp_node = +{ + BGP_NODE, + "%s(config-router)# ", +}; + +/* BGP node structure. */ +struct cmd_node rip_node = +{ + RIP_NODE, + "%s(config-router)# ", +}; + +struct cmd_node interface_node = +{ + INTERFACE_NODE, + "%s(config-if)# ", +}; + +DEFUNSH (VTYSH_BGPD, + router_bgp, + router_bgp_cmd, + "router bgp <1-65535>", + ROUTER_STR + BGP_STR + AS_STR) +{ + vty->node = BGP_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_BGPD, + address_family_vpnv4, + address_family_vpnv4_cmd, + "address-family vpnv4", + "Enter Address Family command mode\n" + "Address family\n") +{ + vty->node = BGP_VPNV4_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_BGPD, + address_family_vpnv4_unicast, + address_family_vpnv4_unicast_cmd, + "address-family vpnv4 unicast", + "Enter Address Family command mode\n" + "Address family\n" + "Address Family Modifier\n") +{ + vty->node = BGP_VPNV4_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_BGPD, + address_family_ipv4_unicast, + address_family_ipv4_unicast_cmd, + "address-family ipv4 unicast", + "Enter Address Family command mode\n" + "Address family\n" + "Address Family Modifier\n") +{ + vty->node = BGP_IPV4_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_BGPD, + address_family_ipv4_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") + +/* Execute command in child process. */ +int +execute_command (char *command, int argc, char *arg1, char *arg2) +{ + int ret; + pid_t pid; + int status; + + /* Call fork(). */ + pid = fork (); + + if (pid < 0) + { + /* Failure of fork(). */ + fprintf (stderr, "Can't fork: %s\n", strerror (errno)); + exit (1); + } + else if (pid == 0) + { + /* This is child process. */ + switch (argc) + { + case 0: + ret = execlp (command, command, NULL); + break; + case 1: + ret = execlp (command, command, arg1, NULL); + break; + case 2: + ret = execlp (command, command, arg1, arg2, NULL); + break; + } + + /* When execlp suceed, this part is not executed. */ + fprintf (stderr, "Can't execute %s: %s\n", command, strerror (errno)); + exit (1); + } + else + { + /* This is parent. */ + execute_flag = 1; + ret = wait4 (pid, &status, 0, NULL); + execute_flag = 0; + } + return 0; +} + +DEFUN (vtysh_ping, + vtysh_ping_cmd, + "ping WORD", + "send echo messages\n" + "Ping destination address or hostname\n") +{ + execute_command ("ping", 1, argv[0], NULL); + return CMD_SUCCESS; +} + +DEFUN (vtysh_traceroute, + vtysh_traceroute_cmd, + "traceroute WORD", + "Trace route to destination\n" + "Trace route to destination address or hostname\n") +{ + execute_command ("traceroute", 1, argv[0], NULL); + return CMD_SUCCESS; +} + +DEFUN (vtysh_telnet, + vtysh_telnet_cmd, + "telnet WORD", + "Open a telnet connection\n" + "IP address or hostname of a remote system\n") +{ + execute_command ("telnet", 1, argv[0], NULL); + return CMD_SUCCESS; +} + +DEFUN (vtysh_telnet_port, + vtysh_telnet_port_cmd, + "telnet WORD PORT", + "Open a telnet connection\n" + "IP address or hostname of a remote system\n" + "TCP Port number\n") +{ + execute_command ("telnet", 2, argv[0], argv[1]); + return CMD_SUCCESS; +} + +DEFUN (vtysh_start_shell, + vtysh_start_shell_cmd, + "start-shell", + "Start UNIX shell\n") +{ + execute_command ("sh", 0, NULL, NULL); + return CMD_SUCCESS; +} + +DEFUN (vtysh_start_bash, + vtysh_start_bash_cmd, + "start-shell bash", + "Start UNIX shell\n" + "Start bash\n") +{ + execute_command ("bash", 0, NULL, NULL); + return CMD_SUCCESS; +} + +DEFUN (vtysh_start_zsh, + vtysh_start_zsh_cmd, + "start-shell zsh", + "Start UNIX shell\n" + "Start Z shell\n") +{ + execute_command ("zsh", 0, NULL, NULL); + return CMD_SUCCESS; +} + +/* Route map node structure. */ +struct cmd_node rmap_node = +{ + RMAP_NODE, + "%s(config-route-map)# " +}; + +/* Zebra node structure. */ +struct cmd_node zebra_node = +{ + ZEBRA_NODE, + "%s(config-router)# " +}; + +struct cmd_node bgp_vpnv4_node = +{ + BGP_VPNV4_NODE, + "%s(config-router-af)# " +}; + +struct cmd_node bgp_ipv4_node = +{ + BGP_IPV4_NODE, + "%s(config-router-af)# " +}; + +struct cmd_node bgp_ipv4m_node = +{ + BGP_IPV4M_NODE, + "%s(config-router-af)# " +}; + +struct cmd_node bgp_ipv6_node = +{ + BGP_IPV6_NODE, + "%s(config-router-af)# " +}; + +struct cmd_node ospf_node = +{ + OSPF_NODE, + "%s(config-router)# " +}; + +/* RIPng node structure. */ +struct cmd_node ripng_node = +{ + RIPNG_NODE, + "%s(config-router)# " +}; + +/* OSPF6 node structure. */ +struct cmd_node ospf6_node = +{ + OSPF6_NODE, + "%s(config-ospf6)# " +}; + +struct cmd_node keychain_node = +{ + KEYCHAIN_NODE, + "%s(config-keychain)# " +}; + +struct cmd_node keychain_key_node = +{ + KEYCHAIN_KEY_NODE, + "%s(config-keychain-key)# " +}; + +void +vtysh_install_default (enum node_type node) +{ + install_element (node, &config_list_cmd); +} + +/* Making connection to protocol daemon. */ +int +vtysh_connect (struct vtysh_client *vclient, char *path) +{ + int ret; + int sock, len; + struct sockaddr_un addr; + struct stat s_stat; + uid_t euid; + gid_t egid; + + memset (vclient, 0, sizeof (struct vtysh_client)); + vclient->fd = -1; + + /* Stat socket to see if we have permission to access it. */ + euid = geteuid(); + egid = getegid(); + ret = stat (path, &s_stat); + if (ret < 0 && errno != ENOENT) + { + fprintf (stderr, "vtysh_connect(%s): stat = %s\n", + path, strerror(errno)); + exit(1); + } + + if (ret >= 0) + { + if (! S_ISSOCK(s_stat.st_mode)) + { + fprintf (stderr, "vtysh_connect(%s): Not a socket\n", + path); + exit (1); + } + + if (euid != s_stat.st_uid + || !(s_stat.st_mode & S_IWUSR) + || !(s_stat.st_mode & S_IRUSR)) + { + fprintf (stderr, "vtysh_connect(%s): No permission to access socket\n", + path); + exit (1); + } + } + + sock = socket (AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + { +#ifdef DEBUG + fprintf(stderr, "vtysh_connect(%s): socket = %s\n", path, strerror(errno)); +#endif /* DEBUG */ + return -1; + } + + memset (&addr, 0, sizeof (struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy (addr.sun_path, path, strlen (path)); +#ifdef HAVE_SUN_LEN + len = addr.sun_len = SUN_LEN(&addr); +#else + len = sizeof (addr.sun_family) + strlen (addr.sun_path); +#endif /* HAVE_SUN_LEN */ + + ret = connect (sock, (struct sockaddr *) &addr, len); + if (ret < 0) + { +#ifdef DEBUG + fprintf(stderr, "vtysh_connect(%s): connect = %s\n", path, strerror(errno)); +#endif /* DEBUG */ + close (sock); + return -1; + } + vclient->fd = sock; + + return 0; +} + +void +vtysh_connect_all() +{ + /* Clear each daemons client structure. */ + vtysh_connect (&vtysh_client[VTYSH_INDEX_ZEBRA], ZEBRA_PATH); + vtysh_connect (&vtysh_client[VTYSH_INDEX_RIP], RIP_PATH); + vtysh_connect (&vtysh_client[VTYSH_INDEX_RIPNG], RIPNG_PATH); + vtysh_connect (&vtysh_client[VTYSH_INDEX_OSPF], OSPF_PATH); + vtysh_connect (&vtysh_client[VTYSH_INDEX_OSPF6], OSPF6_PATH); + vtysh_connect (&vtysh_client[VTYSH_INDEX_BGP], BGP_PATH); +} + + +/* To disable readline's filename completion */ +int +vtysh_completion_entry_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 index 00000000..29d68087 --- /dev/null +++ b/vtysh/vtysh.conf.sample @@ -0,0 +1,4 @@ +! +! vtysh sample configuratin file +! +!username kunihiro nopassword diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h new file mode 100644 index 00000000..193f46ea --- /dev/null +++ b/vtysh/vtysh.h @@ -0,0 +1,83 @@ +/* Virtual terminal interface shell. + * Copyright (C) 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef VTYSH_H +#define VTYSH_H + +#define VTYSH_ZEBRA 0x01 +#define VTYSH_RIPD 0x02 +#define VTYSH_RIPNGD 0x04 +#define VTYSH_OSPFD 0x08 +#define VTYSH_OSPF6D 0x10 +#define VTYSH_BGPD 0x20 +#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD +#define VTYSH_RMAP VTYSH_RIPD|VTYSH_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 index 00000000..f71a79a0 --- /dev/null +++ b/vtysh/vtysh_cmd.c @@ -0,0 +1,14710 @@ +#include +#include "command.h" +#include "vtysh.h" + +DEFSH (VTYSH_BGPD, neighbor_version_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X) " "version (4|4-)", + "Specify neighbor router\n" + "Neighbor address\nIPv6 address\n" + "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 /, 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 /, 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 /, 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 /, 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 /, 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 /, 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 /\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 /, 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 /, 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 /, 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 /, 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 /, 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 /, 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 /\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 /\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 /, 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 /, 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 /, e.g., 35.0.0.0/8\n") + +DEFSH (VTYSH_BGPD, no_bgp_router_id_cmd_vtysh, + "no bgp router-id", + "Negate a command or set its defaults\n" + "BGP information\n" + "Override configured router identifier\n") + +DEFSH (VTYSH_BGPD, dump_bgp_all_interval_cmd_vtysh, + "dump bgp all PATH INTERVAL", + "Dump packet\n" + "BGP packet dump\n" + "Dump all BGP packets\n" + "Output filename\n" + "Interval of output\n") + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_filter_list_cmd_vtysh, + "show ipv6 mbgp filter-list WORD", + "Show running system information\n" + "IPv6 information\n" + "MBGP information\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") + +DEFSH (VTYSH_BGPD, dump_bgp_updates_cmd_vtysh, + "dump bgp updates PATH", + "Dump packet\n" + "BGP packet dump\n" + "Dump BGP updates only\n" + "Output filename\n") + +DEFSH (VTYSH_BGPD, no_bgp_network_backdoor_cmd_vtysh, + "no network A.B.C.D/M backdoor", + "Negate a command or set its defaults\n" + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify a BGP backdoor route\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_in_cmd_vtysh, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, clear_bgp_peer_soft_in_cmd_vtysh, + "clear bgp (A.B.C.D|X:X::X:X) soft in", + "Reset functions\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_OSPF6D, redistribute_ospf6_cmd_vtysh, + "redistribute ospf6", + "Redistribute control\n" + "OSPF6 route\n") + +DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_seq_ge_le_cmd_vtysh, + "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", + "Negate a command or set its defaults\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_dead_interval_cmd_vtysh, + "no ip ospf dead-interval", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n") + +DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_le_cmd_vtysh, + "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>", + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_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 /, 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 /, 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 /, 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 /, 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 /, 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 /, 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 /, 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 /, 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 /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_retransmit_interval_cmd_vtysh, + "no ip ospf retransmit-interval", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_community2_cmd_vtysh, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "IPv6 information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_BGPD, aggregate_address_mask_as_set_summary_cmd_vtysh, + "aggregate-address A.B.C.D A.B.C.D as-set summary-only", + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n" + "Generate AS set path information\n" + "Filter more specific routes from updates\n") + +DEFSH (VTYSH_BGPD, no_aggregate_address_mask_cmd_vtysh, + "no aggregate-address A.B.C.D A.B.C.D", + "Negate a command or set its defaults\n" + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_prefix_longer_cmd_vtysh, + "show ip bgp A.B.C.D/M longer-prefixes", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") + +DEFSH (VTYSH_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 /, 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 /, 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 /, 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 /, 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 /\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 /, 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 /, 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 /\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 /, 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 /, 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 /, 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 /, 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 /, 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 /, 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 /, 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 /, 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 /\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 /, 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 /, 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 /, 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 /, 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 /, 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 /\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 /, 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 /, 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 /, 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 /, 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 /, 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 /, 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 /\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 /, 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 /, 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 /, 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 /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_prefix_cmd_vtysh, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D/M", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "IP prefix /, e.g., 35.0.0.0/8\n") + +DEFSH (VTYSH_BGPD, bgp_network_route_map_cmd_vtysh, + "network A.B.C.D/M route-map WORD", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_community_list_cmd_vtysh, + "show ip bgp community-list 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 /, 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 /, 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 /\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_prefix_cmd_vtysh, + "show ipv6 bgp X:X::X:X/M", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "IPv6 prefix /, e.g., 3ffe::/16\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_out_cmd_vtysh, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_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 /, 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 /, 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 /, 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 /, 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 /\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 /, 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 /, e.g., 35.0.0.0/8\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_summary_cmd_vtysh, + "show ip bgp summary", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Summary of BGP neighbor status\n") + +DEFSH (VTYSH_BGPD, no_vpnv4_network_cmd_vtysh, + "no network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", + "Negate a command or set its defaults\n" + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify Route Distinguisher\n" + "VPN Route Distinguisher\n" + "BGP tag\n" + "tag value\n") + +DEFSH (VTYSH_BGPD, bgp_network_backdoor_cmd_vtysh, + "network A.B.C.D/M backdoor", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify a BGP backdoor route\n") + +DEFSH (VTYSH_BGPD, no_neighbor_send_community_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Send Community attribute to this neighbor\n") + +DEFSH (VTYSH_ZEBRA, debug_zebra_packet_detail_cmd_vtysh, + "debug zebra packet (recv|send) detail", + "Debugging functions (see also 'undebug')\n" + "Zebra configuration\n" + "Debug option set for zebra packet\n" + "Debug option set for receive packet\n" + "Debug option set for send packet\n" + "Debug option set detaied information\n") + +DEFSH (VTYSH_OSPFD, 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 /, 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 /, 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 /, 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 /, 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 /, 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 /, 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 index 00000000..b9c9ad6d --- /dev/null +++ b/vtysh/vtysh_config.c @@ -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 + +#include "command.h" +#include "linklist.h" +#include "memory.h" + +#include "vtysh/vtysh.h" + +vector configvec; + +struct config +{ + /* Configuration node name. */ + char *name; + + /* Configuration string line. */ + struct list *line; + + /* Configuration can be nest. */ + struct config *config; + + /* Index of this config. */ + u_int32_t index; +}; + +struct list *config_top; + +int +line_cmp (char *c1, char *c2) +{ + return strcmp (c1, c2); +} + +void +line_del (char *line) +{ + XFREE (MTYPE_VTYSH_CONFIG_LINE, line); +} + +struct config * +config_new () +{ + struct config *config; + config = XCALLOC (MTYPE_VTYSH_CONFIG, sizeof (struct config)); + return config; +} + +int +config_cmp (struct config *c1, struct config *c2) +{ + return strcmp (c1->name, c2->name); +} + +void +config_del (struct config* config) +{ + list_delete (config->line); + if (config->name) + XFREE (MTYPE_VTYSH_CONFIG_LINE, config->name); + XFREE (MTYPE_VTYSH_CONFIG, config); +} + +struct config * +config_get (int index, char *line) +{ + struct config *config; + struct config *config_loop; + struct list *master; + struct listnode *nn; + + config = config_loop = NULL; + + master = vector_lookup_ensure (configvec, index); + + if (! master) + { + master = list_new (); + master->del = (void (*) (void *))config_del; + master->cmp = (int (*)(void *, void *)) config_cmp; + vector_set_index (configvec, index, master); + } + + LIST_LOOP (master, config_loop, nn) + { + if (strcmp (config_loop->name, line) == 0) + config = config_loop; + } + + if (! config) + { + config = config_new (); + config->line = list_new (); + config->line->del = (void (*) (void *))line_del; + config->line->cmp = (int (*)(void *, void *)) line_cmp; + config->name = XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line); + config->index = index; + listnode_add (master, config); + } + return config; +} + +void +config_add_line (struct list *config, char *line) +{ + listnode_add (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line)); +} + +void +config_add_line_uniq (struct list *config, char *line) +{ + struct listnode *nn; + char *pnt; + + LIST_LOOP (config, pnt, nn) + { + if (strcmp (pnt, line) == 0) + return; + } + listnode_add_sort (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line)); +} + +void +vtysh_config_parse_line (char *line) +{ + char c; + static struct config *config = NULL; + + if (! line) + return; + + c = line[0]; + + if (c == '\0') + return; + + /* printf ("[%s]\n", line); */ + + switch (c) + { + case '!': + case '#': + break; + case ' ': + /* Store line to current configuration. */ + if (config) + { + if (strncmp (line, " address-family vpnv4", strlen (" address-family vpnv4")) == 0) + config = config_get (BGP_VPNV4_NODE, line); + else if (strncmp (line, " address-family ipv4 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 index 00000000..f30aba43 --- /dev/null +++ b/vtysh/vtysh_main.c @@ -0,0 +1,288 @@ +/* Virtual terminal interface shell. + * Copyright (C) 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "version.h" +#include "getopt.h" +#include "command.h" + +#include "vtysh/vtysh.h" +#include "vtysh/vtysh_user.h" + +/* VTY shell program name. */ +char *progname; + +/* Configuration file name. Usually this is configurable, but vtysh + has static configuration file only. */ +char *config_file = NULL; + +/* Configuration file and directory. */ +char *config_current = NULL; +char config_default[] = SYSCONFDIR VTYSH_DEFAULT_CONFIG; + +/* Integrated configuration file. */ +char *integrate_file = NULL; +char *integrate_current = NULL; +#if 0 +char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG; +#endif + +/* Flag for indicate executing child command. */ +int execute_flag = 0; + +/* For sigsetjmp() & siglongjmp(). */ +static sigjmp_buf jmpbuf; + +/* Flag for avoid recursive siglongjmp() call. */ +static int jmpflag = 0; + +/* A static variable for holding the line. */ +static char *line_read; + +/* Master of threads. */ +struct thread_master *master; + +/* SIGTSTP handler. This function care user's ^Z input. */ +void +sigtstp (int sig) +{ + /* Execute "end" command. */ + vtysh_execute ("end"); + + /* Initialize readline. */ + rl_initialize (); + printf ("\n"); + + /* Check jmpflag for duplicate siglongjmp(). */ + if (! jmpflag) + return; + + jmpflag = 0; + + /* Back to main command loop. */ + siglongjmp (jmpbuf, 1); +} + +/* SIGINT handler. This function care user's ^Z input. */ +void +sigint (int sig) +{ + /* Check this process is not child process. */ + if (! execute_flag) + { + rl_initialize (); + printf ("\n"); + rl_forced_update_display (); + } +} + +/* Signale wrapper. */ +RETSIGTYPE * +signal_set (int signo, void (*func)(int)) +{ + int ret; + struct sigaction sig; + struct sigaction osig; + + sig.sa_handler = func; + sigemptyset (&sig.sa_mask); + sig.sa_flags = 0; +#ifdef SA_RESTART + sig.sa_flags |= SA_RESTART; +#endif /* SA_RESTART */ + + ret = sigaction (signo, &sig, &osig); + + if (ret < 0) + return (SIG_ERR); + else + return (osig.sa_handler); +} + +/* Initialization of signal handles. */ +void +signal_init () +{ + signal_set (SIGINT, sigint); + signal_set (SIGTSTP, sigtstp); + signal_set (SIGPIPE, SIG_IGN); +} + +/* Help information display. */ +static void +usage (int status) +{ + if (status != 0) + fprintf (stderr, "Try `%s --help' for more information.\n", progname); + else + { + printf ("Usage : %s [OPTION...]\n\n\ +Daemon which manages kernel routing table management and \ +redistribution between different routing protocols.\n\n\ +-b, --boot Execute boot startup configuration\n\ +-e, --eval Execute argument as command\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); + } + exit (status); +} + +/* VTY shell options, we use GNU getopt library. */ +struct option longopts[] = +{ + { "boot", no_argument, NULL, 'b'}, + { "eval", required_argument, NULL, 'e'}, + { "help", no_argument, NULL, 'h'}, + { 0 } +}; + +/* Read a string, and return a pointer to it. Returns NULL on EOF. */ +char * +vtysh_rl_gets () +{ + /* If the buffer has already been allocated, return the memory + to the free pool. */ + if (line_read) + { + free (line_read); + line_read = NULL; + } + + /* Get a line from the user. Change prompt according to node. XXX. */ + line_read = readline (vtysh_prompt ()); + + /* If the line has any text in it, save it on the history. */ + if (line_read && *line_read) + add_history (line_read); + + return (line_read); +} + +/* VTY shell main routine. */ +int +main (int argc, char **argv, char **env) +{ + char *p; + int opt; + int eval_flag = 0; + int boot_flag = 0; + char *eval_line = NULL; + char *integrated_file = NULL; + + /* Preserve name of myself. */ + progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + + /* Option handling. */ + while (1) + { + opt = getopt_long (argc, argv, "be:h", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + case 'b': + boot_flag = 1; + break; + case 'e': + eval_flag = 1; + eval_line = optarg; + break; + case 'h': + usage (0); + break; + case 'i': + integrated_file = strdup (optarg); + default: + usage (1); + break; + } + } + + /* Initialize user input buffer. */ + line_read = NULL; + + /* Signal and others. */ + signal_init (); + + /* Make vty structure and register commands. */ + vtysh_init_vty (); + vtysh_init_cmd (); + vtysh_user_init (); + vtysh_config_init (); + + vty_init_vtysh (); + + sort_node (); + + vtysh_connect_all (); + + /* Read vtysh configuration file. */ + vtysh_read_config (config_file, config_current, config_default); + + /* If eval mode */ + if (eval_flag) + { + vtysh_execute_no_pager (eval_line); + exit (0); + } + + /* Boot startup configuration file. */ + if (boot_flag) + { + vtysh_read_config (integrate_file, integrate_current, integrate_default); + exit (0); + } + + vtysh_pager_init (); + + vtysh_readline_init (); + + vty_hello (vty); + + vtysh_auth (); + + /* Preparation for longjmp() in sigtstp(). */ + sigsetjmp (jmpbuf, 1); + jmpflag = 1; + + /* Main command loop. */ + while (vtysh_rl_gets ()) + vtysh_execute (line_read); + + printf ("\n"); + + /* Rest in peace. */ + exit (0); +} diff --git a/vtysh/vtysh_user.c b/vtysh/vtysh_user.c new file mode 100644 index 00000000..b84da2eb --- /dev/null +++ b/vtysh/vtysh_user.c @@ -0,0 +1,191 @@ +/* User authentication for vtysh. + * Copyright (C) 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include + +#ifdef USE_PAM +#include +#include +#endif /* USE_PAM */ + +#include "memory.h" +#include "linklist.h" +#include "command.h" + +#ifdef USE_PAM +static struct pam_conv conv = +{ + misc_conv, + NULL +}; + +int +vtysh_pam (char *user) +{ + int ret; + pam_handle_t *pamh = NULL; + + /* Start PAM. */ + ret = pam_start("zebra", user, &conv, &pamh); + /* printf ("ret %d\n", ret); */ + + /* Is user really user? */ + if (ret == PAM_SUCCESS) + ret = pam_authenticate (pamh, 0); + /* printf ("ret %d\n", ret); */ + +#if 0 + /* Permitted access? */ + if (ret == PAM_SUCCESS) + ret = pam_acct_mgmt (pamh, 0); + printf ("ret %d\n", ret); + + if (ret == PAM_AUTHINFO_UNAVAIL) + ret = PAM_SUCCESS; +#endif /* 0 */ + + /* This is where we have been authorized or not. */ +#ifdef DEBUG + if (ret == PAM_SUCCESS) + printf("Authenticated\n"); + else + printf("Not Authenticated\n"); +#endif /* DEBUG */ + + /* close Linux-PAM */ + if (pam_end (pamh, ret) != PAM_SUCCESS) + { + pamh = NULL; + fprintf(stderr, "vtysh_pam: failed to release authenticator\n"); + exit(1); + } + + return ret == PAM_SUCCESS ? 0 : 1; +} +#endif /* USE_PAM */ + +struct user +{ + char *name; + u_char nopassword; +}; + +struct list *userlist; + +struct user * +user_new () +{ + struct user *user; + user = XMALLOC (0, sizeof (struct user)); + memset (user, 0, sizeof (struct user)); + return user; +} + +void +user_free (struct user *user) +{ + XFREE (0, user); +} + +struct user * +user_lookup (char *name) +{ + struct listnode *nn; + struct user *user; + + LIST_LOOP (userlist, user, nn) + { + if (strcmp (user->name, name) == 0) + return user; + } + return NULL; +} + +void +user_config_write () +{ + struct listnode *nn; + struct user *user; + + LIST_LOOP (userlist, user, nn) + { + if (user->nopassword) + printf (" username %s nopassword\n", user->name); + } +} + +struct user * +user_get (char *name) +{ + struct user *user; + user = user_lookup (name); + if (user) + return user; + + user = user_new (); + user->name = strdup (name); + listnode_add (userlist, user); + + return user; +} + +DEFUN (username_nopassword, + username_nopassword_cmd, + "username WORD nopassword", + "\n" + "\n" + "\n") +{ + struct user *user; + user = user_get (argv[0]); + user->nopassword = 1; + return CMD_SUCCESS; +} + +int +vtysh_auth () +{ + struct user *user; + struct passwd *passwd; + + passwd = getpwuid (geteuid ()); + + user = user_lookup (passwd->pw_name); + if (user && user->nopassword) + /* Pass through */; + else + { +#ifdef USE_PAM + if (vtysh_pam (passwd->pw_name)) + exit (0); +#endif /* USE_PAM */ + } + return 0; +} + +void +vtysh_user_init () +{ + userlist = list_new (); + install_element (CONFIG_NODE, &username_nopassword_cmd); +} diff --git a/vtysh/vtysh_user.h b/vtysh/vtysh_user.h new file mode 100644 index 00000000..8d0a4cf6 --- /dev/null +++ b/vtysh/vtysh_user.h @@ -0,0 +1,27 @@ +/* User authentication for vtysh. + * Copyright (C) 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _VTYSH_USER_H +#define _VTYSH_USER_H + +int vtysh_auth (); + +#endif /* _VTYSH_USER_H */ diff --git a/zebra/.cvsignore b/zebra/.cvsignore new file mode 100644 index 00000000..95401bfa --- /dev/null +++ b/zebra/.cvsignore @@ -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 index 00000000..b5383f1d --- /dev/null +++ b/zebra/ChangeLog @@ -0,0 +1,1221 @@ +2002-09-28 Akihiro Mizutani + + * zebra_rib.c (static_add_ipv4): Null0 static route is added. + +2002-09-10 Jochen Friedrich + + * rt_netlink.c: Add check for EAGAIN. + * kernel_socket.c: Likewise + +2002-06-12 Israel Keys + + * rt_netlink.c: Setting the NLM_F_ACK flag on the netlink command + message so that we get an ACK for successful netlink commands. + Change the netlink socket to BLOCKING while we wait for a + response; be it an ACK or an NLMSG_ERROR. Change + netlink_parse_info to deal with ACK messages. + +2001-11-01 Jun-ichiro itojun Hagino + + * rtadv.c (rtadv_make_socket): setsockopt(IPV6_CHECKSUM) does not + work for ICMPv6 socket. + +2001-10-24 Kunihiro Ishiguro + + * rib.c (rib_process): Select connected route any case. + +2001-10-23 Kunihiro Ishiguro + + * interface.c (no_ip_address_secondary): Add "no" to command. + +2001-10-18 NOGUCHI Kay + + * ioctl.c (if_prefix_add_ipv6): Set the prefered and valid lifetime + to infinity as the freebsd4.4 workaroud. + +2001-08-26 mihail.balikov@interbgc.com + + * zebra_snmp.c: Fix snmpwalk problem such as IPv4 address + A.B.C.255. + +2001-08-22 NOGUCHI Kay + + * rtadv.c: Do not send RA to loopback interface. + +2001-08-20 Kunihiro Ishiguro + + * ioctl.c (if_set_prefix): Remove Linux 2.0 specific connected + route treatment. + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-17 Kunihiro Ishiguro + + * rib.c: Kernel route is treated as EGP routes in nexthop active + check. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-08-08 "Akihiro Mizutani" + + * rib.c (show_ip_route_prefix_longer): Add longer-prefix option to + show route commands. + +2001-07-29 Yon Uriarte + + * zserv.c (zsend_ipv4_add_multipath): Add + NEXTHOP_TYPE_IPV4_IFINDEX check. + +2001-07-29 NOGUCHI Kay + + * rtadv.c: Apply valid lifetime, preferred lifetime, onilnk flag, + autonomous address-configuration flag patch. + (no_ipv6_nd_suppress_ra): Change "ipv6 nd send-ra" to "no ipv6 nd + suppress-ra". + +2001-07-24 NOGUCHI Kay + + * rtadv.c (ipv6_nd_ra_interval): Add "ipv6 nd ra-interval SECONDS" + command. + +2001-07-24 Jun-ichiro itojun Hagino + + * rt_socket.c (kernel_rtm_ipv4): Add KAME/NetBSD151 equal cost + multicast FIB support both IPv4 and IPv6. + +2001-07-24 Hal Snyder + + * if_ioctl.c (interface_list_ioctl): Fix bug of failing to get the + full list of interfaces on some configurations of OpenBSD. + +2001-07-23 NOGUCHI Kay + + * rtadv.c (ipv6_nd_send_ra): Apply [zebra 9320] to fix "ipv6 nd + send-ra" bug. + (ipv6_nd_ra_lifetime): "ipv6 nd ra-lifetime 0" for default router + availability. + (ipv6_nd_managed_config_flag): "ipv6 nd managed-config-flag" is + added. + (ipv6_nd_other_config_flag): "ipv6 nd other-config-flag" is added. + +2001-07-23 Jun-ichiro itojun Hagino + + * ioctl.c (if_ioctl): Change ioctl argument from int to u_long. + + * rt_ioctl.c: Likewise. + +2001-07-23 Jun-ichiro itojun Hagino + + * kernel_socket.c (rtm_write): Only set RTF_CLONING when the + interface is not p2p. + +2001-04-23 Kunihiro Ishiguro + + * ioctl.c (if_prefix_add_ipv6): Fix argument type. + +2001-04-06 Toshiaki Takada + + * zserv.c (zsend_interface_delete): Use client->obuf instead of + allocating new stream. + +2001-03-10 Kunihiro Ishiguro + + * rt_netlink.c: Revert RTPROT_BOOT change. + +2001-03-08 Kunihiro Ishiguro + + * rt_netlink.c (netlink_route_change): Skip RTPROT_BOOT route. + (netlink_routing_table): Likewise. + +2001-03-07 "Akihiro Mizutani" + + * zserv.c (zsend_ipv4_add_multipath): Send metric value to + protocol daemons. + +2001-02-18 Kunihiro Ishiguro + + * rt_netlink.c (netlink_routing_table): Do not return + tb[RTA_GATEWAY] is NULL. Reported by: "Michael O'Keefe" + . + +2001-02-08 Kunihiro Ishiguro + + * if_ioctl.c (interface_list_ioctl): Call if_add_update(). + Suggested by: Chris Dunlop . + +2001-02-01 Kunihiro Ishiguro + + * rib.c (nexthop_active_ipv4): When nexthop type is + NEXTHOP_TYPE_IPV4_IFINDEX, propery set the ifindex to rifindex. + + * zserv.c: Initialize rtm_table_default with 0. + + * zebra-0.91 is released. + +2001-01-31 Kunihiro Ishiguro + + * kernel_socket.c (rtm_read): Filter cloned route. Suggested by: + Jun-ichiro itojun Hagino + +2001-01-30 Kunihiro Ishiguro + + * connected.c (connected_up_ipv6): When point-to-point destination + address is ::, use local address for connected network. + (connected_down_ipv6): Likewise. + +2001-01-25 Kunihiro Ishiguro + + * zserv.c (zebra_serv): Add missing close() call. Reported by: + David Waitzman . + +2001-01-24 Kunihiro Ishiguro + + * rib.c (rib_lookup_ipv4): New function for checking exact match + IGP route. + +2001-01-23 Kunihiro Ishiguro + + * rib.c (show_ipv6_route_protocol): Fix bug of "show ip route + route-type". + +2001-01-22 Kunihiro Ishiguro + + * interface.c (zebra_interface): Do not call + zebra_interface_add_update for inactive interface. + + * zserv.c (zsend_interface_address_add): Send interface address + flag. + (zsend_interface_address_delete): Likewise. + +2001-01-19 Kunihiro Ishiguro + + * interface.c (if_addr_add): Add flags. + + * connected.c (ifa_add_ipv4): Add new function for interface + address handling. + (ifa_delete_ipv4): Likewise. + +2001-01-16 Kunihiro Ishiguro + + * rib.c (rib_update): Update IPv6 RIB. + + * kernel_socket.c (ifam_read): Call if_refresh() for update + interface flag status. This is for implicit interface up on *BSD. + + * interface.c (if_refresh): Add interface flag refresh function. + + * kernel_socket.c (rtm_read): Fetch link-local address interface + index. + (ifan_read): We need to fetch interface information. Suggested + by: Yasuhiro Ohara . + + * rib.c (static_ipv6_nexthop_same): Add check for + NEXTHOP_TYPE_IPV6_IFNAME. + +2001-01-15 Kunihiro Ishiguro + + * rib.h (NEW_RIB): Turn on NEW_RIB flag. IPv6 new RIB code are + taken into place. + +2001-01-14 Kunihiro Ishiguro + + * rib.c (static_ipv6_write): Display STATIC_IPV6_GATEWAY_IFNAME + configuration. + (rib_delete_ipv6): Handle same route conter for IPv6 connected + route. + (show_ipv6_route_protocol): New command. + (show_ipv6_route_addr): Likewise. + (show_ipv6_route_prefix): Likewise. + (rib_update): Sweep kernel route when it is cleaned up. + + * rt_socket.c (kernel_add_ipv6): Add NEXTHOP_IPV6_IFNAME + treatmenet. + + * rt_netlink.c (kernel_init): Likewise. + + * rt_ioctl.c (kernel_ioctl_ipv6_multipath): Likewise. + + * rib.c (rib_add_ipv4): Cope with same connected route on a + interface. Suggested by: Matthew Grant . + (nexthop_ipv6_ifname_add): Add NEXTHOP_IPV6_IFNAME treatmenet. + + * rib.h (struct new_rib): Add refcnt to keep track on the + reference of same connected route. + + * ioctl.c (if_set_prefix): Add check for GNU_LINUX. + +2001-01-13 Yasuhiro Ohara + + * kernel_socket.c (ifan_read, rtm_type_str): Add RTM_OIFINFO check. + (rtm_type_str): Add RTM_IFANNOUNCE check. + (ifan_read): New function. + (kernel_read): Add case for RTM_IFANNOUNCE. + +2001-01-13 Kunihiro Ishiguro + + * rt_ioctl.c (kernel_ioctl_ipv6_multipath): New function. + + * rt_netlink.c (netlink_route_multipath): IPv6 address ifindex + treatment. + + * connected.c (connected_up_ipv6): Add dest value check. + + * rib.c (nexthop_active_ipv6): Do not touch IPv6 nexthop's + ifindex. + (rib_add_ipv4): Import rib_add_ipv6() same route check code. + (nexthop_active_check): NEXTHOP_TYPE_IPV6_IFINDEX activity is only + checked by ifindex. + + * rt_socket.c (kernel_rtm_ipv6_multipath): New function. + + * redistribute.c (redistribute_add): Use + zsend_ipv6_add_multipath(). + (redistribute_delete_multipath): Use + zsend_ipv6_delete_multipath(). + + * interface.c (ip_address): Check current IP address to avoid + duplicate. + + * rib.c (rib_delete_ipv4): When deleted route is connected route, + check ifindex. + (rib_add_ipv4): When connected route is added do not perform + implicit withdraw. + (rib_delete_ipv4): Check ifindex for connected route. + + * kernel_socket.c (rtm_read): When route has RTF_STATIC, set + ZEBRA_FLAG_STATIC for indicate as persistent route. + (ifam_read): Unset interface index from link-local address when + IPv6 stack is KAME. + + * rib.c (rib_update): Do not delete persistent kernel route. + + * rib.h (struct new_rib): Integrate RIB_FLAG_* to ZEBRA_FLAG_*. + + * rt_socket.c (kernel_add_ipv6_multipath): Add placeholder. + (kernel_delete_ipv6_multipath): Likewise. + + * rt_netlink.c (netlink_talk): Give struct nlsock to netlink_talk. + +2001-01-12 Kunihiro Ishiguro + + * rib.c (rib_update): Revert Matthew Grant's patch + zebra_cvs_newribfix.patch. Use struct rib->ifindex for kernel + interface index. Introduce NEXTHOP_TYPE_IPV4_IFINDEX to support + that. Add support for address deletion situation. + +2001-01-11 Kunihiro Ishiguro + + * interface.c: Remove HAVE_IF_PSEUDO part. + + * rib.h: Likewise. + + * rt_netlink.c (netlink_link_change): Likewise. + +2001-01-10 Kunihiro Ishiguro + + * zserv.c: Remove OLD_RIB codes. + +2001-01-09 Kunihiro Ishiguro + + * zebra-0.90 is released. + +2001-01-09 Matthew Grant + + * interface.c (if_new_intern_ifindex): Allocate a new internal + interface index. + (if_addr_refresh): Fix up ip addresses configured via zebra. + (if_add_update): Handle an interface addition. + (if_delete_update): Handle an interface delete event. + + * rib.c (nexthop_ipv4_add): Add kernel route deletion process when + interface goes down. + +2001-01-08 Kunihiro Ishiguro + + * interface.c (if_dump_vty): When HAVE_NET_RT_IFLIST is defined, + NetBSD also use this function. Suggested by Jasper Wallace + . + +2001-01-07 Kunihiro Ishiguro + + * rib.c (nexthop_active_ipv4): Move back to set methodo to old + one. + +2001-01-05 Kunihiro Ishiguro + + * rib.c (rib_add_ipv4): EBGP multihop set ZEBRA_FLAG_INTERNAL + flag, so treat it. + +2001-01-04 Kunihiro Ishiguro + + * rt_netlink.c (netlink_talk_ipv6): When IPv6 route message is + sent from netlink_cmd, the same message comes from netlink. To + avoid confusion, temporary netlink_talk_ipv6 use netlink.sock + instead of netlink_cmd.sock. + +2001-01-01 Kunihiro Ishiguro + + * zserv.h (ZEBRA_SERV_PATH): Change "/tmp/zebra" to "/tmp/.zebra". + Change "/tmp/zserv" to "/tmp/.zserv". + +2000-12-29 Frank van Maarseveen + + * rt_netlink.c (struct nlsock): Divide kernel message into listen + socket and command socket. + (netlink_talk): Remove socket listen code. Use netlink_parse_info + for read kernel response. + +2000-12-29 Kunihiro Ishiguro + + * rib.c (vty_show_ip_route): Show uptime of the RIP,OSPF,BGP + routes. + +2000-12-27 Kunihiro Ishiguro + + * rt_netlink.c (netlink_route_multipath): Metric value is + reflected to kernel routing table. + + * rt_ioctl.c (kernel_ioctl_ipv4_multipath): Likewise. + + * kernel_socket.c (rtm_write): Likewise. + + * rib.c (nexthop_active_ipv4): Only iBGP route perform recursive + nexthop lookup. + + * rt_ioctl.c (kernel_ioctl_ipv4_multipath): Add ioctl version of + new RIB implementation. + +2000-12-26 Kunihiro Ishiguro + + * rib.h: Remove MULTIPATH_NUM. It is defined by configure script. + +2000-12-25 Michael Rozhavsky + + * rib.c (rib_if_up): Call rib_fib_set instead of RIB_FIB_SET for + proper redistribution. + +2000-12-19 Kunihiro Ishiguro + + * rib.c (nexthop_active_ipv4): Add self lookup nexthop check. + (show_ip_route_protocol): Support new RIB. + + * rt_netlink.c (netlink_route_change): Do not return when gate is + NULL. + +2000-12-18 Kunihiro Ishiguro + + * rib.c (rib_lookup_ipv4_nexthop): IBGP nexthop check function is + updated. + (rib_add_ipv4): Free implicit withdraw route's RIB. + +2000-12-15 Kunihiro Ishiguro + + * rib.c (nexthop_active_ipv4): Check indirect nexthop. + + * redistribute.c (redistribute_add_multipath): Redistribution + works with new rib code. + +2000-12-14 Kunihiro Ishiguro + + * rt_netlink.c (netlink_route_multipath): Check useful nexthop + number. + (netlink_route_multipath): Clear rtnh_flags and rtnh_hops. + + * rib.c (nexthop_active_update): Set flag for the rib's nexthop + activity is changed. + (nexthop_active_check): Before checking interface is up, make it + sure the interface exist. + +2000-11-20 Kunihiro Ishiguro + + * rib.c (ip_route): New RIB prototype. + +2000-11-16 Yon Uriarte + + * zserv.c (zsend_interface_add): Send hardware address when + hw_addr_len is greater than 0. + +2000-11-07 Kunihiro Ishiguro + + * connected.c (connected_up_ipv4): Fix ptop bug. The destination + network should be installed into routing table. + (connected_down_ipv4): Likewise. + (connected_add_ipv4): Change to use connected_up_ipv4. + (connected_delete_ipv4): Likewise. + +2000-11-06 Kunihiro Ishiguro + + * rt_netlink.c (netlink_interface_addr): Revert Harald Welte + 's ptop patch then back to original code to + avoid duplicated connected route problem. Suggested by Frank van + Maarseveen . + + * kernel_socket.c (rtm_read): Make behavior consistent even #ifdef + DEBUG is defined. Reported by Jun-ichiro itojun Hagino + . + +2000-10-23 Jochen Friedrich + + * main.c (main): Call zebra_snmp_init() when it is enabled. + +2000-10-23 Kunihiro Ishiguro + + * zserv.c (zebra_serv_un): UNIX domain socket server of zebra + protocol. + +2000-10-19 Kunihiro Ishiguro + + * rib.c (rib_add_ipv4): Same check bug is fixed. + +2000-10-03 Kunihiro Ishiguro + + * rib.c (rib_if_down): Remove kernel route when the interface goes + down. + + * debug.c: New command "debug zebra kernel" is added. + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 is released. + +2000-09-24 Harald Welte + + * rt_netlink.c (netlink_interface_addr): Fix point-to-point address + treatment in netlink interface. + +2000-09-21 David Lipovkov + + * rib.c (rib_if_down): Pull static route only. Protocol daemon + must withdraw routes when interface goes down. + (rib_add_ipv4): Check nexthop when replace route. + +2000-09-21 Kunihiro Ishiguro + + * if_ioctl.c (if_getaddrs): New function for looking up + interface's address by getifaddrs(). + +2000-09-10 Kunihiro Ishiguro + + * connected.c (connected_delete_ipv4): Add check for connected + address is found or not. + (connected_add_ipv6): Reflect IPv6 connected address change to + protocol daemons. + (connected_delete_ipv6): Likewise. + +2000-09-07 David Lipovkov + + * rib.c (rib_delete_ipv4): Reverted the change from pseudo + interface patch to original. Because ospfd deletes routes using + zero ifindex. + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 is released. + +2000-08-15 "Akihiro Mizutani" + + * rib.c (show_ip_route_protocol): Help string correction. + (show_ip_route_prefix): Check prefix mask. + (show_ip_route_vty_detail): Display distance and metric. + +2000-08-14 Kunihiro Ishiguro + + * zserv.c (zsend_interface_add): Change ifindex store size from + two octet to four. + (zsend_interface_delete): Likewise. + (zsend_interface_address_add): Likewise. + (zsend_interface_address_delete): Likewise. + (zsend_interface_up): Likewise. + (zsend_interface_down): Likewise. + +2000-08-13 Kunihiro Ishiguro + + * rib.c (rib_add_ipv4): Do not install distance 255 route. + +2000-08-10 Toshiaki Takada + + * interface.c (bandwidth_if), (no_bandwidth_if): Call + zebra_interface_up_update () instead of using if_up() and if_down(). + +2000-08-07 "Akihiro Mizutani" + + * interface.c (bandwidth_if): Fix help string. + +2000-08-07 Matthew Grant + + * interface.c (if_dump_vty): Display bandwidth value. + (bandwidth_if): New command "bandwidth <1-10000000>" is added. + When interface is up, force protocol daemons to recalculate routes + due to cost change. + (no_bandwidth_if): Likewise. + (if_config_write): Output bandwidth configuration. + + * zserv.c (zsend_interface_add): Send bandwidth value. + (zsend_interface_up): Likewise. + (zsend_interface_down): Likewise. + + +2000-08-07 Michael Rozhavsky + + * rib.c (show_ip_route_protocol): "show ip route + (bgp|connected|kernel|ospf|rip|static)" is added. + +2000-08-07 Kunihiro Ishiguro + + * rib.c (rib_lookup_ipv4_nexthop): Check parent node until IGP + nexthop is found. + (rib_add_ipv4_internal): Set fib ifindex to rib ifindex. + +2000-08-06 Kunihiro Ishiguro + + * redistribute.c (redistribute_delete): Fix bug of default route + redistribute treatment. + +2000-08-05 Kunihiro Ishiguro + + * rib.c (rib_init): Install ip_node in rib.c instead of zserv.c. + Change default distance value. + + Old New + ------------------------------------------ + system 10 0 + kernel 20 0 + connected 30 0 + static 40 1 + rip 50 120 + ripng 50 120 + ospf 60 110 + ospf6 49 110 + bgp 70 200(iBGP) 20(eBGP) + ------------------------------------------ + + * zserv.c (client_lookup): Function removed. + (zsend_interface_add): Use client's output buffer. Check ifinfo + flag. + (zsend_interface_delete): Likewise. + Delete ipv4_static_radix and ipv6_static_radix. + +2000-08-02 Kunihiro Ishiguro + + * zserv.h (struct zebra_client): When client request interface + information, ifinfo is set. + + * rib.c: Temporary Revert changes for pseudo interface. + + * rib.h: Likewise. + + * zserv.c: Likewise. + + * interface.c: Likewise. + +2000-08-02 David Lipovkov + + * interface.c (zebra_if_init): Install interface "pseudo" + commands. + + * rib.c (rib_create): ifname argument is added. + (rib_add_ipv4_pseudo): New function is added. + (rib_delete_ipv4_pseudo): Likewise. + + * rib.h : Delete INTERFACE_UNKNOWN definition. Add prototype for + pseudo interface functions. + + * rt_netlink.c (netlink_link_change): Check for pseudo interface. + + * zserv.c (ip_route): When destination is pseudo interface, call + rib_add_ipv4_pseudo(). + + * zserv.c (no_ip_route): Trim "unknown" argument. + +2000-07-26 kunitake@dti.ad.jp + + * if_ioctl.c (if_get_hwaddr): Fix hardware address length from 8 + to 6. + + * rtadv.c (rtadv_send_packet): Fix shift bug for hardware address. + +2000-07-24 Akihiro Mizutani + + * interface.c: Use install_default() for common VTY commands. + +2000-07-23 Kunihiro Ishiguro + + * if_ioctl.c (interface_list_ioctl): A interface list size is + calculated from ifreq->if_addr.sa_len. This is for OpenBSD. + + * ioctl.c (if_get_mtu): Remove codes for SIOCGIFDATA. + +2000-07-09 Chris Dunlop + + * if_ioctl.c (if_get_index): Add check for HAVE_BROKEN_ALIASES. + +2000-07-04 Kunihiro Ishiguro + + * zserv.c (zebra_client_read): Add ZEBRA_REDISTRIBUTE_{ADD,DELETE} + message handling. + +2000-07-02 David Lipovkov + + * zserv.c: "ip route A.B.C.D/M unknown" command is added. + +2000-06-28 Michael Rozhavsky + + * rib.c: Remove old kernel route when new route comes in. + +2000-06-13 David Lipovkov + + * rib.c (rib_if_up): Add check for unknown interface. + +2000-06-13 Kunihiro Ishiguro + + * rib.h: Define INTERFACE_UNKNOWN. + +2000-06-08 Kunihiro Ishiguro + + * Makefile.am (EXTRA_DIST): Move irdp.c until implementation is + finished. + +2000-06-05 David Lipovkov + + * interface.c (if_zebra_delete_hook): Call rib_if_delete(). + + * redistribute.c (zebra_interface_delete_update): New function. + + * redistribute.h (zebra_interface_delete_update): New function + prototype. + + * rib.c (rib_if_delete): New function. Walk down all routes and + delete all on the interface. + + * rib.h: New function prototype. + + * rt_netlink.c (netlink_link_change): Call + zebra_interface_delete_update (). + +2000-05-10 Kunihiro Ishiguro + + * if_ioctl.c (interface_info_ioctl): Check interface's flag before + checking interface's address. + +2000-04-26 Jochen Friedrich + + * GNOME-PRODUCT-ZEBRA-MIB: New file. + + * GNOME-SMI: New file. + +2000-04-23 Kunihiro Ishiguro + + * irdp.c: New file from 1997 development code. + * irdp.h: Likewise. + +2000-04-19 Kunihiro Ishiguro + + * rtadv.c (rtadv_send_packet): Enclose router advertisement + logging with IS_ZEBRA_DEBUG_PACKET. + +2000-04-17 Kunihiro Ishiguro + + * zserv.c (zebra_client_close): Remove client structure from + client_list when connection is terminated. + +2000-03-21 David Lipovkov + + * connected.c (connected_add_ipv4): Allows all necessary structure + updates for connected route, but doesn't insert it into rib if + it's interface is down. + +2000-01-21 Hideto Yamakawa + + * rtread_getmsg.c: Set some definition for Solaris 2.5 and Solaris + 2.5.1. + +2000-01-21 Kunihiro Ishiguro + + * rib.c (no_ipv6_route_ifname): Fix buf of cheking return value + from str2prefix_ipv6(). + +2000-01-14 Kunihiro Ishiguro + + * rt_socket.c: Revert to use RTF_HOST for IPv4 with /32 route and + IPv6 with /128 routes. + (kernel_rtm_ipv4): In case of /32 route's gateway is interface. It + should have mask for cloning. + +1999-12-26 Jochen.Friedrich@genorz.de + + * interface.c (if_dump_vty): Fix a bug of missing VTY_NEWLINE. + +1999-12-23 Alex Zinin + * interface.*: dynamic int up/down support + +1999-12-09 Kunihiro Ishiguro + + * ipforward_proc.c (dropline): Move dropline() from lib/dropline.c + + * rtread_proc.c (proc_route_read): Don't use dropline(). + +1999-12-08 Kunihiro Ishiguro + + * kernel_socket.c (rtm_read): When message is RTM_GET, it has own + process's pid. + +1999-12-04 Kunihiro Ishiguro + + * main.c (main): Change to default log output to ZLOG_STDOUT. + + * zserv.c (zebra_serv): More detailed error print. + +1999-11-30 Kunihiro Ishiguro + + * kernel_socket.c (rtm_read): Check old pid for static route + insertion check. + +1999-11-30 Kunihiro Ishiguro + + * interface.c (if_dump_vty): BSDI/OS uses 64bit for interface + statistics counter. + + * mtu_kvm.c: New file added. + +1999-11-27 Vladimir B. Grebenschikov + + * kernel_socket.c (rtm_write): Set RTF_CLONING flag for + route to the directly connected interface. + +1999-11-27 Kunihiro Ishiguro + + * rt_socket.c: Delete USE_HOST_BIT definition. + +1999-11-21 Michael Handler + + * rtread_getmsg.c: Undef some definition to resolve conflict. + +1999-11-27 Kunihiro Ishiguro + + * kernel_socket.c (rtm_write): Change to use pre stored struct_dl + value for gateway specification. + +1999-11-25 Kunihiro Ishiguro + + * rt_socket.c (kernel_rtm_ipv4): Even mask is 32 under IPv4 or + 128 under IPv6, don't use RTF_HOST. + +1999-11-21 Kunihiro Ishiguro + + * Makefile.am (EXTRA_DIST): Add rtread_getmsg.c. + +1999-11-21 Michael Handler + + * rtread_getmsg.c: Added for Solaris 2.6 support. + +1999-11-18 Kunihiro Ishiguro + + * rtread_sysctl.c (rtm_read_route): RTM_DELETE handling added. + + * rt_socket.c (kernel_read): Better BSD routing socket support. + +1999-10-19 Kunihiro Ishiguro + + * client_main.c: Disable making obsolete zebra test `client' + command. + +1999-10-18 Kunihiro Ishiguro + + * zebra.c: Renamed to zserv.c. + + * zebra.h: Global definitions are moved to lib/zebra.h. Then + renamed to zserv.h. + +1999-10-15 Jordan Mendelson + + * if_ioctl.c: Add Linux 2.2.X's alias support and dynamic + interface. Remove ugly MAX_INTERFACE handling codes. + +1999-09-17 Satosi KOBAYASI + + * Fix serious bug of IPv6 route deletion. + +1999-09-11 Kunihiro Ishiguro + + * ioctl.c (if_set_prefix): Properly set broadcast address. + +1999-09-04 Yasuhiro Ohara + + * rib.c (rib_add_ipv6, rib_delete_ipv6): now protocol daemons + can install connected route to kernel via zebra + +1999-08-24 VOP + + * rib.c: Include "sockunion.h" + +1999-08-22 Kunihiro Ishiguro + + * ipforward.h: New file. + + * zebra.h: Obsolete message ZEBRA_GET_ALL_INTERFACE, + ZEBRA_GET_ONE_INTERFACE, ZEBRA_GET_HOSTINFO are deleted. + +1999-08-18 Kunihiro Ishiguro + + * zebra.h (ZEBRA_INTERFACE_ADDRESS_ADD): + ZEBRA_INTERFACE_{ADD,DELETE} added. + +1999-08-15 Kunihiro Ishiguro + + * rib.c: show ip route A.B.C.D works. + + * zebra.c (zebra_read_ipv4): Add ifindex to zebra messages. + +1999-08-12 Kunihiro Ishiguro + + * zebra.h: New Zebra message ZEBRA_INTERFACE_{ADD,DELETE} added. + +1999-08-09 Kunihiro Ishiguro + + * interface.h: New file. + * Makefile.am: Add interface.h + +1999-08-04 Yasuhiro Ohara + + * redistribute.c (zebra_redistribute): give ifindex to client. + +1999-08-02 Kunihiro Ishiguro + + * main.c (longopts): -k, --keep_kernel option added. + +1999-07-18 Yasuhiro Ohara + + * rt_socket.c (rtm_write): forgot closing socket bug fixed. + +1999-07-17 Yasuhiro Ohara + + * rib.c (show_ipv6_cmd): if rib is link show interface name. + +1999-07-17 Yasuhiro Ohara + + * rt_socket.c (rtm_write): use sockaddr_dl when null gateway. + +1999-07-16 Yasuhiro Ohara + + * rt_socket.c (rtm_write): ipv6 route table bug fixed. + +1999-07-15 Yasuhiro Ohara + + * zebra.c (zebra_read_ipv6): read link prefix from ospf6 support + +1999-07-15 Yasuhiro Ohara + + * rt_socket.c (kernel_rtm_ipv6): gate treatment bug fixed. + +1999-07-15 Kunihiro Ishiguro + + * if_sysctl.c (ifm_read): Clear sockunion argument before fetching + data. Suggested by "Chris P. Ross" + +1999-07-08 HEO SeonMeyong + + * interface.c (if_tun_add): Add KAME's gif tunnel setting codes. + +1999-06-26 Kunihiro Ishiguro + + * zebra.c (zebra_serv): Only accept loopback address connection. + +1999-06-25 Kunihiro Ishiguro + + * zebra.h (ZEBRA_ROUTE_EXTERNAL): Add zebra messages flags + +1999-06-17 Kunihiro Ishiguro + + * ipforward_proc.c: ipforward_on () and ipforward_off () added. + +1999-06-14 Kunihiro Ishiguro + + * ipforward_proc.c (ipforward_ipv6): Check for IPv6 forwarding + using /proc file system is added. + +1999-06-06 Kunihiro Ishiguro + + * if_ioctl.c (if_get_index): Interface index set bug is fixed by + adding #else at the middle of function. Suggested by David Luyer + . + +1999-05-29 + + * rt_ioctl.c: Comment out #include . + +1999-05-26 Kunihiro Ishiguro + + * zebra.h (ZEBRA_ROUTE_MAX): Add new define for the max value of + the sort of routes. + +1999-05-25 Patrick Koppen + + * rt_netlink.c (netlink_socket): Make netlink socket non-blocking. + (netlink_parse_info): If errno is EWOULDBLOCK then continue to + parse the message. + (netlink_talk): Likewise + +1999-05-17 + + * redistribute.c (zebra_check_addr): Added for loopback address + check. + +1999-05-15 Kunihiro Ishiguro + + * rt_netlink.c (netlink_route_change): Tempolary bypass ipv6 route + change treatment. + + * Makefile.am (noinst_HEADERS): redistribute.h added. + + * redistribute.h: New file. + +1999-05-14 Stephen R. van den Berg + + * zebra.c (show_table): Show all table configuration DEFUN. + (config_table): Config table number DEFUN. + + * rt_netlink.c: Add support for multiple routing table. + + * rib.c (rib_weed_table): New function added for delete all + routes from specified routing table. + + * main.c (signal_init): SIGTERM call sigint. + (sigint): Loggging more better message. + +1999-05-09 Kunihiro Ishiguro + + * rt_netlink.c: Change log () to zlog (). + +1999-05-07 + + * zebra.h (ZEBRA_ROUTE_OSPF6): Added for ospf6d route. + +1999-04-20 Kunihiro Ishiguro + + * interface.c: Add `no ip address' command. + +1999-04-10 Kunihiro Ishiguro + + * rt_netlink.c (kernel_read): Function added for asynchronous + zebra between kernel communication. + +1999-03-25 Kunihiro Ishiguro + + * rtread_sysctl.c (rtm_read): Fix address memcopy overrun bug. + Reported by Achim Patzner . + +1999-03-03 Kunihiro Ishiguro + + * Makefile.am: Install configuration sample with 600 permission. + +1999-03-02 Kunihiro Ishiguro + + * Makefile.am: Add -I.. to INCLUDES. + +1999-02-18 Peter Galbavy + + * syslog support added + +1999-02-17 Peter Galbavy + + * if_sysctl.c (interface_list): allocated memory free when unknown + ifm_type is returned. + + * ioctl.c (if_get_mtu): added SIOCGIFDATA treatment. + +1998-12-15 Magnus Ahltorp + + * interface.c: Header include added. + +1998-12-14 Kunihiro Ishiguro + + * rt.h (kernel_delete_ipv6): change int index to unsigned int index. + +1998-12-13 Kunihiro Ishiguro + + * if_ioctl.c (interface_list_ioctl): interface flag must be + checked before check addresses of the interface. + +1998-12-07 Kunihiro Ishiguro + + * Makefile.am (INCLUDES): add @INCLUDES@ for Linux IPv6. + +1998-10-14 Kunihiro Ishiguro + + * ioctl.c: Linux version before 2.1.0 need interface route setup. + +1998-09-15 HEO SeonMeyong + + * change HYDRANGEA to KAME + +1998-09-01 Kunihiro Ishiguro + + * if_ioctl.c (if_addr_ioctl): set address family for getting + interface's address. + (if_get_index): silently return when can't get interface's index. + +1998-08-17 Kunihiro Ishiguro + + * main.c (main): batch mode option '-b' added. + +1998-08-16 Kunihiro Ishiguro + + * ioctl.c (if_set_prefix): add `ip address IPV4ADDR' command. + * interface.c (shutdown_if): add interface shutdown and no + shutdown command. + +1998-08-12 Kunihiro Ishiguro + + * rib.c (rib_add_ipv6): delete rib_add_in6. + +1998-07-27 Kunihiro Ishiguro + + * main.c: retain flag is added. + +1998-07-08 Kunihiro Ishiguro + + * rtable.[ch]: merged with rib.[ch] + +1998-07-07 Kunihiro Ishiguro + + * connected.h: renamed from ifa.h. + +1998-06-09 Kunihiro Ishiguro + + * rename if.c to interface.c + * rename ifa.c to connected.c + + * Porting to Debian GNU/Linux 2.0 (hamm). + +1998-06-08 Kunihiro Ishiguro + + * rt_netlink.c: renamed from krt_netlink.c + + * fib.c: deleted. + * rt_kvm.c: deleted. + * rtread_getmsg.c: deleted. + +1998-06-07 Kunihiro Ishiguro + + * if.c (multicast): add multicast flag [un]set fucntion. + +1998-05-19 Yamshita TAKAO + + * rt_socket.c: Modify for compile on Solaris, but dont't work it. + rt_socket.c have some undefined function, so add directive "IMPLEMENT" + +1998-05-18 Yamshita TAKAO + + * zebra.c: Modify for compile on Solaris. + +1998-05-03 Kunihiro Ishiguro + + * main.c: change CONFDIR to SYSCONFDIR. + +1998-05-01 Kunihiro Ishiguro + + * .cvsignore: added. + +1998-04-02 Kunihiro Ishiguro + + * client.c: moves to ../lib. + +1998-03-30 Kunihiro Ishiguro + + * if_ioctl.c (if_get_addr): Change address copy from memcopy() to + structure assignment. + +1998-03-30 URA Hiroshi + + * if_sysctl.c (ifm_interface_add): sdl->sdl_data copy bug fixed. + +1998-02-23 "Hannes R. Boehm" + + * if.c (if_init): add config_exit_cmd and config_help_cmd. + +1998-01-24 Kunihiro Ishiguro + + * rt_ioctl.c (route_ioctl): EPERM treatment added. + +1998-01-05 Kunihiro Ishiguro + + * rt_socket.c (kernel_read): communication port zebra between + kernel is now handled by kernel_read. + +1998-01-02 Kunihiro Ishiguro + + * main.c (main): zebra [-P port] can specify vty port number. + +1997-12-25 Kunihiro Ishiguro + + * zebra.c: change select will be block. + +1997-12-04 Kunihiro Ishiguro + + * add static route treatment. + +1997-11-25 Kunihiro Ishiguro + + * rt_netlink.c: add netlink support over GNU/Linux system. + +1997-11-23 Kunihiro Ishiguro + + * all inet_addr is changed to inet_aton. + + * zebra.c (ip_route): add ip route command for static routes. + +1997-11-20 Kunihiro Ishiguro + + * if.c (if_flag_dump): Linux port of if_flag_dump and _vty. + +1997-11-19 Kunihiro Ishiguro + + * if.c: add interface command. + +1997-11-18 Kunihiro Ishiguro + + * ipforward_proc.c : Now works on Linux. + +1997-10-25 Kunihiro Ishiguro + + * command.c : add completion feature. + +1997-10-18 Kunihiro Ishiguro + + * vty.c (vty_command): add vty interface. + +1997-10-13 Kunihiro Ishiguro + + * zebra.c: add verbose mode. + +1997-10-12 SonMyong Ho + + * Hydrangea for FreeBSD supported + * in.h: add some prototype. + +1997-10-11 Kunihiro Ishiguro + + * rt_socket.c and rtread.c completely rewritten. + +1997-10-05 Kunihiro Ishiguro + + * rt_socket.c: rename kernel_sock to routing_socket + +1997-10-04 Kunihiro Ishiguro + + * if.c (if_new): interface structure change from linklist to vector. + +1997-10-03 Kunihiro Ishiguro + + * vector.c (vector_init): create vector related function + +1997-09-25 Kunihiro Ishiguro + + * Makefile.in: add tags target + + * start IPv6 support for INRIA FreeBSD. + diff --git a/zebra/GNOME-PRODUCT-ZEBRA-MIB b/zebra/GNOME-PRODUCT-ZEBRA-MIB new file mode 100644 index 00000000..96bcec57 --- /dev/null +++ b/zebra/GNOME-PRODUCT-ZEBRA-MIB @@ -0,0 +1,78 @@ +GNOME-PRODUCT-ZEBRA-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, + OBJECT-IDENTITY + FROM SNMPv2-SMI + gnomeProducts + FROM GNOME-SMI; + +zebra MODULE-IDENTITY + LAST-UPDATED "200004250000Z" + ORGANIZATION "GNOME project" + CONTACT-INFO + "GNU Network Object Model Environment project + + see http://www.gnome.org for contact persons of a particular + area or subproject of GNOME. + + Administrative contact for MIB module: + + Jochen Friedrich + Wingertstr. 70/1 + 68809 Neulussheim + Germany + + email: snmp@gnome.org" + DESCRIPTION + "The product registrations for the various zebra subdeamons. + These registrations are guaranteed to be unique and are used + for SMUX registration by default (if not overridden manually)." + ::= { gnomeProducts 2 } + +zserv OBJECT-IDENTITY + STATUS current + DESCRIPTION + "zserv is part of the zebra project which again is a GNU + endorsed internet routing program. + zserv is the main zebra process which implements routing + entries with the kernel and handles routing updates between + other routing protocols." + ::= { zebra 1 } + +bgpd OBJECT-IDENTITY + STATUS current + DESCRIPTION + "bgpd is part of the zebra project which again is a GNU + endorsed internet routing program." + ::= { zebra 2 } + +ripd OBJECT-IDENTITY + STATUS current + DESCRIPTION + "ripd is part of the zebra project which again is a GNU + endorsed internet routing program." + ::= { zebra 3 } + +ripngd OBJECT-IDENTITY + STATUS current + DESCRIPTION + "ripngd is part of the zebra project which again is a GNU + endorsed internet routing program." + ::= { zebra 4 } + +ospfd OBJECT-IDENTITY + STATUS current + DESCRIPTION + "ospfd is part of the zebra project which again is a GNU + endorsed internet routing program." + ::= { zebra 5 } + +ospf6d OBJECT-IDENTITY + STATUS current + DESCRIPTION + "ospf6d is part of the zebra project which again is a GNU + endorsed internet routing program." + ::= { zebra 6 } + +END diff --git a/zebra/GNOME-SMI b/zebra/GNOME-SMI new file mode 100644 index 00000000..164732bb --- /dev/null +++ b/zebra/GNOME-SMI @@ -0,0 +1,53 @@ +GNOME-SMI DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, + OBJECT-IDENTITY, + enterprises + FROM SNMPv2-SMI; + +gnome MODULE-IDENTITY + LAST-UPDATED "9809010000Z" + ORGANIZATION "GNOME project" + CONTACT-INFO + "GNU Network Object Model Environment project + + see http://www.gnome.org for contact persons of a particular + area or subproject of GNOME. + + Administrative contact for MIB module: + + Jochen Friedrich + Wingertstr. 70/1 + 68809 Neulussheim + Germany + + email: snmp@gnome.org" + DESCRIPTION + "The Structure of GNOME." + ::= { enterprises 3317 } -- assigned by IANA + +gnomeProducts OBJECT-IDENTITY + STATUS current + DESCRIPTION + "gnomeProducts is the root OBJECT IDENTIFIER from + which sysObjectID values are assigned." + ::= { gnome 1 } + +gnomeMgmt OBJECT-IDENTITY + STATUS current + DESCRIPTION + "gnomeMgmt defines the subtree for production GNOME related + MIB registrations." + ::= { gnome 2 } + +gnomeTest OBJECT-IDENTITY + STATUS current + DESCRIPTION + "gnomeTest defines the subtree for testing GNOME related + MIB registrations." + ::= { gnome 3 } + +-- more to come if necessary. + +END diff --git a/zebra/Makefile.am b/zebra/Makefile.am new file mode 100644 index 00000000..6214767d --- /dev/null +++ b/zebra/Makefile.am @@ -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 index 00000000..ad35b383 --- /dev/null +++ b/zebra/Makefile.in @@ -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 index 00000000..c319aac7 --- /dev/null +++ b/zebra/client_main.c @@ -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 + +#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 index 00000000..cb43074b --- /dev/null +++ b/zebra/connected.c @@ -0,0 +1,394 @@ +/* + * Address linked list routine. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "linklist.h" +#include "if.h" +#include "table.h" +#include "rib.h" +#include "table.h" +#include "log.h" + +#include "zebra/zserv.h" +#include "zebra/redistribute.h" + +/* If same interface address is already exist... */ +struct connected * +connected_check_ipv4 (struct interface *ifp, struct prefix *p) +{ + struct connected *ifc; + listnode node; + + for (node = listhead (ifp->connected); node; node = nextnode (node)) + { + ifc = getdata (node); + + if (prefix_same (ifc->address, p)) + return ifc; + } + return NULL; +} + +/* Called from if_up(). */ +void +connected_up_ipv4 (struct interface *ifp, struct connected *ifc) +{ + struct prefix_ipv4 p; + struct prefix_ipv4 *addr; + struct prefix_ipv4 *dest; + + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + return; + + addr = (struct prefix_ipv4 *) ifc->address; + dest = (struct prefix_ipv4 *) ifc->destination; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = addr->prefixlen; + + /* Point-to-point check. */ + if (if_is_pointopoint (ifp)) + p.prefix = dest->prefix; + else + p.prefix = addr->prefix; + + /* Apply mask to the network. */ + apply_mask_ipv4 (&p); + + /* In case of connected address is 0.0.0.0/0 we treat it tunnel + address. */ + if (prefix_ipv4_any (&p)) + return; + + rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, 0, 0); + + rib_update (); +} + +/* Add connected IPv4 route to the interface. */ +void +connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, + int prefixlen, struct in_addr *broad, char *label) +{ + struct prefix_ipv4 *p; + struct connected *ifc; + struct connected *current; + + /* Make connected structure. */ + ifc = connected_new (); + ifc->ifp = ifp; + ifc->flags = flags; + + /* Allocate new connected address. */ + p = prefix_ipv4_new (); + p->family = AF_INET; + p->prefix = *addr; + p->prefixlen = prefixlen; + ifc->address = (struct prefix *) p; + + /* If there is broadcast or pointopoint address. */ + if (broad) + { + p = prefix_ipv4_new (); + p->family = AF_INET; + p->prefix = *broad; + ifc->destination = (struct prefix *) p; + } + + /* Label of this address. */ + if (label) + ifc->label = strdup (label); + + /* Check same connected route. */ + current = connected_check_ipv4 (ifp, (struct prefix *) ifc->address); + if (current) + { + connected_free (ifc); + ifc = current; + } + else + { + listnode_add (ifp->connected, ifc); + } + + /* Update interface address information to protocol daemon. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + { + SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + + zebra_interface_address_add_update (ifp, ifc); + + if (if_is_up(ifp)) + connected_up_ipv4 (ifp, ifc); + } +} + +void +connected_down_ipv4 (struct interface *ifp, struct connected *ifc) +{ + struct prefix_ipv4 p; + struct prefix_ipv4 *addr; + struct prefix_ipv4 *dest; + + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + return; + + addr = (struct prefix_ipv4 *)ifc->address; + dest = (struct prefix_ipv4 *)ifc->destination; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = addr->prefixlen; + + if (if_is_pointopoint (ifp)) + p.prefix = dest->prefix; + else + p.prefix = addr->prefix; + + /* Apply mask to the network. */ + apply_mask_ipv4 (&p); + + /* In case of connected address is 0.0.0.0/0 we treat it tunnel + address. */ + if (prefix_ipv4_any (&p)) + return; + + rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0); + + rib_update (); +} + +/* Delete connected IPv4 route to the interface. */ +void +connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, + int prefixlen, struct in_addr *broad, char *label) +{ + struct prefix_ipv4 p; + struct connected *ifc; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefix = *addr; + p.prefixlen = prefixlen; + + ifc = connected_check_ipv4 (ifp, (struct prefix *) &p); + if (! ifc) + return; + + /* Update interface address information to protocol daemon. */ + if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + { + zebra_interface_address_delete_update (ifp, ifc); + + connected_down_ipv4 (ifp, ifc); + + UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + } + + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) + { + listnode_delete (ifp->connected, ifc); + connected_free (ifc); + } +} + +#ifdef HAVE_IPV6 +/* If same interface address is already exist... */ +struct connected * +connected_check_ipv6 (struct interface *ifp, struct prefix *p) +{ + struct connected *ifc; + listnode node; + + for (node = listhead (ifp->connected); node; node = nextnode (node)) + { + ifc = getdata (node); + + if (prefix_same (ifc->address, p)) + return ifc; + } + return 0; +} + +void +connected_up_ipv6 (struct interface *ifp, struct connected *ifc) +{ + struct prefix_ipv6 p; + struct prefix_ipv6 *addr; + struct prefix_ipv6 *dest; + + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + return; + + addr = (struct prefix_ipv6 *) ifc->address; + dest = (struct prefix_ipv6 *) ifc->destination; + + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = addr->prefixlen; + + if (if_is_pointopoint (ifp) && dest) + { + if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix)) + p.prefix = addr->prefix; + else + p.prefix = dest->prefix; + } + else + p.prefix = addr->prefix; + + /* Apply mask to the network. */ + apply_mask_ipv6 (&p); + + if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix)) + return; + + rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0); + + rib_update (); +} + +/* Add connected IPv6 route to the interface. */ +void +connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr, + int prefixlen, struct in6_addr *broad) +{ + struct prefix_ipv6 *p; + struct connected *ifc; + struct connected *current; + + /* Make connected structure. */ + ifc = connected_new (); + ifc->ifp = ifp; + + /* Allocate new connected address. */ + p = prefix_ipv6_new (); + p->family = AF_INET6; + IPV6_ADDR_COPY (&p->prefix, addr); + p->prefixlen = prefixlen; + ifc->address = (struct prefix *) p; + + /* If there is broadcast or pointopoint address. */ + if (broad) + { + p = prefix_ipv6_new (); + p->family = AF_INET6; + IPV6_ADDR_COPY (&p->prefix, broad); + ifc->destination = (struct prefix *) p; + } + + current = connected_check_ipv6 (ifp, (struct prefix *) ifc->address); + if (current) + { + connected_free (ifc); + ifc = current; + } + else + { + listnode_add (ifp->connected, ifc); + } + + /* Update interface address information to protocol daemon. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + { + SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + + zebra_interface_address_add_update (ifp, ifc); + + if (if_is_up(ifp)) + connected_up_ipv6 (ifp, ifc); + } +} + +void +connected_down_ipv6 (struct interface *ifp, struct connected *ifc) +{ + struct prefix_ipv6 p; + struct prefix_ipv6 *addr; + struct prefix_ipv6 *dest; + + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + return; + + addr = (struct prefix_ipv6 *) ifc->address; + dest = (struct prefix_ipv6 *) ifc->destination; + + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = addr->prefixlen; + + if (if_is_pointopoint (ifp) && dest) + { + if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix)) + p.prefix = addr->prefix; + else + p.prefix = dest->prefix; + } + else + p.prefix = addr->prefix; + + apply_mask_ipv6 (&p); + + if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix)) + return; + + rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0); + + rib_update (); +} + +void +connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address, + int prefixlen, struct in6_addr *broad) +{ + struct prefix_ipv6 p; + struct connected *ifc; + + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + memcpy (&p.prefix, address, sizeof (struct in6_addr)); + p.prefixlen = prefixlen; + + ifc = connected_check_ipv6 (ifp, (struct prefix *) &p); + if (! ifc) + return; + + /* Update interface address information to protocol daemon. */ + if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + { + zebra_interface_address_delete_update (ifp, ifc); + + connected_down_ipv6 (ifp, ifc); + + UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + } + + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) + { + listnode_delete (ifp->connected, ifc); + connected_free (ifc); + } +} +#endif /* HAVE_IPV6 */ diff --git a/zebra/connected.h b/zebra/connected.h new file mode 100644 index 00000000..7bf13baf --- /dev/null +++ b/zebra/connected.h @@ -0,0 +1,60 @@ +/* + * Interface's address and mask. + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_CONNECTED_H +#define _ZEBRA_CONNECTED_H + +struct connected * +connected_check_ipv4 (struct interface *ifp, struct prefix *p); + +void +connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, + int prefixlen, struct in_addr *broad, char *label); + +void +connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, + int prefixlen, struct in_addr *broad, char *label); + +void +connected_up_ipv4 (struct interface *, struct connected *); +void +connected_down_ipv4 (struct interface *, struct connected *); + +#ifdef HAVE_IPV6 +struct connected * +connected_check_ipv6 (struct interface *ifp, struct prefix *p); + +void +connected_add_ipv6 (struct interface *ifp, struct in6_addr *address, + int prefixlen, struct in6_addr *broad); +void +connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address, + int prefixlen, struct in6_addr *broad); +void +connected_up_ipv6 (struct interface *, struct connected *); + +void +connected_down_ipv6 (struct interface *ifp, struct connected *); + +#endif /* HAVE_IPV6 */ + +#endif /*_ZEBRA_CONNECTED_H */ diff --git a/zebra/debug.c b/zebra/debug.c new file mode 100644 index 00000000..fc99623a --- /dev/null +++ b/zebra/debug.c @@ -0,0 +1,272 @@ +/* + * Zebra debug related function + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "command.h" +#include "debug.h" + +/* For debug statement. */ +unsigned long zebra_debug_event; +unsigned long zebra_debug_packet; +unsigned long zebra_debug_kernel; + +DEFUN (show_debugging_zebra, + show_debugging_zebra_cmd, + "show debugging zebra", + SHOW_STR + "Zebra configuration\n" + "Debugging information\n") +{ + vty_out (vty, "Zebra debugging status:%s", VTY_NEWLINE); + + if (IS_ZEBRA_DEBUG_EVENT) + vty_out (vty, " Zebra event debugging is on%s", VTY_NEWLINE); + + if (IS_ZEBRA_DEBUG_PACKET) + { + if (IS_ZEBRA_DEBUG_SEND && IS_ZEBRA_DEBUG_RECV) + { + vty_out (vty, " Zebra packet%s debugging is on%s", + IS_ZEBRA_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + } + else + { + if (IS_ZEBRA_DEBUG_SEND) + vty_out (vty, " Zebra packet send%s debugging is on%s", + IS_ZEBRA_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + else + vty_out (vty, " Zebra packet receive%s debugging is on%s", + IS_ZEBRA_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + } + } + + if (IS_ZEBRA_DEBUG_KERNEL) + vty_out (vty, " Zebra kernel debugging is on%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN (debug_zebra_events, + debug_zebra_events_cmd, + "debug zebra events", + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra events\n") +{ + zebra_debug_event = ZEBRA_DEBUG_EVENT; + return CMD_WARNING; +} + +DEFUN (debug_zebra_packet, + debug_zebra_packet_cmd, + "debug zebra packet", + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra packet\n") +{ + zebra_debug_packet = ZEBRA_DEBUG_PACKET; + zebra_debug_packet |= ZEBRA_DEBUG_SEND; + zebra_debug_packet |= ZEBRA_DEBUG_RECV; + return CMD_SUCCESS; +} + +DEFUN (debug_zebra_packet_direct, + debug_zebra_packet_direct_cmd, + "debug zebra packet (recv|send)", + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra packet\n" + "Debug option set for receive packet\n" + "Debug option set for send packet\n") +{ + zebra_debug_packet = ZEBRA_DEBUG_PACKET; + if (strncmp ("send", argv[0], strlen (argv[0])) == 0) + zebra_debug_packet |= ZEBRA_DEBUG_SEND; + if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) + zebra_debug_packet |= ZEBRA_DEBUG_RECV; + zebra_debug_packet &= ~ZEBRA_DEBUG_DETAIL; + return CMD_SUCCESS; +} + +DEFUN (debug_zebra_packet_detail, + debug_zebra_packet_detail_cmd, + "debug zebra packet (recv|send) detail", + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra packet\n" + "Debug option set for receive packet\n" + "Debug option set for send packet\n" + "Debug option set detaied information\n") +{ + zebra_debug_packet = ZEBRA_DEBUG_PACKET; + if (strncmp ("send", argv[0], strlen (argv[0])) == 0) + zebra_debug_packet |= ZEBRA_DEBUG_SEND; + if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) + zebra_debug_packet |= ZEBRA_DEBUG_RECV; + zebra_debug_packet |= ZEBRA_DEBUG_DETAIL; + return CMD_SUCCESS; +} + +DEFUN (debug_zebra_kernel, + debug_zebra_kernel_cmd, + "debug zebra kernel", + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra between kernel interface\n") +{ + zebra_debug_kernel = ZEBRA_DEBUG_KERNEL; + return CMD_SUCCESS; +} + +DEFUN (no_debug_zebra_events, + no_debug_zebra_events_cmd, + "no debug zebra events", + NO_STR + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra events\n") +{ + zebra_debug_event = 0; + return CMD_SUCCESS; +} + +DEFUN (no_debug_zebra_packet, + no_debug_zebra_packet_cmd, + "no debug zebra packet", + NO_STR + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra packet\n") +{ + zebra_debug_packet = 0; + return CMD_SUCCESS; +} + +DEFUN (no_debug_zebra_packet_direct, + no_debug_zebra_packet_direct_cmd, + "no debug zebra packet (recv|send)", + NO_STR + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra packet\n" + "Debug option set for receive packet\n" + "Debug option set for send packet\n") +{ + if (strncmp ("send", argv[0], strlen (argv[0])) == 0) + zebra_debug_packet &= ~ZEBRA_DEBUG_SEND; + if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) + zebra_debug_packet &= ~ZEBRA_DEBUG_RECV; + return CMD_SUCCESS; +} + +DEFUN (no_debug_zebra_kernel, + no_debug_zebra_kernel_cmd, + "no debug zebra kernel", + NO_STR + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra between kernel interface\n") +{ + zebra_debug_kernel = 0; + return CMD_SUCCESS; +} + +/* Debug node. */ +struct cmd_node debug_node = +{ + DEBUG_NODE, + "", /* Debug node has no interface. */ + 1 +}; + +int +config_write_debug (struct vty *vty) +{ + int write = 0; + + if (IS_ZEBRA_DEBUG_EVENT) + { + vty_out (vty, "debug zebra events%s", VTY_NEWLINE); + write++; + } + if (IS_ZEBRA_DEBUG_PACKET) + { + if (IS_ZEBRA_DEBUG_SEND && IS_ZEBRA_DEBUG_RECV) + { + vty_out (vty, "debug zebra packet%s%s", + IS_ZEBRA_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + write++; + } + else + { + if (IS_ZEBRA_DEBUG_SEND) + vty_out (vty, "debug zebra packet send%s%s", + IS_ZEBRA_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + else + vty_out (vty, "debug zebra packet recv%s%s", + IS_ZEBRA_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + write++; + } + } + if (IS_ZEBRA_DEBUG_KERNEL) + { + vty_out (vty, "debug zebra kernel%s", VTY_NEWLINE); + write++; + } + return write; +} + +void +zebra_debug_init () +{ + zebra_debug_event = 0; + zebra_debug_packet = 0; + + install_node (&debug_node, config_write_debug); + + install_element (VIEW_NODE, &show_debugging_zebra_cmd); + + install_element (ENABLE_NODE, &show_debugging_zebra_cmd); + install_element (ENABLE_NODE, &debug_zebra_events_cmd); + install_element (ENABLE_NODE, &debug_zebra_packet_cmd); + install_element (ENABLE_NODE, &debug_zebra_packet_direct_cmd); + install_element (ENABLE_NODE, &debug_zebra_packet_detail_cmd); + install_element (ENABLE_NODE, &debug_zebra_kernel_cmd); + install_element (ENABLE_NODE, &no_debug_zebra_events_cmd); + install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd); + install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd); + + install_element (CONFIG_NODE, &debug_zebra_events_cmd); + install_element (CONFIG_NODE, &debug_zebra_packet_cmd); + install_element (CONFIG_NODE, &debug_zebra_packet_direct_cmd); + install_element (CONFIG_NODE, &debug_zebra_packet_detail_cmd); + install_element (CONFIG_NODE, &debug_zebra_kernel_cmd); + install_element (CONFIG_NODE, &no_debug_zebra_events_cmd); + install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd); + install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd); +} diff --git a/zebra/debug.h b/zebra/debug.h new file mode 100644 index 00000000..6eaa9572 --- /dev/null +++ b/zebra/debug.h @@ -0,0 +1,52 @@ +/* + * Zebra debug related function + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_DEBUG_H +#define _ZEBRA_DEBUG_H + +/* Debug flags. */ +#define ZEBRA_DEBUG_EVENT 0x01 + +#define ZEBRA_DEBUG_PACKET 0x01 +#define ZEBRA_DEBUG_SEND 0x20 +#define ZEBRA_DEBUG_RECV 0x40 +#define ZEBRA_DEBUG_DETAIL 0x80 + +#define ZEBRA_DEBUG_KERNEL 0x01 + +/* Debug related macro. */ +#define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT) + +#define IS_ZEBRA_DEBUG_PACKET (zebra_debug_packet & ZEBRA_DEBUG_PACKET) +#define IS_ZEBRA_DEBUG_SEND (zebra_debug_packet & ZEBRA_DEBUG_SEND) +#define IS_ZEBRA_DEBUG_RECV (zebra_debug_packet & ZEBRA_DEBUG_RECV) +#define IS_ZEBRA_DEBUG_DETAIL (zebra_debug_packet & ZEBRA_DEBUG_DETAIL) + +#define IS_ZEBRA_DEBUG_KERNEL (zebra_debug_kernel & ZEBRA_DEBUG_KERNEL) + +extern unsigned long zebra_debug_event; +extern unsigned long zebra_debug_packet; +extern unsigned long zebra_debug_kernel; + +void zebra_debug_init (); + +#endif /* _ZEBRA_DEBUG_H */ diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c new file mode 100644 index 00000000..46f53011 --- /dev/null +++ b/zebra/if_ioctl.c @@ -0,0 +1,438 @@ +/* + * Interface looking up by ioctl (). + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "if.h" +#include "sockunion.h" +#include "prefix.h" +#include "ioctl.h" +#include "connected.h" +#include "memory.h" +#include "log.h" + +#include "zebra/interface.h" + +/* Interface looking up using infamous SIOCGIFCONF. */ +int +interface_list_ioctl () +{ + int ret; + int sock; +#define IFNUM_BASE 32 + int ifnum; + struct ifreq *ifreq; + struct ifconf ifconf; + struct interface *ifp; + int n; + int lastlen; + + /* Normally SIOCGIFCONF works with AF_INET socket. */ + sock = socket (AF_INET, SOCK_DGRAM, 0); + if (sock < 0) + { + zlog_warn ("Can't make AF_INET socket stream: %s", strerror (errno)); + return -1; + } + + /* Set initial ifreq count. This will be double when SIOCGIFCONF + fail. Solaris has SIOCGIFNUM. */ +#ifdef SIOCGIFNUM + ret = ioctl (sock, SIOCGIFNUM, &ifnum); + if (ret < 0) + ifnum = IFNUM_BASE; + else + ifnum++; +#else + ifnum = IFNUM_BASE; +#endif /* SIOCGIFNUM */ + + ifconf.ifc_buf = NULL; + + lastlen = 0; + /* Loop until SIOCGIFCONF success. */ + for (;;) + { + ifconf.ifc_len = sizeof (struct ifreq) * ifnum; + ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len); + + ret = ioctl(sock, SIOCGIFCONF, &ifconf); + + if (ret < 0) + { + zlog_warn ("SIOCGIFCONF: %s", strerror(errno)); + goto end; + } + /* Repeatedly get info til buffer fails to grow. */ + if (ifconf.ifc_len > lastlen) + { + lastlen = ifconf.ifc_len; + ifnum += 10; + continue; + } + /* Success. */ + break; + } + + /* Allocate interface. */ + ifreq = ifconf.ifc_req; + +#ifdef OPEN_BSD + for (n = 0; n < ifconf.ifc_len; ) + { + int size; + + ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n); + ifp = if_get_by_name (ifreq->ifr_name); + if_add_update (ifp); + size = ifreq->ifr_addr.sa_len; + if (size < sizeof (ifreq->ifr_addr)) + size = sizeof (ifreq->ifr_addr); + size += sizeof (ifreq->ifr_name); + n += size; + } +#else + for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq)) + { + ifp = if_get_by_name (ifreq->ifr_name); + if_add_update (ifp); + ifreq++; + } +#endif /* OPEN_BSD */ + + end: + close (sock); + XFREE (MTYPE_TMP, ifconf.ifc_buf); + + return ret; +} + +/* Get interface's index by ioctl. */ +int +if_get_index (struct interface *ifp) +{ + static int if_fake_index = 1; + +#ifdef HAVE_BROKEN_ALIASES + /* Linux 2.2.X does not provide individual interface index for aliases. */ + ifp->ifindex = if_fake_index++; + return ifp->ifindex; +#else +#ifdef SIOCGIFINDEX + int ret; + struct ifreq ifreq; + + ifreq_set_name (&ifreq, ifp); + + ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq); + if (ret < 0) + { + /* Linux 2.0.X does not have interface index. */ + ifp->ifindex = if_fake_index++; + return ifp->ifindex; + } + + /* OK we got interface index. */ +#ifdef ifr_ifindex + ifp->ifindex = ifreq.ifr_ifindex; +#else + ifp->ifindex = ifreq.ifr_index; +#endif + return ifp->ifindex; + +#else + ifp->ifindex = if_fake_index++; + return ifp->ifindex; +#endif /* SIOCGIFINDEX */ +#endif /* HAVE_BROKEN_ALIASES */ +} + +#ifdef SIOCGIFHWADDR +int +if_get_hwaddr (struct interface *ifp) +{ + int ret; + struct ifreq ifreq; + int i; + + strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ); + ifreq.ifr_addr.sa_family = AF_INET; + + /* Fetch Hardware address if available. */ + ret = if_ioctl (SIOCGIFHWADDR, (caddr_t) &ifreq); + if (ret < 0) + ifp->hw_addr_len = 0; + else + { + memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6); + + for (i = 0; i < 6; i++) + if (ifp->hw_addr[i] != 0) + break; + + if (i == 6) + ifp->hw_addr_len = 0; + else + ifp->hw_addr_len = 6; + } + return 0; +} +#endif /* SIOCGIFHWADDR */ + +#ifdef HAVE_GETIFADDRS +#include + +int +if_getaddrs () +{ + int ret; + struct ifaddrs *ifap; + struct ifaddrs *ifapfree; + struct interface *ifp; + int prefixlen; + + ret = getifaddrs (&ifap); + if (ret != 0) + { + zlog_err ("getifaddrs(): %s", strerror (errno)); + return -1; + } + + for (ifapfree = ifap; ifap; ifap = ifap->ifa_next) + { + ifp = if_lookup_by_name (ifap->ifa_name); + if (ifp == NULL) + { + zlog_err ("if_getaddrs(): Can't lookup interface %s\n", + ifap->ifa_name); + continue; + } + + if (ifap->ifa_addr->sa_family == AF_INET) + { + struct sockaddr_in *addr; + struct sockaddr_in *mask; + struct sockaddr_in *dest; + struct in_addr *dest_pnt; + + addr = (struct sockaddr_in *) ifap->ifa_addr; + mask = (struct sockaddr_in *) ifap->ifa_netmask; + prefixlen = ip_masklen (mask->sin_addr); + + dest_pnt = NULL; + + if (ifap->ifa_flags & IFF_POINTOPOINT) + { + dest = (struct sockaddr_in *) ifap->ifa_dstaddr; + dest_pnt = &dest->sin_addr; + } + + if (ifap->ifa_flags & IFF_BROADCAST) + { + dest = (struct sockaddr_in *) ifap->ifa_broadaddr; + dest_pnt = &dest->sin_addr; + } + + connected_add_ipv4 (ifp, 0, &addr->sin_addr, + prefixlen, dest_pnt, NULL); + } +#ifdef HAVE_IPV6 + if (ifap->ifa_addr->sa_family == AF_INET6) + { + struct sockaddr_in6 *addr; + struct sockaddr_in6 *mask; + struct sockaddr_in6 *dest; + struct in6_addr *dest_pnt; + + addr = (struct sockaddr_in6 *) ifap->ifa_addr; + mask = (struct sockaddr_in6 *) ifap->ifa_netmask; + prefixlen = ip6_masklen (mask->sin6_addr); + + dest_pnt = NULL; + + if (ifap->ifa_flags & IFF_POINTOPOINT) + { + if (ifap->ifa_dstaddr) + { + dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr; + dest_pnt = &dest->sin6_addr; + } + } + + if (ifap->ifa_flags & IFF_BROADCAST) + { + if (ifap->ifa_broadaddr) + { + dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr; + dest_pnt = &dest->sin6_addr; + } + } + + connected_add_ipv6 (ifp, &addr->sin6_addr, prefixlen, dest_pnt); + } +#endif /* HAVE_IPV6 */ + } + + freeifaddrs (ifapfree); + + return 0; +} +#else /* HAVE_GETIFADDRS */ +/* Interface address lookup by ioctl. This function only looks up + IPv4 address. */ +int +if_get_addr (struct interface *ifp) +{ + int ret; + struct ifreq ifreq; + struct sockaddr_in addr; + struct sockaddr_in mask; + struct sockaddr_in dest; + struct in_addr *dest_pnt; + u_char prefixlen; + + /* Interface's name and address family. */ + strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ); + ifreq.ifr_addr.sa_family = AF_INET; + + /* Interface's address. */ + ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq); + if (ret < 0) + { + if (errno != EADDRNOTAVAIL) + { + zlog_warn ("SIOCGIFADDR fail: %s", strerror (errno)); + return ret; + } + return 0; + } + memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in)); + + /* Interface's network mask. */ + ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq); + if (ret < 0) + { + if (errno != EADDRNOTAVAIL) + { + zlog_warn ("SIOCGIFNETMASK fail: %s", strerror (errno)); + return ret; + } + return 0; + } +#ifdef ifr_netmask + memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in)); +#else + memcpy (&mask, &ifreq.ifr_addr, sizeof (struct sockaddr_in)); +#endif /* ifr_netmask */ + prefixlen = ip_masklen (mask.sin_addr); + + /* Point to point or borad cast address pointer init. */ + dest_pnt = NULL; + + if (ifp->flags & IFF_POINTOPOINT) + { + ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq); + if (ret < 0) + { + if (errno != EADDRNOTAVAIL) + { + zlog_warn ("SIOCGIFDSTADDR fail: %s", strerror (errno)); + return ret; + } + return 0; + } + memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in)); + dest_pnt = &dest.sin_addr; + } + if (ifp->flags & IFF_BROADCAST) + { + ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq); + if (ret < 0) + { + if (errno != EADDRNOTAVAIL) + { + zlog_warn ("SIOCGIFBRDADDR fail: %s", strerror (errno)); + return ret; + } + return 0; + } + memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in)); + dest_pnt = &dest.sin_addr; + } + + + /* Set address to the interface. */ + connected_add_ipv4 (ifp, 0, &addr.sin_addr, prefixlen, dest_pnt, NULL); + + return 0; +} +#endif /* HAVE_GETIFADDRS */ + +/* Fetch interface information via ioctl(). */ +static void +interface_info_ioctl () +{ + listnode node; + struct interface *ifp; + + for (node = listhead (iflist); node; node = nextnode (node)) + { + ifp = getdata (node); + + if_get_index (ifp); +#ifdef SIOCGIFHWADDR + if_get_hwaddr (ifp); +#endif /* SIOCGIFHWADDR */ + if_get_flags (ifp); +#ifndef HAVE_GETIFADDRS + if_get_addr (ifp); +#endif /* ! HAVE_GETIFADDRS */ + if_get_mtu (ifp); + if_get_metric (ifp); + } +} + +/* Lookup all interface information. */ +void +interface_list () +{ + /* Linux can do both proc & ioctl, ioctl is the only way to get + interface aliases in 2.2 series kernels. */ +#ifdef HAVE_PROC_NET_DEV + interface_list_proc (); +#endif /* HAVE_PROC_NET_DEV */ + interface_list_ioctl (); + + /* After listing is done, get index, address, flags and other + interface's information. */ + interface_info_ioctl (); + +#ifdef HAVE_GETIFADDRS + if_getaddrs (); +#endif /* HAVE_GETIFADDRS */ + +#if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6) + /* Linux provides interface's IPv6 address via + /proc/net/if_inet6. */ + ifaddr_proc_ipv6 (); +#endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */ +} diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c new file mode 100644 index 00000000..c9c14760 --- /dev/null +++ b/zebra/if_netlink.c @@ -0,0 +1,33 @@ +/* + * Interface looking up by netlink. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +/* Extern from rt_netlink.c */ +void interface_lookup_netlink (); + +/* Interface information read by netlink. */ +void +interface_list () +{ + interface_lookup_netlink (); +} diff --git a/zebra/if_proc.c b/zebra/if_proc.c new file mode 100644 index 00000000..117859fd --- /dev/null +++ b/zebra/if_proc.c @@ -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 + +#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; +} + +#if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6) + +#ifndef _PATH_PROC_NET_IF_INET6 +#define _PATH_PROC_NET_IF_INET6 "/proc/net/if_inet6" +#endif /* _PATH_PROC_NET_IF_INET6 */ + +int +ifaddr_proc_ipv6 () +{ + FILE *fp; + char buf[PROCBUFSIZ]; + int n; + char addr[33]; + char ifname[20]; + int ifindex, plen, scope, status; + struct interface *ifp; + struct prefix_ipv6 p; + + /* Open proc file system. */ + fp = fopen (_PATH_PROC_NET_IF_INET6, "r"); + if (fp == NULL) + { + zlog_warn ("Can't open proc file %s: %s", + _PATH_PROC_NET_IF_INET6, strerror (errno)); + return -1; + } + + /* Get interface's IPv6 address. */ + while (fgets (buf, PROCBUFSIZ, fp) != NULL) + { + n = sscanf (buf, "%32s %02x %02x %02x %02x %20s", + addr, &ifindex, &plen, &scope, &status, ifname); + if (n != 6) + continue; + + ifp = if_get_by_name (ifname); + + /* Fetch interface's IPv6 address. */ + str2in6_addr (addr, &p.prefix); + p.prefixlen = plen; + + connected_add_ipv6 (ifp, &p.prefix, p.prefixlen, NULL); + } + return 0; +} +#endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */ diff --git a/zebra/if_sysctl.c b/zebra/if_sysctl.c new file mode 100644 index 00000000..1441dfcc --- /dev/null +++ b/zebra/if_sysctl.c @@ -0,0 +1,148 @@ +/* + * Get interface's address and mask information by sysctl() function. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "if.h" +#include "sockunion.h" +#include "prefix.h" +#include "connected.h" +#include "memory.h" +#include "ioctl.h" +#include "log.h" + +int +ifstat_update_sysctl () +{ + caddr_t ref, buf, end; + size_t bufsiz; + struct if_msghdr *ifm; + struct interface *ifp; + +#define MIBSIZ 6 + int mib[MIBSIZ] = + { + CTL_NET, + PF_ROUTE, + 0, + 0, /* AF_INET & AF_INET6 */ + NET_RT_IFLIST, + 0 + }; + + /* Query buffer size. */ + if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) + { + zlog_warn ("sysctl() error by %s", strerror (errno)); + return -1; + } + + /* We free this memory at the end of this function. */ + ref = buf = XMALLOC (MTYPE_TMP, bufsiz); + + /* Fetch interface informations into allocated buffer. */ + if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0) + { + zlog (NULL, LOG_WARNING, "sysctl error by %s", strerror (errno)); + return -1; + } + + /* Parse both interfaces and addresses. */ + for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) + { + ifm = (struct if_msghdr *) buf; + if (ifm->ifm_type == RTM_IFINFO) + { + ifp = if_lookup_by_index (ifm->ifm_index); + if (ifp) + ifp->stats = ifm->ifm_data; + } + } + + /* Free sysctl buffer. */ + XFREE (MTYPE_TMP, ref); + + return 0; +} + +/* Interface listing up function using sysctl(). */ +void +interface_list () +{ + caddr_t ref, buf, end; + size_t bufsiz; + struct if_msghdr *ifm; + int ifm_read (struct if_msghdr *); + int ifam_read (struct ifa_msghdr *); + +#define MIBSIZ 6 + int mib[MIBSIZ] = + { + CTL_NET, + PF_ROUTE, + 0, + 0, /* AF_INET & AF_INET6 */ + NET_RT_IFLIST, + 0 + }; + + /* Query buffer size. */ + if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) + { + zlog (NULL, LOG_WARNING, "sysctl() error by %s", strerror (errno)); + return; + } + + /* We free this memory at the end of this function. */ + ref = buf = XMALLOC (MTYPE_TMP, bufsiz); + + /* Fetch interface informations into allocated buffer. */ + if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0) + { + zlog (NULL, LOG_WARNING, "sysctl error by %s", strerror (errno)); + return; + } + + /* Parse both interfaces and addresses. */ + for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) + { + ifm = (struct if_msghdr *) buf; + + switch (ifm->ifm_type) + { + case RTM_IFINFO: + ifm_read (ifm); + break; + case RTM_NEWADDR: + ifam_read ((struct ifa_msghdr *) ifm); + break; + default: + zlog_info ("interfaces_list(): unexpected message type"); + XFREE (MTYPE_TMP, ref); + return; + break; + } + } + + /* Free sysctl buffer. */ + XFREE (MTYPE_TMP, ref); +} diff --git a/zebra/interface.c b/zebra/interface.c new file mode 100644 index 00000000..5629ebb3 --- /dev/null +++ b/zebra/interface.c @@ -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 + +#include "if.h" +#include "vty.h" +#include "sockunion.h" +#include "prefix.h" +#include "command.h" +#include "memory.h" +#include "ioctl.h" +#include "connected.h" +#include "log.h" +#include "zclient.h" + +#include "zebra/interface.h" +#include "zebra/rtadv.h" +#include "zebra/rib.h" +#include "zebra/zserv.h" +#include "zebra/redistribute.h" +#include "zebra/debug.h" + +/* Allocate a new internal interface index + * This works done from the top so that %d macros + * print a - sign! + */ +static unsigned int +if_new_intern_ifindex (void) +{ + /* Start here so that first one assigned is 0xFFFFFFFF */ + static unsigned int ifindex = IFINDEX_INTERNBASE + 1; + + for (;;) + { + ifindex--; + if ( ifindex <= IFINDEX_INTERNBASE ) + ifindex = 0xFFFFFFFF; + + if (if_lookup_by_index(ifindex) == NULL) + return ifindex; + } +} + +/* Called when new interface is added. */ +int +if_zebra_new_hook (struct interface *ifp) +{ + struct zebra_if *zebra_if; + + zebra_if = XMALLOC (MTYPE_TMP, sizeof (struct zebra_if)); + memset (zebra_if, 0, sizeof (struct zebra_if)); + + zebra_if->multicast = IF_ZEBRA_MULTICAST_UNSPEC; + zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_UNSPEC; + +#ifdef RTADV + { + /* Set default router advertise values. */ + struct rtadvconf *rtadv; + + rtadv = &zebra_if->rtadv; + + rtadv->AdvSendAdvertisements = 0; + rtadv->MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL; + rtadv->MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL; + rtadv->AdvIntervalTimer = 0; + rtadv->AdvManagedFlag = 0; + rtadv->AdvOtherConfigFlag = 0; + rtadv->AdvLinkMTU = 0; + rtadv->AdvReachableTime = 0; + rtadv->AdvRetransTimer = 0; + rtadv->AdvCurHopLimit = 0; + rtadv->AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME; + + rtadv->AdvPrefixList = list_new (); + } +#endif /* RTADV */ + + ifp->info = zebra_if; + return 0; +} + +/* Called when interface is deleted. */ +int +if_zebra_delete_hook (struct interface *ifp) +{ + if (ifp->info) + XFREE (MTYPE_TMP, ifp->info); + return 0; +} + +/* Wake up configured address if it is not in current kernel + address. */ +void +if_addr_wakeup (struct interface *ifp) +{ + struct listnode *node; + struct connected *ifc; + struct prefix *p; + int ret; + + for (node = listhead (ifp->connected); node; nextnode (node)) + { + ifc = getdata (node); + p = ifc->address; + + if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED) + && ! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + { + /* Address check. */ + if (p->family == AF_INET) + { + if (! if_is_up (ifp)) + { + if_set_flags (ifp, IFF_UP | IFF_RUNNING); + if_refresh (ifp); + } + + ret = if_set_prefix (ifp, ifc); + if (ret < 0) + { + zlog_warn ("Can't set interface's address: %s", + strerror(errno)); + continue; + } + SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + + zebra_interface_address_add_update (ifp, ifc); + + if (if_is_up(ifp)) + connected_up_ipv4 (ifp, ifc); + } +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + { + if (! if_is_up (ifp)) + { + if_set_flags (ifp, IFF_UP | IFF_RUNNING); + if_refresh (ifp); + } + + ret = if_prefix_add_ipv6 (ifp, ifc); + if (ret < 0) + { + zlog_warn ("Can't set interface's address: %s", + strerror(errno)); + continue; + } + SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + + zebra_interface_address_add_update (ifp, ifc); + + if (if_is_up(ifp)) + connected_up_ipv6 (ifp, ifc); + } +#endif /* HAVE_IPV6 */ + } + } +} + +/* Handle interface addition */ +void +if_add_update (struct interface *ifp) +{ + zebra_interface_add_update (ifp); + + if (! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) + { + SET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE); + + if_addr_wakeup (ifp); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("interface %s index %d becomes active.", + ifp->name, ifp->ifindex); + } + else + { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("interface %s index %d is added.", ifp->name, ifp->ifindex); + } +} + +/* Handle an interface delete event */ +void +if_delete_update (struct interface *ifp) +{ + struct listnode *node; + struct listnode *next; + struct connected *ifc; + struct prefix *p; + + if (if_is_up(ifp)) + { + zlog_err ("interface %s index %d is still up while being deleted.", + ifp->name, ifp->ifindex); + return; + } + + /* Mark interface as inactive */ + UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("interface %s index %d is now inactive.", + ifp->name, ifp->ifindex); + + /* Delete connected routes from the kernel. */ + if (ifp->connected) + { + for (node = listhead (ifp->connected); node; node = next) + { + next = node->next; + ifc = getdata (node); + p = ifc->address; + + if (p->family == AF_INET) + connected_down_ipv4 (ifp, ifc); +#ifdef HAVE_IPV6 + else if (p->family == AF_INET6) + connected_down_ipv6 (ifp, ifc); +#endif /* HAVE_IPV6 */ + + zebra_interface_address_delete_update (ifp, ifc); + + UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) + { + listnode_delete (ifp->connected, ifc); + connected_free (ifc); + } + } + } + zebra_interface_delete_update (ifp); +} + +/* Interface is up. */ +void +if_up (struct interface *ifp) +{ + listnode node; + listnode next; + struct connected *ifc; + struct prefix *p; + + /* Notify the protocol daemons. */ + zebra_interface_up_update (ifp); + + /* Install connected routes to the kernel. */ + if (ifp->connected) + { + for (node = listhead (ifp->connected); node; node = next) + { + next = node->next; + ifc = getdata (node); + p = ifc->address; + + if (p->family == AF_INET) + connected_up_ipv4 (ifp, ifc); +#ifdef HAVE_IPV6 + else if (p->family == AF_INET6) + connected_up_ipv6 (ifp, ifc); +#endif /* HAVE_IPV6 */ + } + } + + /* Examine all static routes. */ + rib_update (); +} + +/* Interface goes down. We have to manage different behavior of based + OS. */ +void +if_down (struct interface *ifp) +{ + listnode node; + listnode next; + struct connected *ifc; + struct prefix *p; + + /* Notify to the protocol daemons. */ + zebra_interface_down_update (ifp); + + /* Delete connected routes from the kernel. */ + if (ifp->connected) + { + for (node = listhead (ifp->connected); node; node = next) + { + next = node->next; + ifc = getdata (node); + p = ifc->address; + + if (p->family == AF_INET) + connected_down_ipv4 (ifp, ifc); +#ifdef HAVE_IPV6 + else if (p->family == AF_INET6) + connected_down_ipv6 (ifp, ifc); +#endif /* HAVE_IPV6 */ + } + } + + /* Examine all static routes which direct to the interface. */ + rib_update (); +} + +void +if_refresh (struct interface *ifp) +{ + if (if_is_up (ifp)) + { + if_get_flags (ifp); + if (! if_is_up (ifp)) + if_down (ifp); + } + else + { + if_get_flags (ifp); + if (if_is_up (ifp)) + if_up (ifp); + } +} + +/* Printout flag information into vty */ +void +if_flag_dump_vty (struct vty *vty, unsigned long flag) +{ + int separator = 0; + +#define IFF_OUT_VTY(X, Y) \ + if ((X) && (flag & (X))) \ + { \ + if (separator) \ + vty_out (vty, ","); \ + else \ + separator = 1; \ + vty_out (vty, Y); \ + } + + vty_out (vty, "<"); + IFF_OUT_VTY (IFF_UP, "UP"); + IFF_OUT_VTY (IFF_BROADCAST, "BROADCAST"); + IFF_OUT_VTY (IFF_DEBUG, "DEBUG"); + IFF_OUT_VTY (IFF_LOOPBACK, "LOOPBACK"); + IFF_OUT_VTY (IFF_POINTOPOINT, "POINTOPOINT"); + IFF_OUT_VTY (IFF_NOTRAILERS, "NOTRAILERS"); + IFF_OUT_VTY (IFF_RUNNING, "RUNNING"); + IFF_OUT_VTY (IFF_NOARP, "NOARP"); + IFF_OUT_VTY (IFF_PROMISC, "PROMISC"); + IFF_OUT_VTY (IFF_ALLMULTI, "ALLMULTI"); + IFF_OUT_VTY (IFF_OACTIVE, "OACTIVE"); + IFF_OUT_VTY (IFF_SIMPLEX, "SIMPLEX"); + IFF_OUT_VTY (IFF_LINK0, "LINK0"); + IFF_OUT_VTY (IFF_LINK1, "LINK1"); + IFF_OUT_VTY (IFF_LINK2, "LINK2"); + IFF_OUT_VTY (IFF_MULTICAST, "MULTICAST"); + vty_out (vty, ">"); +} + +/* Output prefix string to vty. */ +int +prefix_vty_out (struct vty *vty, struct prefix *p) +{ + char str[INET6_ADDRSTRLEN]; + + inet_ntop (p->family, &p->u.prefix, str, sizeof (str)); + vty_out (vty, "%s", str); + return strlen (str); +} + +/* Dump if address information to vty. */ +void +connected_dump_vty (struct vty *vty, struct connected *connected) +{ + struct prefix *p; + struct interface *ifp; + + /* Set interface pointer. */ + ifp = connected->ifp; + + /* Print interface address. */ + p = connected->address; + vty_out (vty, " %s ", prefix_family_str (p)); + prefix_vty_out (vty, p); + vty_out (vty, "/%d", p->prefixlen); + + /* If there is destination address, print it. */ + p = connected->destination; + if (p) + { + if (p->family == AF_INET) + if (ifp->flags & IFF_BROADCAST) + { + vty_out (vty, " broadcast "); + prefix_vty_out (vty, p); + } + + if (ifp->flags & IFF_POINTOPOINT) + { + vty_out (vty, " pointopoint "); + prefix_vty_out (vty, p); + } + } + + if (CHECK_FLAG (connected->flags, ZEBRA_IFA_SECONDARY)) + vty_out (vty, " secondary"); + + if (connected->label) + vty_out (vty, " %s", connected->label); + + vty_out (vty, "%s", VTY_NEWLINE); +} + +#ifdef RTADV +/* Dump interface ND information to vty. */ +void +nd_dump_vty (struct vty *vty, struct interface *ifp) +{ + struct zebra_if *zif; + struct rtadvconf *rtadv; + + zif = (struct zebra_if *) ifp->info; + rtadv = &zif->rtadv; + + if (rtadv->AdvSendAdvertisements) + { + vty_out (vty, " ND advertised reachable time is %d milliseconds%s", + rtadv->AdvReachableTime, VTY_NEWLINE); + vty_out (vty, " ND advertised retransmit interval is %d milliseconds%s", + rtadv->AdvRetransTimer, VTY_NEWLINE); + vty_out (vty, " ND router advertisements are sent every %d seconds%s", + rtadv->MaxRtrAdvInterval, VTY_NEWLINE); + vty_out (vty, " ND router advertisements live for %d seconds%s", + rtadv->AdvDefaultLifetime, VTY_NEWLINE); + if (rtadv->AdvManagedFlag) + vty_out (vty, " Hosts use DHCP to obtain routable addresses.%s", + VTY_NEWLINE); + else + vty_out (vty, " Hosts use stateless autoconfig for addresses.%s", + VTY_NEWLINE); + } +} +#endif /* RTADV */ + +/* Interface's information print out to vty interface. */ +void +if_dump_vty (struct vty *vty, struct interface *ifp) +{ +#ifdef HAVE_SOCKADDR_DL + struct sockaddr_dl *sdl; +#endif /* HAVE_SOCKADDR_DL */ + struct connected *connected; + listnode node; + + vty_out (vty, "Interface %s%s", ifp->name, + VTY_NEWLINE); + if (ifp->desc) + vty_out (vty, " Description: %s%s", ifp->desc, + VTY_NEWLINE); + if (ifp->ifindex <= 0) + { + vty_out(vty, " index %d pseudo interface%s", ifp->ifindex, VTY_NEWLINE); + return; + } + else if (! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) + { + vty_out(vty, " index %d inactive interface%s", + ifp->ifindex, + VTY_NEWLINE); + return; + } + + vty_out (vty, " index %d metric %d mtu %d ", + ifp->ifindex, ifp->metric, ifp->mtu); + if_flag_dump_vty (vty, ifp->flags); + vty_out (vty, "%s", VTY_NEWLINE); + + /* Hardware address. */ +#ifdef HAVE_SOCKADDR_DL + sdl = &ifp->sdl; + if (sdl != NULL && sdl->sdl_alen != 0) + { + int i; + u_char *ptr; + + vty_out (vty, " HWaddr: "); + for (i = 0, ptr = LLADDR (sdl); i < sdl->sdl_alen; i++, ptr++) + vty_out (vty, "%s%02x", i == 0 ? "" : ":", *ptr); + vty_out (vty, "%s", VTY_NEWLINE); + } +#else + if (ifp->hw_addr_len != 0) + { + int i; + + vty_out (vty, " HWaddr: "); + for (i = 0; i < ifp->hw_addr_len; i++) + vty_out (vty, "%s%02x", i == 0 ? "" : ":", ifp->hw_addr[i]); + vty_out (vty, "%s", VTY_NEWLINE); + } +#endif /* HAVE_SOCKADDR_DL */ + + /* Bandwidth in kbps */ + if (ifp->bandwidth != 0) + { + vty_out(vty, " bandwidth %u kbps", ifp->bandwidth); + vty_out(vty, "%s", VTY_NEWLINE); + } + + for (node = listhead (ifp->connected); node; nextnode (node)) + { + connected = getdata (node); + if (CHECK_FLAG (connected->conf, ZEBRA_IFC_REAL)) + connected_dump_vty (vty, connected); + } + +#ifdef RTADV + nd_dump_vty (vty, ifp); +#endif /* RTADV */ + +#ifdef HAVE_PROC_NET_DEV + /* Statistics print out using proc file system. */ + vty_out (vty, " input packets %lu, bytes %lu, dropped %lu," + " multicast packets %lu%s", + ifp->stats.rx_packets, ifp->stats.rx_bytes, + ifp->stats.rx_dropped, ifp->stats.rx_multicast, VTY_NEWLINE); + + vty_out (vty, " input errors %lu, length %lu, overrun %lu," + " CRC %lu, frame %lu, fifo %lu, missed %lu%s", + ifp->stats.rx_errors, ifp->stats.rx_length_errors, + ifp->stats.rx_over_errors, ifp->stats.rx_crc_errors, + ifp->stats.rx_frame_errors, ifp->stats.rx_fifo_errors, + ifp->stats.rx_missed_errors, VTY_NEWLINE); + + vty_out (vty, " output packets %lu, bytes %lu, dropped %lu%s", + ifp->stats.tx_packets, ifp->stats.tx_bytes, + ifp->stats.tx_dropped, VTY_NEWLINE); + + vty_out (vty, " output errors %lu, aborted %lu, carrier %lu," + " fifo %lu, heartbeat %lu, window %lu%s", + ifp->stats.tx_errors, ifp->stats.tx_aborted_errors, + ifp->stats.tx_carrier_errors, ifp->stats.tx_fifo_errors, + ifp->stats.tx_heartbeat_errors, ifp->stats.tx_window_errors, + VTY_NEWLINE); + + vty_out (vty, " collisions %lu%s", ifp->stats.collisions, VTY_NEWLINE); +#endif /* HAVE_PROC_NET_DEV */ + +#ifdef HAVE_NET_RT_IFLIST +#if defined (__bsdi__) || defined (__NetBSD__) + /* Statistics print out using sysctl (). */ + vty_out (vty, " input packets %qu, bytes %qu, dropped %qu," + " multicast packets %qu%s", + ifp->stats.ifi_ipackets, ifp->stats.ifi_ibytes, + ifp->stats.ifi_iqdrops, ifp->stats.ifi_imcasts, + VTY_NEWLINE); + + vty_out (vty, " input errors %qu%s", + ifp->stats.ifi_ierrors, VTY_NEWLINE); + + vty_out (vty, " output packets %qu, bytes %qu, multicast packets %qu%s", + ifp->stats.ifi_opackets, ifp->stats.ifi_obytes, + ifp->stats.ifi_omcasts, VTY_NEWLINE); + + vty_out (vty, " output errors %qu%s", + ifp->stats.ifi_oerrors, VTY_NEWLINE); + + vty_out (vty, " collisions %qu%s", + ifp->stats.ifi_collisions, VTY_NEWLINE); +#else + /* Statistics print out using sysctl (). */ + vty_out (vty, " input packets %lu, bytes %lu, dropped %lu," + " multicast packets %lu%s", + ifp->stats.ifi_ipackets, ifp->stats.ifi_ibytes, + ifp->stats.ifi_iqdrops, ifp->stats.ifi_imcasts, + VTY_NEWLINE); + + vty_out (vty, " input errors %lu%s", + ifp->stats.ifi_ierrors, VTY_NEWLINE); + + vty_out (vty, " output packets %lu, bytes %lu, multicast packets %lu%s", + ifp->stats.ifi_opackets, ifp->stats.ifi_obytes, + ifp->stats.ifi_omcasts, VTY_NEWLINE); + + vty_out (vty, " output errors %lu%s", + ifp->stats.ifi_oerrors, VTY_NEWLINE); + + vty_out (vty, " collisions %lu%s", + ifp->stats.ifi_collisions, VTY_NEWLINE); +#endif /* __bsdi__ || __NetBSD__ */ +#endif /* HAVE_NET_RT_IFLIST */ +} + +/* Check supported address family. */ +int +if_supported_family (int family) +{ + if (family == AF_INET) + return 1; +#ifdef HAVE_IPV6 + if (family == AF_INET6) + return 1; +#endif /* HAVE_IPV6 */ + return 0; +} + +/* Wrapper hook point for zebra daemon so that ifindex can be set + * DEFUN macro not used as extract.pl HAS to ignore this + * See also interface_cmd in lib/if.c + */ +DEFUN_NOSH (zebra_interface, + zebra_interface_cmd, + "interface IFNAME", + "Select an interface to configure\n" + "Interface's name\n") +{ + int ret; + struct interface * ifp; + + /* Call lib interface() */ + ret = interface_cmd.func (self, vty, argc, argv); + + ifp = vty->index; + + /* Set ifindex + this only happens if interface is NOT in kernel */ + if (ifp->ifindex == 0) + { + ifp->ifindex = if_new_intern_ifindex (); + UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE); + } + + return ret; +} + +DEFUN (no_zebra_interface, + no_zebra_interface_cmd, + "no interface IFNAME", + "Delete a pseudo interface's configuration\n" + "Interface's name\n") +{ + struct interface *ifp; + + ifp = if_lookup_by_name(argv[0]); + + if (ifp == NULL) + { + vty_out (vty, "Inteface %s does not exist%s", + argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + if (CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) + { + vty_out(vty, "Only inactive interfaces can be deleted%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Delete interface */ + if_delete(ifp); + + return CMD_SUCCESS; +} + +struct cmd_node interface_node = +{ + INTERFACE_NODE, + "%s(config-if)# ", + 1 +}; + +/* Show all or specified interface to vty. */ +DEFUN (show_interface, show_interface_cmd, + "show interface [IFNAME]", + SHOW_STR + "Interface status and configuration\n" + "Inteface name\n") +{ + listnode node; + struct interface *ifp; + +#ifdef HAVE_PROC_NET_DEV + /* If system has interface statistics via proc file system, update + statistics. */ + ifstat_update_proc (); +#endif /* HAVE_PROC_NET_DEV */ +#ifdef HAVE_NET_RT_IFLIST + ifstat_update_sysctl (); +#endif /* HAVE_NET_RT_IFLIST */ + + /* Specified interface print. */ + if (argc != 0) + { + ifp = if_lookup_by_name (argv[0]); + if (ifp == NULL) + { + vty_out (vty, "%% Can't find interface %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + if_dump_vty (vty, ifp); + return CMD_SUCCESS; + } + + /* All interface print. */ + for (node = listhead (iflist); node; nextnode (node)) + if_dump_vty (vty, getdata (node)); + + return CMD_SUCCESS; +} + +DEFUN (multicast, + multicast_cmd, + "multicast", + "Set multicast flag to interface\n") +{ + int ret; + struct interface *ifp; + struct zebra_if *if_data; + + ifp = (struct interface *) vty->index; + ret = if_set_flags (ifp, IFF_MULTICAST); + if (ret < 0) + { + vty_out (vty, "Can't set multicast flag%s", VTY_NEWLINE); + return CMD_WARNING; + } + if_refresh (ifp); + if_data = ifp->info; + if_data->multicast = IF_ZEBRA_MULTICAST_ON; + + return CMD_SUCCESS; +} + +DEFUN (no_multicast, + no_multicast_cmd, + "no multicast", + NO_STR + "Unset multicast flag to interface\n") +{ + int ret; + struct interface *ifp; + struct zebra_if *if_data; + + ifp = (struct interface *) vty->index; + ret = if_unset_flags (ifp, IFF_MULTICAST); + if (ret < 0) + { + vty_out (vty, "Can't unset multicast flag%s", VTY_NEWLINE); + return CMD_WARNING; + } + if_refresh (ifp); + if_data = ifp->info; + if_data->multicast = IF_ZEBRA_MULTICAST_OFF; + + return CMD_SUCCESS; +} + +DEFUN (shutdown_if, + shutdown_if_cmd, + "shutdown", + "Shutdown the selected interface\n") +{ + int ret; + struct interface *ifp; + struct zebra_if *if_data; + + ifp = (struct interface *) vty->index; + ret = if_unset_flags (ifp, IFF_UP); + if (ret < 0) + { + vty_out (vty, "Can't shutdown interface%s", VTY_NEWLINE); + return CMD_WARNING; + } + if_refresh (ifp); + if_data = ifp->info; + if_data->shutdown = IF_ZEBRA_SHUTDOWN_ON; + + return CMD_SUCCESS; +} + +DEFUN (no_shutdown_if, + no_shutdown_if_cmd, + "no shutdown", + NO_STR + "Shutdown the selected interface\n") +{ + int ret; + struct interface *ifp; + struct zebra_if *if_data; + + ifp = (struct interface *) vty->index; + ret = if_set_flags (ifp, IFF_UP | IFF_RUNNING); + if (ret < 0) + { + vty_out (vty, "Can't up interface%s", VTY_NEWLINE); + return CMD_WARNING; + } + if_refresh (ifp); + if_data = ifp->info; + if_data->shutdown = IF_ZEBRA_SHUTDOWN_OFF; + + return CMD_SUCCESS; +} + +DEFUN (bandwidth_if, + bandwidth_if_cmd, + "bandwidth <1-10000000>", + "Set bandwidth informational parameter\n" + "Bandwidth in kilobits\n") +{ + struct interface *ifp; + unsigned int bandwidth; + + ifp = (struct interface *) vty->index; + bandwidth = strtol(argv[0], NULL, 10); + + /* bandwidth range is <1-10000000> */ + if (bandwidth < 1 || bandwidth > 10000000) + { + vty_out (vty, "Bandwidth is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ifp->bandwidth = bandwidth; + + /* force protocols to recalculate routes due to cost change */ + if (if_is_up (ifp)) + zebra_interface_up_update (ifp); + + return CMD_SUCCESS; +} + +DEFUN (no_bandwidth_if, + no_bandwidth_if_cmd, + "no bandwidth", + NO_STR + "Set bandwidth informational parameter\n") +{ + struct interface *ifp; + + ifp = (struct interface *) vty->index; + + ifp->bandwidth = 0; + + /* force protocols to recalculate routes due to cost change */ + if (if_is_up (ifp)) + zebra_interface_up_update (ifp); + + return CMD_SUCCESS; +} + +ALIAS (no_bandwidth_if, + no_bandwidth_if_val_cmd, + "no bandwidth <1-10000000>", + NO_STR + "Set bandwidth informational parameter\n" + "Bandwidth in kilobits\n") + +int +ip_address_install (struct vty *vty, struct interface *ifp, char *addr_str, + char *peer_str, char *label, int secondary) +{ + struct prefix_ipv4 cp; + struct connected *ifc; + struct prefix_ipv4 *p; + struct in_addr mask; + int ret; + + ret = str2prefix_ipv4 (addr_str, &cp); + if (ret <= 0) + { + vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); + return CMD_WARNING; + } + + ifc = connected_check_ipv4 (ifp, (struct prefix *) &cp); + if (! ifc) + { + ifc = connected_new (); + ifc->ifp = ifp; + + /* Address. */ + p = prefix_ipv4_new (); + *p = cp; + ifc->address = (struct prefix *) p; + + /* Broadcast. */ + if (p->prefixlen <= 30) + { + p = prefix_ipv4_new (); + *p = cp; + masklen2ip (p->prefixlen, &mask); + p->prefix.s_addr |= ~mask.s_addr; + ifc->destination = (struct prefix *) p; + } + + /* Secondary. */ + if (secondary) + SET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY); + + /* Label. */ + if (label) + ifc->label = strdup (label); + + /* Add to linked list. */ + listnode_add (ifp->connected, ifc); + } + + /* This address is configured from zebra. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) + SET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED); + + /* In case of this route need to install kernel. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL) + && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) + { + /* Some system need to up the interface to set IP address. */ + if (! if_is_up (ifp)) + { + if_set_flags (ifp, IFF_UP | IFF_RUNNING); + if_refresh (ifp); + } + + ret = if_set_prefix (ifp, ifc); + if (ret < 0) + { + vty_out (vty, "%% Can't set interface IP address: %s.%s", + strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* IP address propery set. */ + SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + + /* Update interface address information to protocol daemon. */ + zebra_interface_address_add_update (ifp, ifc); + + /* If interface is up register connected route. */ + if (if_is_up(ifp)) + connected_up_ipv4 (ifp, ifc); + } + + return CMD_SUCCESS; +} + +int +ip_address_uninstall (struct vty *vty, struct interface *ifp, char *addr_str, + char *peer_str, char *label, int secondry) +{ + struct prefix_ipv4 cp; + struct connected *ifc; + int ret; + + /* Convert to prefix structure. */ + ret = str2prefix_ipv4 (addr_str, &cp); + if (ret <= 0) + { + vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check current interface address. */ + ifc = connected_check_ipv4 (ifp, (struct prefix *) &cp); + if (! ifc) + { + vty_out (vty, "%% Can't find address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* This is not configured address. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) + return CMD_WARNING; + + /* This is not real address or interface is not active. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL) + || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) + { + listnode_delete (ifp->connected, ifc); + connected_free (ifc); + return CMD_WARNING; + } + + /* This is real route. */ + ret = if_unset_prefix (ifp, ifc); + if (ret < 0) + { + vty_out (vty, "%% Can't unset interface IP address: %s.%s", + strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* Redistribute this information. */ + zebra_interface_address_delete_update (ifp, ifc); + + /* Remove connected route. */ + connected_down_ipv4 (ifp, ifc); + + /* Free address information. */ + listnode_delete (ifp->connected, ifc); + connected_free (ifc); + + return CMD_SUCCESS; +} + +DEFUN (ip_address, + ip_address_cmd, + "ip address A.B.C.D/M", + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP address (e.g. 10.0.0.1/8)\n") +{ + return ip_address_install (vty, vty->index, argv[0], NULL, NULL, 0); +} + +DEFUN (no_ip_address, + no_ip_address_cmd, + "no ip address A.B.C.D/M", + NO_STR + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP Address (e.g. 10.0.0.1/8)") +{ + return ip_address_uninstall (vty, vty->index, argv[0], NULL, NULL, 0); +} + +#ifdef HAVE_NETLINK +DEFUN (ip_address_secondary, + ip_address_secondary_cmd, + "ip address A.B.C.D/M secondary", + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP address (e.g. 10.0.0.1/8)\n" + "Secondary IP address\n") +{ + return ip_address_install (vty, vty->index, argv[0], NULL, NULL, 1); +} + +DEFUN (ip_address_label, + ip_address_label_cmd, + "ip address A.B.C.D/M label LINE", + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP address (e.g. 10.0.0.1/8)\n" + "Label of this address\n" + "Label\n") +{ + return ip_address_install (vty, vty->index, argv[0], NULL, argv[1], 1); +} + +DEFUN (no_ip_address_secondary, + no_ip_address_secondary_cmd, + "no ip address A.B.C.D/M secondary", + NO_STR + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP address (e.g. 10.0.0.1/8)\n" + "Secondary IP address\n") +{ + return ip_address_uninstall (vty, vty->index, argv[0], NULL, NULL, 1); +} + +DEFUN (no_ip_address_label, + no_ip_address_label_cmd, + "no ip address A.B.C.D/M label LINE", + NO_STR + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP address (e.g. 10.0.0.1/8)\n" + "Label of this address\n" + "Label\n") +{ + return ip_address_uninstall (vty, vty->index, argv[0], NULL, argv[1], 1); +} +#endif /* HAVE_NETLINK */ + +#ifdef HAVE_IPV6 +int +ipv6_address_install (struct vty *vty, struct interface *ifp, char *addr_str, + char *peer_str, char *label, int secondary) +{ + struct prefix_ipv6 cp; + struct connected *ifc; + struct prefix_ipv6 *p; + int ret; + + ret = str2prefix_ipv6 (addr_str, &cp); + if (ret <= 0) + { + vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); + return CMD_WARNING; + } + + ifc = connected_check_ipv6 (ifp, (struct prefix *) &cp); + if (! ifc) + { + ifc = connected_new (); + ifc->ifp = ifp; + + /* Address. */ + p = prefix_ipv6_new (); + *p = cp; + ifc->address = (struct prefix *) p; + + /* Secondary. */ + if (secondary) + SET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY); + + /* Label. */ + if (label) + ifc->label = strdup (label); + + /* Add to linked list. */ + listnode_add (ifp->connected, ifc); + } + + /* This address is configured from zebra. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) + SET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED); + + /* In case of this route need to install kernel. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL) + && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) + { + /* Some system need to up the interface to set IP address. */ + if (! if_is_up (ifp)) + { + if_set_flags (ifp, IFF_UP | IFF_RUNNING); + if_refresh (ifp); + } + + ret = if_prefix_add_ipv6 (ifp, ifc); + + if (ret < 0) + { + vty_out (vty, "%% Can't set interface IP address: %s.%s", + strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* IP address propery set. */ + SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + + /* Update interface address information to protocol daemon. */ + zebra_interface_address_add_update (ifp, ifc); + + /* If interface is up register connected route. */ + if (if_is_up(ifp)) + connected_up_ipv6 (ifp, ifc); + } + + return CMD_SUCCESS; +} + +int +ipv6_address_uninstall (struct vty *vty, struct interface *ifp, char *addr_str, + char *peer_str, char *label, int secondry) +{ + struct prefix_ipv6 cp; + struct connected *ifc; + int ret; + + /* Convert to prefix structure. */ + ret = str2prefix_ipv6 (addr_str, &cp); + if (ret <= 0) + { + vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check current interface address. */ + ifc = connected_check_ipv6 (ifp, (struct prefix *) &cp); + if (! ifc) + { + vty_out (vty, "%% Can't find address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* This is not configured address. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) + return CMD_WARNING; + + /* This is not real address or interface is not active. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL) + || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) + { + listnode_delete (ifp->connected, ifc); + connected_free (ifc); + return CMD_WARNING; + } + + /* This is real route. */ + ret = if_prefix_delete_ipv6 (ifp, ifc); + if (ret < 0) + { + vty_out (vty, "%% Can't unset interface IP address: %s.%s", + strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* Redistribute this information. */ + zebra_interface_address_delete_update (ifp, ifc); + + /* Remove connected route. */ + connected_down_ipv6 (ifp, ifc); + + /* Free address information. */ + listnode_delete (ifp->connected, ifc); + connected_free (ifc); + + return CMD_SUCCESS; +} + +DEFUN (ipv6_address, + ipv6_address_cmd, + "ipv6 address X:X::X:X/M", + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IPv6 address (e.g. 3ffe:506::1/48)\n") +{ + return ipv6_address_install (vty, vty->index, argv[0], NULL, NULL, 0); +} + +DEFUN (no_ipv6_address, + no_ipv6_address_cmd, + "no ipv6 address X:X::X:X/M", + NO_STR + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IPv6 address (e.g. 3ffe:506::1/48)\n") +{ + return ipv6_address_uninstall (vty, vty->index, argv[0], NULL, NULL, 0); +} +#endif /* HAVE_IPV6 */ + +#ifdef KAME +DEFUN (ip_tunnel, + ip_tunnel_cmd, + "ip tunnel IP_address IP_address", + "KAME ip tunneling configuration commands\n" + "Set FROM IP address and TO IP address\n") +{ + return CMD_SUCCESS; +} + +DEFUN (no_ip_tunnel, no_ip_tunnel_cmd, + "no ip tunnel", + NO_STR + "Set FROM IP address and TO IP address\n") +{ + return CMD_SUCCESS; +} +#endif /* KAME */ + +int +if_config_write (struct vty *vty) +{ + listnode node; + struct interface *ifp; + char buf[BUFSIZ]; + + for (node = listhead (iflist); node; nextnode (node)) + { + struct zebra_if *if_data; + listnode addrnode; + struct connected *ifc; + struct prefix *p; + + ifp = getdata (node); + if_data = ifp->info; + + vty_out (vty, "interface %s%s", ifp->name, + VTY_NEWLINE); + + if (ifp->desc) + vty_out (vty, " description %s%s", ifp->desc, + VTY_NEWLINE); + + /* Assign bandwidth here to avoid unnecessary interface flap + while processing config script */ + if (ifp->bandwidth != 0) + vty_out(vty, " bandwidth %u%s", ifp->bandwidth, VTY_NEWLINE); + + for (addrnode = listhead (ifp->connected); addrnode; nextnode (addrnode)) + { + ifc = getdata (addrnode); + if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) + { + p = ifc->address; + vty_out (vty, " ip%s address %s/%d", + p->family == AF_INET ? "" : "v6", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen); + + if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY)) + vty_out (vty, " secondary"); + + if (ifc->label) + vty_out (vty, " label %s", ifc->label); + + vty_out (vty, "%s", VTY_NEWLINE); + } + } + + if (if_data) + { + if (if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON) + vty_out (vty, " shutdown%s", VTY_NEWLINE); + + if (if_data->multicast != IF_ZEBRA_MULTICAST_UNSPEC) + vty_out (vty, " %smulticast%s", + if_data->multicast == IF_ZEBRA_MULTICAST_ON ? "" : "no ", + VTY_NEWLINE); + } + +#ifdef RTADV + rtadv_config_write (vty, ifp); +#endif /* RTADV */ + + vty_out (vty, "!%s", VTY_NEWLINE); + } + return 0; +} + +/* Allocate and initialize interface vector. */ +void +zebra_if_init () +{ + /* Initialize interface and new hook. */ + if_init (); + if_add_hook (IF_NEW_HOOK, if_zebra_new_hook); + if_add_hook (IF_DELETE_HOOK, if_zebra_delete_hook); + + /* Install configuration write function. */ + install_node (&interface_node, if_config_write); + + install_element (VIEW_NODE, &show_interface_cmd); + install_element (ENABLE_NODE, &show_interface_cmd); + install_element (CONFIG_NODE, &zebra_interface_cmd); + install_element (CONFIG_NODE, &no_zebra_interface_cmd); + install_default (INTERFACE_NODE); + install_element (INTERFACE_NODE, &interface_desc_cmd); + install_element (INTERFACE_NODE, &no_interface_desc_cmd); + install_element (INTERFACE_NODE, &multicast_cmd); + install_element (INTERFACE_NODE, &no_multicast_cmd); + install_element (INTERFACE_NODE, &shutdown_if_cmd); + install_element (INTERFACE_NODE, &no_shutdown_if_cmd); + install_element (INTERFACE_NODE, &bandwidth_if_cmd); + install_element (INTERFACE_NODE, &no_bandwidth_if_cmd); + install_element (INTERFACE_NODE, &no_bandwidth_if_val_cmd); + install_element (INTERFACE_NODE, &ip_address_cmd); + install_element (INTERFACE_NODE, &no_ip_address_cmd); +#ifdef HAVE_IPV6 + install_element (INTERFACE_NODE, &ipv6_address_cmd); + install_element (INTERFACE_NODE, &no_ipv6_address_cmd); +#endif /* HAVE_IPV6 */ +#ifdef KAME + install_element (INTERFACE_NODE, &ip_tunnel_cmd); + install_element (INTERFACE_NODE, &no_ip_tunnel_cmd); +#endif /* KAME */ +#ifdef HAVE_NETLINK + install_element (INTERFACE_NODE, &ip_address_secondary_cmd); + install_element (INTERFACE_NODE, &ip_address_label_cmd); + install_element (INTERFACE_NODE, &no_ip_address_secondary_cmd); + install_element (INTERFACE_NODE, &no_ip_address_label_cmd); +#endif /* HAVE_NETLINK */ +} diff --git a/zebra/interface.h b/zebra/interface.h new file mode 100644 index 00000000..dbfa8221 --- /dev/null +++ b/zebra/interface.h @@ -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 index 00000000..13afba29 --- /dev/null +++ b/zebra/ioctl.c @@ -0,0 +1,540 @@ +/* + * Common ioctl functions. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "linklist.h" +#include "if.h" +#include "prefix.h" +#include "ioctl.h" +#include "log.h" + +#include "zebra/rib.h" +#include "zebra/rt.h" + +/* clear and set interface name string */ +void +ifreq_set_name (struct ifreq *ifreq, struct interface *ifp) +{ + strncpy (ifreq->ifr_name, ifp->name, IFNAMSIZ); +} + +/* call ioctl system call */ +int +if_ioctl (u_long request, caddr_t buffer) +{ + int sock; + int ret = 0; + int err = 0; + + sock = socket (AF_INET, SOCK_DGRAM, 0); + if (sock < 0) + { + perror ("socket"); + exit (1); + } + + ret = ioctl (sock, request, buffer); + if (ret < 0) + { + err = errno; + } + close (sock); + + if (ret < 0) + { + errno = err; + return ret; + } + return 0; +} + +#ifdef HAVE_IPV6 +int +if_ioctl_ipv6 (u_long request, caddr_t buffer) +{ + int sock; + int ret = 0; + int err = 0; + + sock = socket (AF_INET6, SOCK_DGRAM, 0); + if (sock < 0) + { + perror ("socket"); + exit (1); + } + + ret = ioctl (sock, request, buffer); + if (ret < 0) + { + err = errno; + } + close (sock); + + if (ret < 0) + { + errno = err; + return ret; + } + return 0; +} +#endif /* HAVE_IPV6 */ + +/* + * get interface metric + * -- if value is not avaliable set -1 + */ +void +if_get_metric (struct interface *ifp) +{ +#ifdef SIOCGIFMETRIC + struct ifreq ifreq; + + ifreq_set_name (&ifreq, ifp); + + if (if_ioctl (SIOCGIFMETRIC, (caddr_t) &ifreq) < 0) + return; + ifp->metric = ifreq.ifr_metric; + if (ifp->metric == 0) + ifp->metric = 1; +#else /* SIOCGIFMETRIC */ + ifp->metric = -1; +#endif /* SIOCGIFMETRIC */ +} + +/* get interface MTU */ +void +if_get_mtu (struct interface *ifp) +{ + struct ifreq ifreq; + + ifreq_set_name (&ifreq, ifp); + +#if defined(SIOCGIFMTU) + if (if_ioctl (SIOCGIFMTU, (caddr_t) & ifreq) < 0) + { + zlog_info ("Can't lookup mtu by ioctl(SIOCGIFMTU)"); + ifp->mtu = -1; + return; + } + +#ifdef SUNOS_5 + ifp->mtu = ifreq.ifr_metric; +#else + ifp->mtu = ifreq.ifr_mtu; +#endif /* SUNOS_5 */ + +#else + zlog (NULL, LOG_INFO, "Can't lookup mtu on this system"); + ifp->mtu = -1; +#endif +} + +#ifdef HAVE_NETLINK +/* Interface address setting via netlink interface. */ +int +if_set_prefix (struct interface *ifp, struct connected *ifc) +{ + return kernel_address_add_ipv4 (ifp, ifc); +} + +/* Interface address is removed using netlink interface. */ +int +if_unset_prefix (struct interface *ifp, struct connected *ifc) +{ + return kernel_address_delete_ipv4 (ifp, ifc); +} +#else /* ! HAVE_NETLINK */ +#ifdef HAVE_IFALIASREQ +/* Set up interface's IP address, netmask (and broadcas? ). *BSD may + has ifaliasreq structure. */ +int +if_set_prefix (struct interface *ifp, struct connected *ifc) +{ + int ret; + struct ifaliasreq addreq; + struct sockaddr_in addr; + struct sockaddr_in mask; + struct prefix_ipv4 *p; + + p = (struct prefix_ipv4 *) ifc->address; + + memset (&addreq, 0, sizeof addreq); + strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + + memset (&addr, 0, sizeof (struct sockaddr_in)); + addr.sin_addr = p->prefix; + addr.sin_family = p->family; +#ifdef HAVE_SIN_LEN + addr.sin_len = sizeof (struct sockaddr_in); +#endif + memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in)); + + memset (&mask, 0, sizeof (struct sockaddr_in)); + masklen2ip (p->prefixlen, &mask.sin_addr); + mask.sin_family = p->family; +#ifdef HAVE_SIN_LEN + mask.sin_len = sizeof (struct sockaddr_in); +#endif + memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in)); + + ret = if_ioctl (SIOCAIFADDR, (caddr_t) &addreq); + if (ret < 0) + return ret; + return 0; +} + +/* Set up interface's IP address, netmask (and broadcas? ). *BSD may + has ifaliasreq structure. */ +int +if_unset_prefix (struct interface *ifp, struct connected *ifc) +{ + int ret; + struct ifaliasreq addreq; + struct sockaddr_in addr; + struct sockaddr_in mask; + struct prefix_ipv4 *p; + + p = (struct prefix_ipv4 *)ifc->address; + + memset (&addreq, 0, sizeof addreq); + strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + + memset (&addr, 0, sizeof (struct sockaddr_in)); + addr.sin_addr = p->prefix; + addr.sin_family = p->family; +#ifdef HAVE_SIN_LEN + addr.sin_len = sizeof (struct sockaddr_in); +#endif + memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in)); + + memset (&mask, 0, sizeof (struct sockaddr_in)); + masklen2ip (p->prefixlen, &mask.sin_addr); + mask.sin_family = p->family; +#ifdef HAVE_SIN_LEN + mask.sin_len = sizeof (struct sockaddr_in); +#endif + memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in)); + + ret = if_ioctl (SIOCDIFADDR, (caddr_t) &addreq); + if (ret < 0) + return ret; + return 0; +} +#else +/* Set up interface's address, netmask (and broadcas? ). Linux or + Solaris uses ifname:number semantics to set IP address aliases. */ +int +if_set_prefix (struct interface *ifp, struct connected *ifc) +{ + int ret; + struct ifreq ifreq; + struct sockaddr_in addr; + struct sockaddr_in broad; + struct sockaddr_in mask; + struct prefix_ipv4 ifaddr; + struct prefix_ipv4 *p; + + p = (struct prefix_ipv4 *) ifc->address; + + ifaddr = *p; + + ifreq_set_name (&ifreq, ifp); + + addr.sin_addr = p->prefix; + addr.sin_family = p->family; + memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in)); + ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq); + if (ret < 0) + return ret; + + /* We need mask for make broadcast addr. */ + masklen2ip (p->prefixlen, &mask.sin_addr); + + if (if_is_broadcast (ifp)) + { + apply_mask_ipv4 (&ifaddr); + addr.sin_addr = ifaddr.prefix; + + broad.sin_addr.s_addr = (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr); + broad.sin_family = p->family; + + memcpy (&ifreq.ifr_broadaddr, &broad, sizeof (struct sockaddr_in)); + ret = if_ioctl (SIOCSIFBRDADDR, (caddr_t) &ifreq); + if (ret < 0) + return ret; + } + + mask.sin_family = p->family; +#ifdef SUNOS_5 + memcpy (&mask, &ifreq.ifr_addr, sizeof (mask)); +#else + memcpy (&ifreq.ifr_netmask, &mask, sizeof (struct sockaddr_in)); +#endif /* SUNOS5 */ + ret = if_ioctl (SIOCSIFNETMASK, (caddr_t) &ifreq); + if (ret < 0) + return ret; + + return 0; +} + +/* Set up interface's address, netmask (and broadcas? ). Linux or + Solaris uses ifname:number semantics to set IP address aliases. */ +int +if_unset_prefix (struct interface *ifp, struct connected *ifc) +{ + int ret; + struct ifreq ifreq; + struct sockaddr_in addr; + struct prefix_ipv4 *p; + + p = (struct prefix_ipv4 *) ifc->address; + + ifreq_set_name (&ifreq, ifp); + + memset (&addr, 0, sizeof (struct sockaddr_in)); + addr.sin_family = p->family; + memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in)); + ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq); + if (ret < 0) + return ret; + + return 0; +} +#endif /* HAVE_IFALIASREQ */ +#endif /* HAVE_NETLINK */ + +/* get interface flags */ +void +if_get_flags (struct interface *ifp) +{ + int ret; + struct ifreq ifreq; + + ifreq_set_name (&ifreq, ifp); + + ret = if_ioctl (SIOCGIFFLAGS, (caddr_t) &ifreq); + if (ret < 0) + { + perror ("ioctl"); + return; + } + + ifp->flags = ifreq.ifr_flags & 0x0000ffff; +} + +/* Set interface flags */ +int +if_set_flags (struct interface *ifp, unsigned long flags) +{ + int ret; + struct ifreq ifreq; + + ifreq_set_name (&ifreq, ifp); + + ifreq.ifr_flags = ifp->flags; + ifreq.ifr_flags |= flags; + + ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq); + + if (ret < 0) + { + zlog_info ("can't set interface flags"); + return ret; + } + return 0; +} + +/* Unset interface's flag. */ +int +if_unset_flags (struct interface *ifp, unsigned long flags) +{ + int ret; + struct ifreq ifreq; + + ifreq_set_name (&ifreq, ifp); + + ifreq.ifr_flags = ifp->flags; + ifreq.ifr_flags &= ~flags; + + ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq); + + if (ret < 0) + { + zlog_info ("can't unset interface flags"); + return ret; + } + return 0; +} + +#ifdef HAVE_IPV6 + +#ifdef LINUX_IPV6 +#ifndef _LINUX_IN6_H +/* linux/include/net/ipv6.h */ +struct in6_ifreq +{ + struct in6_addr ifr6_addr; + u_int32_t ifr6_prefixlen; + int ifr6_ifindex; +}; +#endif /* _LINUX_IN6_H */ + +/* Interface's address add/delete functions. */ +int +if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc) +{ + int ret; + struct prefix_ipv6 *p; + struct in6_ifreq ifreq; + + p = (struct prefix_ipv6 *) ifc->address; + + memset (&ifreq, 0, sizeof (struct in6_ifreq)); + + memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr)); + ifreq.ifr6_ifindex = ifp->ifindex; + ifreq.ifr6_prefixlen = p->prefixlen; + + ret = if_ioctl_ipv6 (SIOCSIFADDR, (caddr_t) &ifreq); + + return ret; +} + +int +if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc) +{ + int ret; + struct prefix_ipv6 *p; + struct in6_ifreq ifreq; + + p = (struct prefix_ipv6 *) ifc->address; + + memset (&ifreq, 0, sizeof (struct in6_ifreq)); + + memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr)); + ifreq.ifr6_ifindex = ifp->ifindex; + ifreq.ifr6_prefixlen = p->prefixlen; + + ret = if_ioctl_ipv6 (SIOCDIFADDR, (caddr_t) &ifreq); + + return ret; +} +#else /* LINUX_IPV6 */ +#ifdef HAVE_IN6_ALIASREQ +#ifndef ND6_INFINITE_LIFETIME +#define ND6_INFINITE_LIFETIME 0xffffffffL +#endif /* ND6_INFINITE_LIFETIME */ +int +if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc) +{ + int ret; + struct in6_aliasreq addreq; + struct sockaddr_in6 addr; + struct sockaddr_in6 mask; + struct prefix_ipv6 *p; + + p = (struct prefix_ipv6 * ) ifc->address; + + memset (&addreq, 0, sizeof addreq); + strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + + memset (&addr, 0, sizeof (struct sockaddr_in6)); + addr.sin6_addr = p->prefix; + addr.sin6_family = p->family; +#ifdef HAVE_SIN_LEN + addr.sin6_len = sizeof (struct sockaddr_in6); +#endif + memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6)); + + memset (&mask, 0, sizeof (struct sockaddr_in6)); + masklen2ip6 (p->prefixlen, &mask.sin6_addr); + mask.sin6_family = p->family; +#ifdef HAVE_SIN_LEN + mask.sin6_len = sizeof (struct sockaddr_in6); +#endif + memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6)); + + addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; + addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; + + ret = if_ioctl_ipv6 (SIOCAIFADDR_IN6, (caddr_t) &addreq); + if (ret < 0) + return ret; + return 0; +} + +int +if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc) +{ + int ret; + struct in6_aliasreq addreq; + struct sockaddr_in6 addr; + struct sockaddr_in6 mask; + struct prefix_ipv6 *p; + + p = (struct prefix_ipv6 *) ifc->address; + + memset (&addreq, 0, sizeof addreq); + strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + + memset (&addr, 0, sizeof (struct sockaddr_in6)); + addr.sin6_addr = p->prefix; + addr.sin6_family = p->family; +#ifdef HAVE_SIN_LEN + addr.sin6_len = sizeof (struct sockaddr_in6); +#endif + memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6)); + + memset (&mask, 0, sizeof (struct sockaddr_in6)); + masklen2ip6 (p->prefixlen, &mask.sin6_addr); + mask.sin6_family = p->family; +#ifdef HAVE_SIN_LEN + mask.sin6_len = sizeof (struct sockaddr_in6); +#endif + memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6)); + + addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; + addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; + + ret = if_ioctl_ipv6 (SIOCDIFADDR_IN6, (caddr_t) &addreq); + if (ret < 0) + return ret; + return 0; +} +#else +int +if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc) +{ + return 0; +} + +int +if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc) +{ + return 0; +} +#endif /* HAVE_IN6_ALIASREQ */ + +#endif /* LINUX_IPV6 */ + +#endif /* HAVE_IPV6 */ diff --git a/zebra/ioctl.h b/zebra/ioctl.h new file mode 100644 index 00000000..157fc44e --- /dev/null +++ b/zebra/ioctl.h @@ -0,0 +1,46 @@ +/* + * Common ioctl functions. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_IOCTL_H +#define _ZEBRA_IOCTL_H + +/* Prototypes. */ +void ifreq_set_name (struct ifreq *, struct interface *); +int if_ioctl (u_long, caddr_t); + +int if_set_flags (struct interface *, unsigned long); +int if_unset_flags (struct interface *, unsigned long); +void if_get_flags (struct interface *); + +int if_set_prefix (struct interface *, struct connected *); +int if_unset_prefix (struct interface *, struct connected *); + +void if_get_metric (struct interface *); +void if_get_mtu (struct interface *); + +#ifdef HAVE_IPV6 +int if_prefix_add_ipv6 (struct interface *, struct connected *); +int if_prefix_delete_ipv6 (struct interface *, struct connected *); + +#endif /* HAVE_IPV6 */ + +#endif /* _ZEBRA_IOCTL_H */ diff --git a/zebra/ipforward.h b/zebra/ipforward.h new file mode 100644 index 00000000..a772337b --- /dev/null +++ b/zebra/ipforward.h @@ -0,0 +1,35 @@ +/* IP forward settings. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_IPFORWARD_H +#define _ZEBRA_IPFORWARD_H + +int ipforward (); +int ipforward_on (); +int ipforward_off (); + +#ifdef HAVE_IPV6 +int ipforward_ipv6 (); +int ipforward_ipv6_on (); +int ipforward_ipv6_off (); +#endif /* HAVE_IPV6 */ + +#endif /* _ZEBRA_IPFORWARD_H */ diff --git a/zebra/ipforward_aix.c b/zebra/ipforward_aix.c new file mode 100644 index 00000000..c79e7f1c --- /dev/null +++ b/zebra/ipforward_aix.c @@ -0,0 +1,64 @@ +/* + * ipforward value get function for aix. + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +int +ipforward () +{ + int fd, ret; + int af = AF_INET; + char netopt[] = "ipforwarding"; + struct optreq oq; + + fd = socket(af, SOCK_DGRAM, 0); + if (fd < 0) { + /* need logging here */ + return -1; + } + + strcpy (oq.name, netopt); + oq.getnext = 0; + + ret = ioctl (fd, SIOCGNETOPT, (caddr_t)&oq); + close(fd); + + if (ret < 0) { + /* need logging here */ + return -1; + } + + ret = atoi (oq.data); + return ret; +} + +int +ipforward_on () +{ + ; +} + +int +ipforward_off () +{ + ; +} diff --git a/zebra/ipforward_ews.c b/zebra/ipforward_ews.c new file mode 100644 index 00000000..c872000a --- /dev/null +++ b/zebra/ipforward_ews.c @@ -0,0 +1,60 @@ +/* + * Ipforward value get function for NEC EWS. + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +int +ipforward () +{ + int fd; + char buf[BUFSIZ]; + struct mioc_rksym rks; + + fd = open ("/dev/kmem", O_RDWR); + if (fd < 0) { + /* need logging here */ + return -1; + } + + rks.mirk_symname = "ipforwarding"; + rks.mirk_buf = buf; + rks.mirk_buflen = sizeof (int); + + if (ioctl (fd, MIOC_READKSYM, &rks) < 0) { + /* need logging here */ + return -1; + } + close (fd); + return *(int *)buf; +} + +int +ipforward_on () +{ + ; +} + +int +ipforward_off () +{ + ; +} diff --git a/zebra/ipforward_proc.c b/zebra/ipforward_proc.c new file mode 100644 index 00000000..eb8cef01 --- /dev/null +++ b/zebra/ipforward_proc.c @@ -0,0 +1,155 @@ +/* + * Fetch ipforward value by reading /proc filesystem. + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +char proc_net_snmp[] = "/proc/net/snmp"; + +static void +dropline (FILE *fp) +{ + int c; + + while ((c = getc (fp)) != '\n') + ; +} + +int +ipforward () +{ + FILE *fp; + int ipforwarding = 0; + char *pnt; + char buf[10]; + + fp = fopen (proc_net_snmp, "r"); + + if (fp == NULL) + return -1; + + /* We don't care about the first line. */ + dropline (fp); + + /* Get ip_statistics.IpForwarding : + 1 => ip forwarding enabled + 2 => ip forwarding off. */ + pnt = fgets (buf, 6, fp); + sscanf (buf, "Ip: %d", &ipforwarding); + + if (ipforwarding == 1) + return 1; + + return 0; +} + +/* char proc_ipv4_forwarding[] = "/proc/sys/net/ipv4/conf/all/forwarding"; */ +char proc_ipv4_forwarding[] = "/proc/sys/net/ipv4/ip_forward"; + +int +ipforward_on () +{ + FILE *fp; + + fp = fopen (proc_ipv4_forwarding, "w"); + + if (fp == NULL) + return -1; + + fprintf (fp, "1\n"); + + fclose (fp); + + return ipforward (); +} + +int +ipforward_off () +{ + FILE *fp; + + fp = fopen (proc_ipv4_forwarding, "w"); + + if (fp == NULL) + return -1; + + fprintf (fp, "0\n"); + + fclose (fp); + + return ipforward (); +} +#ifdef HAVE_IPV6 + +char proc_ipv6_forwarding[] = "/proc/sys/net/ipv6/conf/all/forwarding"; + +int +ipforward_ipv6 () +{ + FILE *fp; + char buf[5]; + int ipforwarding = 0; + + fp = fopen (proc_ipv6_forwarding, "r"); + + if (fp == NULL) + return -1; + + fgets (buf, 2, fp); + sscanf (buf, "%d", &ipforwarding); + + return ipforwarding; +} + +int +ipforward_ipv6_on () +{ + FILE *fp; + + fp = fopen (proc_ipv6_forwarding, "w"); + + if (fp == NULL) + return -1; + + fprintf (fp, "1\n"); + + fclose (fp); + + return ipforward_ipv6 (); +} + +int +ipforward_ipv6_off () +{ + FILE *fp; + + fp = fopen (proc_ipv6_forwarding, "w"); + + if (fp == NULL) + return -1; + + fprintf (fp, "0\n"); + + fclose (fp); + + return ipforward_ipv6 (); +} +#endif /* HAVE_IPV6 */ diff --git a/zebra/ipforward_solaris.c b/zebra/ipforward_solaris.c new file mode 100644 index 00000000..99b0e1a8 --- /dev/null +++ b/zebra/ipforward_solaris.c @@ -0,0 +1,77 @@ +/* + * ipforward value get function for solaris. + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "memory.h" + +int +ipforward () +{ + int fd, ret; + int ipforwarding = 0; + char forward[] = "ip_forwarding"; + char *buf; + struct strioctl si; + + buf = (char *) XMALLOC (MTYPE_TMP, sizeof forward + 1); + strcpy (buf, forward); + + fd = open ("/dev/ip", O_RDWR); + if (fd < 0) { + free (buf); + /* need logging here */ + /* "I can't get ipforwarding value because can't open /dev/ip" */ + return -1; + } + + si.ic_cmd = ND_GET; + si.ic_timout = 0; + si.ic_len = strlen (buf) + 1; + si.ic_dp = (caddr_t) buf; + + ret = ioctl (fd, I_STR, &si); + close (fd); + + if (ret < 0) { + free (buf); + /* need logging here */ + /* can't get ipforwarding value : ioctl failed */ + return -1; + } + + ipforwarding = atoi (buf); + free (buf); + return ipforwarding; +} + +int +ipforward_on () +{ + return 0; +} + +int +ipforward_off () +{ + return 0; +} diff --git a/zebra/ipforward_sysctl.c b/zebra/ipforward_sysctl.c new file mode 100644 index 00000000..828eb865 --- /dev/null +++ b/zebra/ipforward_sysctl.c @@ -0,0 +1,146 @@ +/* IP forward control by sysctl function. + * Copyright (C) 1997, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#ifdef NRL +#include +#endif /* NRL */ + +#include "log.h" + +#define MIB_SIZ 4 + +/* IPv4 forwarding control MIB. */ +int mib[MIB_SIZ] = +{ + CTL_NET, + PF_INET, + IPPROTO_IP, + IPCTL_FORWARDING +}; + +int +ipforward () +{ + int len; + int ipforwarding = 0; + + len = sizeof ipforwarding; + if (sysctl (mib, MIB_SIZ, &ipforwarding, &len, 0, 0) < 0) + { + zlog_warn ("Can't get ipforwarding value"); + return -1; + } + return ipforwarding; +} + +int +ipforward_on () +{ + int len; + int ipforwarding = 1; + + len = sizeof ipforwarding; + if (sysctl (mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) + { + zlog_warn ("Can't set ipforwarding on"); + return -1; + } + return ipforwarding; +} + +int +ipforward_off () +{ + int len; + int ipforwarding = 0; + + len = sizeof ipforwarding; + if (sysctl (mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) + { + zlog_warn ("Can't set ipforwarding on"); + return -1; + } + return ipforwarding; +} + +#ifdef HAVE_IPV6 + +/* IPv6 forwarding control MIB. */ +int mib_ipv6[MIB_SIZ] = +{ + CTL_NET, + PF_INET6, +#if defined(KAME) || (defined(__bsdi__) && _BSDI_VERSION >= 199802 ) || defined(NRL) + IPPROTO_IPV6, + IPV6CTL_FORWARDING +#else /* NOT KAME */ + IPPROTO_IP, + IP6CTL_FORWARDING +#endif /* KAME */ +}; + +int +ipforward_ipv6 () +{ + int len; + int ip6forwarding = 0; + + len = sizeof ip6forwarding; + if (sysctl (mib_ipv6, MIB_SIZ, &ip6forwarding, &len, 0, 0) < 0) + { + zlog_warn ("can't get ip6forwarding value"); + return -1; + } + return ip6forwarding; +} + +int +ipforward_ipv6_on () +{ + int len; + int ip6forwarding = 1; + + len = sizeof ip6forwarding; + if (sysctl (mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0) + { + zlog_warn ("can't get ip6forwarding value"); + return -1; + } + return ip6forwarding; +} + +int +ipforward_ipv6_off () +{ + int len; + int ip6forwarding = 0; + + len = sizeof ip6forwarding; + if (sysctl (mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0) + { + zlog_warn ("can't get ip6forwarding value"); + return -1; + } + return ip6forwarding; +} +#endif /* HAVE_IPV6 */ diff --git a/zebra/irdp.c b/zebra/irdp.c new file mode 100644 index 00000000..1b3bf232 --- /dev/null +++ b/zebra/irdp.c @@ -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 + +#include + +#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); + } +} + +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; +} + +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 index 00000000..0fad581d --- /dev/null +++ b/zebra/irdp.h @@ -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 index 00000000..23b2153e --- /dev/null +++ b/zebra/kernel_netlink.c @@ -0,0 +1,20 @@ +/* Kernel communication using netlink interface. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c new file mode 100644 index 00000000..a47f4f63 --- /dev/null +++ b/zebra/kernel_socket.c @@ -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 + +#include "if.h" +#include "prefix.h" +#include "sockunion.h" +#include "connected.h" +#include "memory.h" +#include "ioctl.h" +#include "log.h" +#include "str.h" +#include "table.h" +#include "rib.h" + +#include "zebra/interface.h" +#include "zebra/zserv.h" +#include "zebra/debug.h" + +/* Socket length roundup function. */ +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) + +/* And this macro is wrapper for handling sa_len. */ +#ifdef HAVE_SA_LEN +#define WRAPUP(X) ROUNDUP(((struct sockaddr *)(X))->sa_len) +#else +#define WRAPUP(X) ROUNDUP(sizeof (struct sockaddr)) +#endif /* HAVE_SA_LEN */ + +/* Routing socket message types. */ +struct message rtm_type_str[] = +{ + {RTM_ADD, "RTM_ADD"}, + {RTM_DELETE, "RTM_DELETE"}, + {RTM_CHANGE, "RTM_CHANGE"}, + {RTM_GET, "RTM_GET"}, + {RTM_LOSING, "RTM_LOSING"}, + {RTM_REDIRECT, "RTM_REDIRECT"}, + {RTM_MISS, "RTM_MISS"}, + {RTM_LOCK, "RTM_LOCK"}, + {RTM_OLDADD, "RTM_OLDADD"}, + {RTM_OLDDEL, "RTM_OLDDEL"}, + {RTM_RESOLVE, "RTM_RESOLVE"}, + {RTM_NEWADDR, "RTM_NEWADDR"}, + {RTM_DELADDR, "RTM_DELADDR"}, + {RTM_IFINFO, "RTM_IFINFO"}, +#ifdef RTM_OIFINFO + {RTM_OIFINFO, "RTM_OIFINFO"}, +#endif /* RTM_OIFINFO */ +#ifdef RTM_NEWMADDR + {RTM_NEWMADDR, "RTM_NEWMADDR"}, +#endif /* RTM_NEWMADDR */ +#ifdef RTM_DELMADDR + {RTM_DELMADDR, "RTM_DELMADDR"}, +#endif /* RTM_DELMADDR */ +#ifdef RTM_IFANNOUNCE + {RTM_IFANNOUNCE, "RTM_IFANNOUNCE"}, +#endif /* RTM_IFANNOUNCE */ + {0, NULL} +}; + +struct message rtm_flag_str[] = +{ + {RTF_UP, "UP"}, + {RTF_GATEWAY, "GATEWAY"}, + {RTF_HOST, "HOST"}, + {RTF_REJECT, "REJECT"}, + {RTF_DYNAMIC, "DYNAMIC"}, + {RTF_MODIFIED, "MODIFIED"}, + {RTF_DONE, "DONE"}, +#ifdef RTF_MASK + {RTF_MASK, "MASK"}, +#endif /* RTF_MASK */ + {RTF_CLONING, "CLONING"}, + {RTF_XRESOLVE, "XRESOLVE"}, + {RTF_LLINFO, "LLINFO"}, + {RTF_STATIC, "STATIC"}, + {RTF_BLACKHOLE, "BLACKHOLE"}, + {RTF_PROTO1, "PROTO1"}, + {RTF_PROTO2, "PROTO2"}, +#ifdef RTF_PRCLONING + {RTF_PRCLONING, "PRCLONING"}, +#endif /* RTF_PRCLONING */ +#ifdef RTF_WASCLONED + {RTF_WASCLONED, "WASCLONED"}, +#endif /* RTF_WASCLONED */ +#ifdef RTF_PROTO3 + {RTF_PROTO3, "PROTO3"}, +#endif /* RTF_PROTO3 */ +#ifdef RTF_PINNED + {RTF_PINNED, "PINNED"}, +#endif /* RTF_PINNED */ +#ifdef RTF_LOCAL + {RTF_LOCAL, "LOCAL"}, +#endif /* RTF_LOCAL */ +#ifdef RTF_BROADCAST + {RTF_BROADCAST, "BROADCAST"}, +#endif /* RTF_BROADCAST */ +#ifdef RTF_MULTICAST + {RTF_MULTICAST, "MULTICAST"}, +#endif /* RTF_MULTICAST */ + {0, NULL} +}; + +/* Kernel routing update socket. */ +int routing_sock = -1; + +/* Yes I'm checking ugly routing socket behavior. */ +/* #define DEBUG */ + +/* Supported address family check. */ +static int +af_check (int family) +{ + if (family == AF_INET) + return 1; +#ifdef HAVE_IPV6 + if (family == AF_INET6) + return 1; +#endif /* HAVE_IPV6 */ + return 0; +} + +/* Dump routing table flag for debug purpose. */ +void +rtm_flag_dump (int flag) +{ + struct message *mes; + static char buf[BUFSIZ]; + + for (mes = rtm_flag_str; mes->key != 0; mes++) + { + if (mes->key & flag) + { + strlcat (buf, mes->str, BUFSIZ); + strlcat (buf, " ", BUFSIZ); + } + } + zlog_info ("Kernel: %s", buf); +} + +#ifdef RTM_IFANNOUNCE +/* Interface adding function */ +int +ifan_read (struct if_announcemsghdr *ifan) +{ + struct interface *ifp; + + ifp = if_lookup_by_index (ifan->ifan_index); + if (ifp == NULL && ifan->ifan_what == IFAN_ARRIVAL) + { + /* Create Interface */ + ifp = if_get_by_name (ifan->ifan_name); + ifp->ifindex = ifan->ifan_index; + + if_add_update (ifp); + } + else if (ifp != NULL && ifan->ifan_what == IFAN_DEPARTURE) + { + if_delete_update (ifp); + if_delete (ifp); + } + + if_get_flags (ifp); + if_get_mtu (ifp); + if_get_metric (ifp); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("interface %s index %d", ifp->name, ifp->ifindex); + + return 0; +} +#endif /* RTM_IFANNOUNCE */ + +/* Interface adding function called from interface_list. */ +int +ifm_read (struct if_msghdr *ifm) +{ + struct interface *ifp; + struct sockaddr_dl *sdl = NULL; + + sdl = (struct sockaddr_dl *)(ifm + 1); + + /* Use sdl index. */ + ifp = if_lookup_by_index (ifm->ifm_index); + + if (ifp == NULL) + { + /* Check interface's address.*/ + if (! (ifm->ifm_addrs & RTA_IFP)) + { + zlog_warn ("There must be RTA_IFP address for ifindex %d\n", + ifm->ifm_index); + return -1; + } + + ifp = if_create (); + + strncpy (ifp->name, sdl->sdl_data, sdl->sdl_nlen); + ifp->ifindex = ifm->ifm_index; + ifp->flags = ifm->ifm_flags; +#if defined(__bsdi__) + if_kvm_get_mtu (ifp); +#else + if_get_mtu (ifp); +#endif /* __bsdi__ */ + if_get_metric (ifp); + + /* Fetch hardware address. */ + if (sdl->sdl_family != AF_LINK) + { + zlog_warn ("sockaddr_dl->sdl_family is not AF_LINK"); + return -1; + } + memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl)); + + if_add_update (ifp); + } + else + { + /* There is a case of promisc, allmulti flag modification. */ + if (if_is_up (ifp)) + { + ifp->flags = ifm->ifm_flags; + if (! if_is_up (ifp)) + if_down (ifp); + } + else + { + ifp->flags = ifm->ifm_flags; + if (if_is_up (ifp)) + if_up (ifp); + } + } + +#ifdef HAVE_NET_RT_IFLIST + ifp->stats = ifm->ifm_data; +#endif /* HAVE_NET_RT_IFLIST */ + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("interface %s index %d", ifp->name, ifp->ifindex); + + return 0; +} + +/* Address read from struct ifa_msghdr. */ +void +ifam_read_mesg (struct ifa_msghdr *ifm, + union sockunion *addr, + union sockunion *mask, + union sockunion *dest) +{ + caddr_t pnt, end; + + pnt = (caddr_t)(ifm + 1); + end = ((caddr_t)ifm) + ifm->ifam_msglen; + +#define IFAMADDRGET(X,R) \ + if (ifm->ifam_addrs & (R)) \ + { \ + int len = WRAPUP(pnt); \ + if (((X) != NULL) && af_check (((struct sockaddr *)pnt)->sa_family)) \ + memcpy ((caddr_t)(X), pnt, len); \ + pnt += len; \ + } +#define IFAMMASKGET(X,R) \ + if (ifm->ifam_addrs & (R)) \ + { \ + int len = WRAPUP(pnt); \ + if ((X) != NULL) \ + memcpy ((caddr_t)(X), pnt, len); \ + pnt += len; \ + } + + /* Be sure structure is cleared */ + memset (mask, 0, sizeof (union sockunion)); + memset (addr, 0, sizeof (union sockunion)); + memset (dest, 0, sizeof (union sockunion)); + + /* We fetch each socket variable into sockunion. */ + IFAMADDRGET (NULL, RTA_DST); + IFAMADDRGET (NULL, RTA_GATEWAY); + IFAMMASKGET (mask, RTA_NETMASK); + IFAMADDRGET (NULL, RTA_GENMASK); + IFAMADDRGET (NULL, RTA_IFP); + IFAMADDRGET (addr, RTA_IFA); + IFAMADDRGET (NULL, RTA_AUTHOR); + IFAMADDRGET (dest, RTA_BRD); + + /* Assert read up end point matches to end point */ + if (pnt != end) + zlog_warn ("ifam_read() 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; +} + +/* 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; +} + + +#include "thread.h" +#include "zebra/zserv.h" + +extern struct thread_master *master; + +/* For debug purpose. */ +void +rtmsg_debug (struct rt_msghdr *rtm) +{ + char *type = "Unknown"; + struct message *mes; + + for (mes = rtm_type_str; mes->str; mes++) + if (mes->key == rtm->rtm_type) + { + type = mes->str; + break; + } + + zlog_info ("Kernel: Len: %d Type: %s", rtm->rtm_msglen, type); + rtm_flag_dump (rtm->rtm_flags); + zlog_info ("Kernel: message seq %d", rtm->rtm_seq); + zlog_info ("Kernel: pid %d", rtm->rtm_pid); +} + +/* This is pretty gross, better suggestions welcome -- mhandler */ +#ifndef RTAX_MAX +#ifdef RTA_NUMBITS +#define RTAX_MAX RTA_NUMBITS +#else +#define RTAX_MAX 8 +#endif /* RTA_NUMBITS */ +#endif /* RTAX_MAX */ + +/* Kernel routing table and interface updates via routing socket. */ +int +kernel_read (struct thread *thread) +{ + int sock; + int nbytes; + struct rt_msghdr *rtm; + + union + { + /* Routing information. */ + struct + { + struct rt_msghdr rtm; + struct sockaddr addr[RTAX_MAX]; + } r; + + /* Interface information. */ + struct + { + struct if_msghdr ifm; + struct sockaddr addr[RTAX_MAX]; + } im; + + /* Interface address information. */ + struct + { + struct ifa_msghdr ifa; + struct sockaddr addr[RTAX_MAX]; + } ia; + +#ifdef RTM_IFANNOUNCE + /* Interface arrival/departure */ + struct + { + struct if_announcemsghdr ifan; + struct sockaddr addr[RTAX_MAX]; + } ian; +#endif /* RTM_IFANNOUNCE */ + + } buf; + + /* Fetch routing socket. */ + sock = THREAD_FD (thread); + + nbytes= read (sock, &buf, sizeof buf); + + if (nbytes <= 0) + { + if (nbytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN) + zlog_warn ("routing socket error: %s", strerror (errno)); + return 0; + } + + thread_add_read (master, kernel_read, NULL, sock); + +#ifdef DEBUG + rtmsg_debug (&buf.r.rtm); +#endif /* DEBUG */ + + rtm = &buf.r.rtm; + + switch (rtm->rtm_type) + { + case RTM_ADD: + case RTM_DELETE: + rtm_read (rtm); + break; + case RTM_IFINFO: + ifm_read (&buf.im.ifm); + break; + case RTM_NEWADDR: + case RTM_DELADDR: + ifam_read (&buf.ia.ifa); + break; +#ifdef RTM_IFANNOUNCE + case RTM_IFANNOUNCE: + ifan_read (&buf.ian.ifan); + break; +#endif /* RTM_IFANNOUNCE */ + default: + break; + } + return 0; +} + +/* Make routing socket. */ +void +routing_socket () +{ + routing_sock = socket (AF_ROUTE, SOCK_RAW, 0); + + if (routing_sock < 0) + { + zlog_warn ("Can't init kernel routing socket"); + return; + } + + if (fcntl (routing_sock, F_SETFL, O_NONBLOCK) < 0) + zlog_warn ("Can't set O_NONBLOCK to routing socket"); + + /* kernel_read needs rewrite. */ + thread_add_read (master, kernel_read, NULL, routing_sock); +} + +/* Exported interface function. This function simply calls + routing_socket (). */ +void +kernel_init () +{ + routing_socket (); +} diff --git a/zebra/main.c b/zebra/main.c new file mode 100644 index 00000000..25d8b6de --- /dev/null +++ b/zebra/main.c @@ -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 + +#include "version.h" +#include "getopt.h" +#include "command.h" +#include "thread.h" +#include "filter.h" +#include "memory.h" +#include "prefix.h" +#include "log.h" + +#include "zebra/rib.h" +#include "zebra/zserv.h" +#include "zebra/debug.h" +#include "zebra/rib.h" + +/* Master of threads. */ +struct thread_master *master; + +/* process id. */ +pid_t old_pid; +pid_t pid; + +/* Route retain mode flag. */ +int retain_mode = 0; + +/* Don't delete kernel route. */ +int keep_kernel_mode = 0; + +/* Command line options. */ +struct option longopts[] = +{ + { "batch", no_argument, NULL, 'b'}, + { "daemon", no_argument, NULL, 'd'}, + { "keep_kernel", no_argument, NULL, 'k'}, + { "log_mode", no_argument, NULL, 'l'}, + { "config_file", required_argument, NULL, 'f'}, + { "pid_file", required_argument, NULL, 'i'}, + { "help", no_argument, NULL, 'h'}, + { "vty_addr", required_argument, NULL, 'A'}, + { "vty_port", required_argument, NULL, 'P'}, + { "retain", no_argument, NULL, 'r'}, + { "version", no_argument, NULL, 'v'}, + { 0 } +}; + +/* Default configuration file path. */ +char config_current[] = DEFAULT_CONFIG_FILE; +char config_default[] = SYSCONFDIR DEFAULT_CONFIG_FILE; + +/* Process ID saved for use by init system */ +char *pid_file = PATH_ZEBRA_PID; + +/* Help information display. */ +static void +usage (char *progname, int status) +{ + if (status != 0) + fprintf (stderr, "Try `%s --help' for more information.\n", progname); + else + { + printf ("Usage : %s [OPTION...]\n\n\ +Daemon which manages kernel routing table management and \ +redistribution between different routing protocols.\n\n\ +-b, --batch Runs in batch mode\n\ +-d, --daemon Runs in daemon mode\n\ +-f, --config_file Set configuration file name\n\ +-i, --pid_file Set process identifier file name\n\ +-k, --keep_kernel Don't delete old routes which installed by zebra.\n\ +-l, --log_mode Set verbose log mode flag\n\ +-A, --vty_addr Set vty's bind address\n\ +-P, --vty_port Set vty's port number\n\ +-r, --retain When program terminates, retain added route by zebra.\n\ +-v, --version Print program version\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); + } + + exit (status); +} + +/* SIGHUP handler. */ +void +sighup (int sig) +{ + zlog_info ("SIGHUP received"); + + /* Reload of config file. */ + ; +} + +/* SIGINT handler. */ +void +sigint (int sig) +{ + /* Decrared in rib.c */ + void rib_close (); + + zlog_info ("Terminating on signal"); + + if (!retain_mode) + rib_close (); + + exit (0); +} + +/* SIGUSR1 handler. */ +void +sigusr1 (int sig) +{ + zlog_rotate (NULL); +} + +/* Signale wrapper. */ +RETSIGTYPE * +signal_set (int signo, void (*func)(int)) +{ + int ret; + struct sigaction sig; + struct sigaction osig; + + sig.sa_handler = func; + sigemptyset (&sig.sa_mask); + sig.sa_flags = 0; +#ifdef SA_RESTART + sig.sa_flags |= SA_RESTART; +#endif /* SA_RESTART */ + + ret = sigaction (signo, &sig, &osig); + + if (ret < 0) + return (SIG_ERR); + else + return (osig.sa_handler); +} + +/* Initialization of signal handles. */ +void +signal_init () +{ + signal_set (SIGHUP, sighup); + signal_set (SIGINT, sigint); + signal_set (SIGTERM, sigint); + signal_set (SIGPIPE, SIG_IGN); + signal_set (SIGUSR1, sigusr1); +} + +/* Main startup routine. */ +int +main (int argc, char **argv) +{ + char *p; + char *vty_addr = NULL; + int vty_port = 0; + int batch_mode = 0; + int daemon_mode = 0; + char *config_file = NULL; + char *progname; + struct thread thread; + void rib_weed_tables (); + void zebra_vty_init (); + + /* Set umask before anything for security */ + umask (0027); + + /* preserve my name */ + progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + + zlog_default = openzlog (progname, ZLOG_STDOUT, ZLOG_ZEBRA, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + + while (1) + { + int opt; + + opt = getopt_long (argc, argv, "bdklf:hA:P:rv", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + case 'b': + batch_mode = 1; + case 'd': + daemon_mode = 1; + break; + case 'k': + keep_kernel_mode = 1; + break; + case 'l': + /* log_mode = 1; */ + break; + case 'f': + config_file = optarg; + break; + case 'A': + vty_addr = optarg; + break; + case 'i': + pid_file = optarg; + break; + case 'P': + vty_port = atoi (optarg); + break; + case 'r': + retain_mode = 1; + break; + case 'v': + print_version (progname); + exit (0); + break; + case 'h': + usage (progname, 0); + break; + default: + usage (progname, 1); + break; + } + } + + /* Make master thread emulator. */ + master = thread_master_create (); + + /* Vty related initialize. */ + signal_init (); + cmd_init (1); + vty_init (); + memory_init (); + + /* Zebra related initialize. */ + zebra_init (); + rib_init (); + zebra_if_init (); + zebra_debug_init (); + zebra_vty_init (); + access_list_init (); + rtadv_init (); + + /* For debug purpose. */ + /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */ + + /* Make kernel routing socket. */ + kernel_init (); + interface_list (); + route_read (); + + /* Sort VTY commands. */ + sort_node (); + +#ifdef HAVE_SNMP + zebra_snmp_init (); +#endif /* HAVE_SNMP */ + + /* Clean up self inserted route. */ + if (! keep_kernel_mode) + rib_sweep_route (); + + /* Configuration file read*/ + vty_read_config (config_file, config_current, config_default); + + /* Clean up rib. */ + rib_weed_tables (); + + /* Exit when zebra is working in batch mode. */ + if (batch_mode) + exit (0); + + /* Needed for BSD routing socket. */ + old_pid = getpid (); + + /* Daemonize. */ + if (daemon_mode) + daemon (0, 0); + + /* Output pid of zebra. */ + pid_output (pid_file); + + /* Needed for BSD routing socket. */ + pid = getpid (); + + /* Make vty server socket. */ + vty_serv_sock (vty_addr, + vty_port ? vty_port : ZEBRA_VTY_PORT, ZEBRA_VTYSH_PATH); + + while (thread_fetch (master, &thread)) + thread_call (&thread); + + /* Not reached... */ + exit (0); +} diff --git a/zebra/mtu_kvm.c b/zebra/mtu_kvm.c new file mode 100644 index 00000000..3731dab6 --- /dev/null +++ b/zebra/mtu_kvm.c @@ -0,0 +1,97 @@ +/* MTU get using kvm_read. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include +#include +#include + +#include "if.h" + +/* get interface MTU to use kvm_read */ +void +if_kvm_get_mtu (struct interface *ifp) +{ + kvm_t *kvmd; + struct ifnet ifnet; + unsigned long ifnetaddr; + int len; + + char ifname[IFNAMSIZ]; + char tname[INTERFACE_NAMSIZ + 1]; + char buf[_POSIX2_LINE_MAX]; + + struct nlist nl[] = + { + {"_ifnet"}, + {""} + }; + + ifp->mtu = -1; + + kvmd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, buf); + + if (kvmd == NULL) + return ; + + kvm_nlist(kvmd, nl); + + ifnetaddr = nl[0].n_value; + + if (kvm_read(kvmd, ifnetaddr, (char *)&ifnetaddr, sizeof ifnetaddr) < 0) + { + kvm_close (kvmd); + return ; + } + + while(ifnetaddr != 0) + { + if (kvm_read (kvmd, ifnetaddr, (char *)&ifnet, sizeof ifnet) < 0) + { + kvm_close (kvmd); + return ; + } + + if (kvm_read (kvmd, (u_long)ifnet.if_name, ifname, IFNAMSIZ) < 0) + { + kvm_close (kvmd); + return ; + } + + len = snprintf (tname, INTERFACE_NAMSIZ + 1, + "%s%d", ifname, ifnet.if_unit); + + if (strncmp (tname, ifp->name, len) == 0) + break; + + ifnetaddr = (u_long)ifnet.if_next; + } + + kvm_close (kvmd); + + if (ifnetaddr == 0) + { + return ; + } + + ifp->mtu = ifnet.if_mtu; +} diff --git a/zebra/redistribute.c b/zebra/redistribute.c new file mode 100644 index 00000000..a3d4bad1 --- /dev/null +++ b/zebra/redistribute.c @@ -0,0 +1,410 @@ +/* Redistribution Handler + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "vector.h" +#include "vty.h" +#include "command.h" +#include "prefix.h" +#include "table.h" +#include "stream.h" +#include "zclient.h" +#include "linklist.h" +#include "log.h" + +#include "zebra/rib.h" +#include "zebra/zserv.h" +#include "zebra/redistribute.h" +#include "zebra/debug.h" + +int +zebra_check_addr (struct prefix *p) +{ + if (p->family == AF_INET) + { + u_int32_t addr; + + addr = p->u.prefix4.s_addr; + addr = ntohl (addr); + + if (IPV4_NET127 (addr) || IN_CLASSD (addr)) + return 0; + } +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + { + if (IN6_IS_ADDR_LOOPBACK (&p->u.prefix6)) + return 0; + if (IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) + return 0; + } +#endif /* HAVE_IPV6 */ + return 1; +} + +int +is_default (struct prefix *p) +{ + if (p->family == AF_INET) + if (p->u.prefix4.s_addr == 0 && p->prefixlen == 0) + return 1; +#ifdef HAVE_IPV6 +#if 0 /* IPv6 default separation is now pending until protocol daemon + can handle that. */ + if (p->family == AF_INET6) + if (IN6_IS_ADDR_UNSPECIFIED (&p->u.prefix6) && p->prefixlen == 0) + return 1; +#endif /* 0 */ +#endif /* HAVE_IPV6 */ + return 0; +} + +void +zebra_redistribute_default (struct zserv *client) +{ + struct prefix_ipv4 p; + struct route_table *table; + struct route_node *rn; + struct rib *newrib; +#ifdef HAVE_IPV6 + struct prefix_ipv6 p6; +#endif /* HAVE_IPV6 */ + + + /* Lookup default route. */ + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (table) + { + rn = route_node_lookup (table, (struct prefix *)&p); + if (rn) + { + for (newrib = rn->info; newrib; newrib = newrib->next) + if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) + && newrib->distance != DISTANCE_INFINITY) + zsend_ipv4_add_multipath (client, &rn->p, newrib); + route_unlock_node (rn); + } + } + +#ifdef HAVE_IPV6 + /* Lookup default route. */ + memset (&p6, 0, sizeof (struct prefix_ipv6)); + p6.family = AF_INET6; + + /* Lookup table. */ + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (table) + { + rn = route_node_lookup (table, (struct prefix *)&p6); + if (rn) + { + for (newrib = rn->info; newrib; newrib = newrib->next) + if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) + && newrib->distance != DISTANCE_INFINITY) + zsend_ipv6_add_multipath (client, &rn->p, newrib); + route_unlock_node (rn); + } + } +#endif /* HAVE_IPV6 */ +} + +/* Redistribute routes. */ +void +zebra_redistribute (struct zserv *client, int type) +{ + struct rib *newrib; + struct route_table *table; + struct route_node *rn; + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (table) + for (rn = route_top (table); rn; rn = route_next (rn)) + for (newrib = rn->info; newrib; newrib = newrib->next) + if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) + && newrib->type == type + && newrib->distance != DISTANCE_INFINITY + && zebra_check_addr (&rn->p)) + zsend_ipv4_add_multipath (client, &rn->p, newrib); + +#ifdef HAVE_IPV6 + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (table) + for (rn = route_top (table); rn; rn = route_next (rn)) + for (newrib = rn->info; newrib; newrib = newrib->next) + if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) + && newrib->type == type + && newrib->distance != DISTANCE_INFINITY + && zebra_check_addr (&rn->p)) + zsend_ipv6_add_multipath (client, &rn->p, newrib); +#endif /* HAVE_IPV6 */ +} + +extern list client_list; + +void +redistribute_add (struct prefix *p, struct rib *rib) +{ + listnode node; + struct zserv *client; + + for (node = listhead (client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + { + if (is_default (p)) + { + if (client->redist_default || client->redist[rib->type]) + { + if (p->family == AF_INET) + zsend_ipv4_add_multipath (client, p, rib); +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + zsend_ipv6_add_multipath (client, p, rib); +#endif /* HAVE_IPV6 */ + } + } + else if (client->redist[rib->type]) + { + if (p->family == AF_INET) + zsend_ipv4_add_multipath (client, p, rib); +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + zsend_ipv6_add_multipath (client, p, rib); +#endif /* HAVE_IPV6 */ + } + } +} + +void +redistribute_delete (struct prefix *p, struct rib *rib) +{ + listnode node; + struct zserv *client; + + /* Add DISTANCE_INFINITY check. */ + if (rib->distance == DISTANCE_INFINITY) + return; + + for (node = listhead (client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + { + if (is_default (p)) + { + if (client->redist_default || client->redist[rib->type]) + { + if (p->family == AF_INET) + zsend_ipv4_delete_multipath (client, p, rib); +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + zsend_ipv6_delete_multipath (client, p, rib); +#endif /* HAVE_IPV6 */ + } + } + else if (client->redist[rib->type]) + { + if (p->family == AF_INET) + zsend_ipv4_delete_multipath (client, p, rib); +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + zsend_ipv6_delete_multipath (client, p, rib); +#endif /* HAVE_IPV6 */ + } + } +} + +void +zebra_redistribute_add (int command, struct zserv *client, int length) +{ + int type; + + type = stream_getc (client->ibuf); + + switch (type) + { + case ZEBRA_ROUTE_KERNEL: + case ZEBRA_ROUTE_CONNECT: + case ZEBRA_ROUTE_STATIC: + case ZEBRA_ROUTE_RIP: + case ZEBRA_ROUTE_RIPNG: + case ZEBRA_ROUTE_OSPF: + case ZEBRA_ROUTE_OSPF6: + case ZEBRA_ROUTE_BGP: + if (! client->redist[type]) + { + client->redist[type] = 1; + zebra_redistribute (client, type); + } + break; + default: + break; + } +} + +void +zebra_redistribute_delete (int command, struct zserv *client, int length) +{ + int type; + + type = stream_getc (client->ibuf); + + switch (type) + { + case ZEBRA_ROUTE_KERNEL: + case ZEBRA_ROUTE_CONNECT: + case ZEBRA_ROUTE_STATIC: + case ZEBRA_ROUTE_RIP: + case ZEBRA_ROUTE_RIPNG: + case ZEBRA_ROUTE_OSPF: + case ZEBRA_ROUTE_OSPF6: + case ZEBRA_ROUTE_BGP: + client->redist[type] = 0; + break; + default: + break; + } +} + +void +zebra_redistribute_default_add (int command, struct zserv *client, int length) +{ + client->redist_default = 1; + zebra_redistribute_default (client); +} + +void +zebra_redistribute_default_delete (int command, struct zserv *client, + int length) +{ + client->redist_default = 0;; +} + +/* Interface up information. */ +void +zebra_interface_up_update (struct interface *ifp) +{ + listnode node; + struct zserv *client; + + if (IS_ZEBRA_DEBUG_EVENT) + zlog_info ("MESSAGE: ZEBRA_INTERFACE_UP %s", ifp->name); + + for (node = listhead (client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + zsend_interface_up (client, ifp); +} + +/* Interface down information. */ +void +zebra_interface_down_update (struct interface *ifp) +{ + listnode node; + struct zserv *client; + + if (IS_ZEBRA_DEBUG_EVENT) + zlog_info ("MESSAGE: ZEBRA_INTERFACE_DOWN %s", ifp->name); + + for (node = listhead (client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + zsend_interface_down (client, ifp); +} + +/* Interface information update. */ +void +zebra_interface_add_update (struct interface *ifp) +{ + listnode node; + struct zserv *client; + + if (IS_ZEBRA_DEBUG_EVENT) + zlog_info ("MESSAGE: ZEBRA_INTERFACE_ADD %s", ifp->name); + + for (node = listhead (client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + if (client->ifinfo) + zsend_interface_add (client, ifp); +} + +void +zebra_interface_delete_update (struct interface *ifp) +{ + listnode node; + struct zserv *client; + + if (IS_ZEBRA_DEBUG_EVENT) + zlog_info ("MESSAGE: ZEBRA_INTERFACE_DELETE %s", ifp->name); + + for (node = listhead (client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + if (client->ifinfo) + zsend_interface_delete (client, ifp); +} + +/* Interface address addition. */ +void +zebra_interface_address_add_update (struct interface *ifp, + struct connected *ifc) +{ + listnode node; + struct zserv *client; + struct prefix *p; + char buf[BUFSIZ]; + + if (IS_ZEBRA_DEBUG_EVENT) + { + p = ifc->address; + zlog_info ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD %s/%d on %s", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen, ifc->ifp->name); + } + + for (node = listhead (client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + zsend_interface_address_add (client, ifp, ifc); +} + +/* Interface address deletion. */ +void +zebra_interface_address_delete_update (struct interface *ifp, + struct connected *ifc) +{ + listnode node; + struct zserv *client; + struct prefix *p; + char buf[BUFSIZ]; + + if (IS_ZEBRA_DEBUG_EVENT) + { + p = ifc->address; + zlog_info ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE %s/%d on %s", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen, ifc->ifp->name); + } + + for (node = listhead (client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + zsend_interface_address_delete (client, ifp, ifc); +} diff --git a/zebra/redistribute.h b/zebra/redistribute.h new file mode 100644 index 00000000..8b45cf3b --- /dev/null +++ b/zebra/redistribute.h @@ -0,0 +1,49 @@ +/* + * Redistribution Handler + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_REDISTRIBUTE_H +#define _ZEBRA_REDISTRIBUTE_H + +#include "table.h" + +void zebra_redistribute_add (int, struct zserv *, int); +void zebra_redistribute_delete (int, struct zserv *, int); + +void zebra_redistribute_default_add (int, struct zserv *, int); +void zebra_redistribute_default_delete (int, struct zserv *, int); + +void redistribute_add (struct prefix *, struct rib *); +void redistribute_delete (struct prefix *, struct rib *); + +void zebra_interface_up_update (struct interface *); +void zebra_interface_down_update (struct interface *); + +void zebra_interface_add_update (struct interface *); +void zebra_interface_delete_update (struct interface *); + +void zebra_interface_address_add_update (struct interface *, + struct connected *); +void zebra_interface_address_delete_update (struct interface *, + struct connected *c); + +#endif /* _ZEBRA_REDISTRIBUTE_H */ + diff --git a/zebra/rib.h b/zebra/rib.h new file mode 100644 index 00000000..f5012610 --- /dev/null +++ b/zebra/rib.h @@ -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 index 00000000..faaddab9 --- /dev/null +++ b/zebra/rt.h @@ -0,0 +1,40 @@ +/* + * kernel routing table update prototype. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RT_H +#define _ZEBRA_RT_H + +int kernel_add_ipv4 (struct prefix *, struct rib *); +int kernel_delete_ipv4 (struct prefix *, struct rib *); +int kernel_add_route (struct prefix_ipv4 *, struct in_addr *, int, int); +int kernel_address_add_ipv4 (struct interface *, struct connected *); +int kernel_address_delete_ipv4 (struct interface *, struct connected *); + +#ifdef HAVE_IPV6 +int kernel_add_ipv6 (struct prefix *, struct rib *); +int kernel_delete_ipv6 (struct prefix *, struct rib *); +int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, + unsigned int index, int flags, int table); + +#endif /* HAVE_IPV6 */ + +#endif /* _ZEBRA_RT_H */ diff --git a/zebra/rt_ioctl.c b/zebra/rt_ioctl.c new file mode 100644 index 00000000..d470572b --- /dev/null +++ b/zebra/rt_ioctl.c @@ -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 + +#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); +} + +#ifdef HAVE_IPV6 + +/* Below is hack for GNU libc definition and Linux 2.1.X header. */ +#undef RTF_DEFAULT +#undef RTF_ADDRCONF + +#include + +#if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 +/* struct in6_rtmsg will be declared in net/route.h. */ +#else +#include +#endif + +int +kernel_ioctl_ipv6 (u_long type, struct prefix_ipv6 *dest, struct in6_addr *gate, + int index, int flags) +{ + int ret; + int sock; + struct in6_rtmsg rtm; + + memset (&rtm, 0, sizeof (struct in6_rtmsg)); + + rtm.rtmsg_flags |= RTF_UP; + rtm.rtmsg_metric = 1; + memcpy (&rtm.rtmsg_dst, &dest->prefix, sizeof (struct in6_addr)); + rtm.rtmsg_dst_len = dest->prefixlen; + + /* We need link local index. But this should be done caller... + if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway)) + { + index = if_index_address (&rtm.rtmsg_gateway); + rtm.rtmsg_ifindex = index; + } + else + rtm.rtmsg_ifindex = 0; + */ + + rtm.rtmsg_flags |= RTF_GATEWAY; + + /* For tagging route. */ + /* rtm.rtmsg_flags |= RTF_DYNAMIC; */ + + memcpy (&rtm.rtmsg_gateway, gate, sizeof (struct in6_addr)); + + if (index) + rtm.rtmsg_ifindex = index; + else + rtm.rtmsg_ifindex = 0; + + rtm.rtmsg_metric = 1; + + sock = socket (AF_INET6, SOCK_DGRAM, 0); + if (sock < 0) + { + zlog_warn ("can't make socket\n"); + return -1; + } + + /* Send message via ioctl. */ + ret = ioctl (sock, type, &rtm); + if (ret < 0) + { + zlog_warn ("can't %s ipv6 route: %s\n", type == SIOCADDRT ? "add" : "delete", + strerror(errno)); + ret = errno; + close (sock); + return ret; + } + close (sock); + + return ret; +} + +int +kernel_ioctl_ipv6_multipath (u_long cmd, struct prefix *p, struct rib *rib, + int family) +{ + int ret; + int sock; + struct in6_rtmsg rtm; + struct nexthop *nexthop; + int nexthop_num = 0; + + memset (&rtm, 0, sizeof (struct in6_rtmsg)); + + rtm.rtmsg_flags |= RTF_UP; + rtm.rtmsg_metric = rib->metric; + memcpy (&rtm.rtmsg_dst, &p->u.prefix, sizeof (struct in6_addr)); + rtm.rtmsg_dst_len = p->prefixlen; + + /* We need link local index. But this should be done caller... + if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway)) + { + index = if_index_address (&rtm.rtmsg_gateway); + rtm.rtmsg_ifindex = index; + } + else + rtm.rtmsg_ifindex = 0; + */ + + 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 index 00000000..baca1751 --- /dev/null +++ b/zebra/rt_netlink.c @@ -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 + +/* 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, */ +int +addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen) +{ + int len; + struct rtattr *rta; + + len = RTA_LENGTH(alen); + + if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) + return -1; + + rta = (struct rtattr*) (((char*)n) + NLMSG_ALIGN (n->nlmsg_len)); + rta->rta_type = type; + rta->rta_len = len; + memcpy (RTA_DATA(rta), data, alen); + n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; + + return 0; +} + +int +rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen) +{ + int len; + struct rtattr *subrta; + + len = RTA_LENGTH(alen); + + if (RTA_ALIGN(rta->rta_len) + len > maxlen) + return -1; + + subrta = (struct rtattr*) (((char*)rta) + RTA_ALIGN (rta->rta_len)); + subrta->rta_type = type; + subrta->rta_len = len; + memcpy (RTA_DATA(subrta), data, alen); + rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len; + + return 0; +} + +/* Utility function comes from iproute2. + Authors: Alexey Kuznetsov, */ +int +addattr32 (struct nlmsghdr *n, int maxlen, int type, int data) +{ + int len; + struct rtattr *rta; + + len = RTA_LENGTH(4); + + if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen) + return -1; + + rta = (struct rtattr*) (((char*)n) + NLMSG_ALIGN (n->nlmsg_len)); + rta->rta_type = type; + rta->rta_len = len; + memcpy (RTA_DATA(rta), &data, 4); + n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; + + return 0; +} + +static int +netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h) +{ + zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type); + return 0; +} + +/* sendmsg() to netlink socket then recvmsg(). */ +int +netlink_talk (struct nlmsghdr *n, struct nlsock *nl) +{ + int status; + struct sockaddr_nl snl; + struct iovec iov = { (void*) n, n->nlmsg_len }; + struct msghdr msg = {(void*) &snl, sizeof snl, &iov, 1, NULL, 0, 0}; + int flags = 0; + + memset (&snl, 0, sizeof snl); + snl.nl_family = AF_NETLINK; + + n->nlmsg_seq = ++netlink_cmd.seq; + + /* Request an acknowledgement by setting NLM_F_ACK */ + n->nlmsg_flags |= NLM_F_ACK; + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("netlink_talk: %s type %s(%u), seq=%u", netlink_cmd.name, + lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type, + n->nlmsg_seq); + + /* Send message to netlink interface. */ + status = sendmsg (nl->sock, &msg, 0); + if (status < 0) + { + zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s", + strerror (errno)); + return -1; + } + + /* + * Change socket flags for blocking I/O. + * This ensures we wait for a reply in netlink_parse_info(). + */ + if((flags = fcntl(nl->sock, F_GETFL, 0)) < 0) + { + zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s", + __FUNCTION__, __LINE__, strerror (errno)); + } + flags &= ~O_NONBLOCK; + if(fcntl(nl->sock, F_SETFL, flags) < 0) + { + zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s", + __FUNCTION__, __LINE__, strerror (errno)); + } + + /* + * Get reply from netlink socket. + * The reply should either be an acknowlegement or an error. + */ + status = netlink_parse_info (netlink_talk_filter, nl); + + /* Restore socket flags for nonblocking I/O */ + flags |= O_NONBLOCK; + if(fcntl(nl->sock, F_SETFL, flags) < 0) + { + zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s", + __FUNCTION__, __LINE__, strerror (errno)); + } + + return status; +} + +/* Routing table change via netlink interface. */ +int +netlink_route (int cmd, int family, void *dest, int length, void *gate, + int index, int zebra_flags, int table) +{ + int ret; + int bytelen; + struct sockaddr_nl snl; + int discard; + + struct + { + struct nlmsghdr n; + struct rtmsg r; + char buf[1024]; + } req; + + memset (&req, 0, sizeof req); + + bytelen = (family == AF_INET ? 4 : 16); + + req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); + req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; + req.n.nlmsg_type = cmd; + req.r.rtm_family = family; + req.r.rtm_table = table; + req.r.rtm_dst_len = length; + + if (zebra_flags & ZEBRA_FLAG_BLACKHOLE) + discard = 1; + else + discard = 0; + + if (cmd == RTM_NEWROUTE) + { + 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 */ + +/* Interface address modification. */ +int +netlink_address (int cmd, int family, struct interface *ifp, + struct connected *ifc) +{ + int bytelen; + struct prefix *p; + + struct + { + struct nlmsghdr n; + struct ifaddrmsg ifa; + char buf[1024]; + } req; + + p = ifc->address; + memset (&req, 0, sizeof req); + + bytelen = (family == AF_INET ? 4 : 16); + + req.n.nlmsg_len = NLMSG_LENGTH (sizeof(struct ifaddrmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = cmd; + req.ifa.ifa_family = family; + + req.ifa.ifa_index = ifp->ifindex; + req.ifa.ifa_prefixlen = p->prefixlen; + + addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen); + + if (family == AF_INET && cmd == RTM_NEWADDR) + { + if (if_is_broadcast (ifp) && ifc->destination) + { + p = ifc->destination; + addattr_l(&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix, bytelen); + } + } + + if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY)) + SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY); + + if (ifc->label) + addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label, + strlen (ifc->label) + 1); + + return netlink_talk (&req.n, &netlink_cmd); +} + +int +kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc) +{ + return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc); +} + +int +kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc) +{ + return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc); +} + +#include "thread.h" + +extern struct thread_master *master; + +/* Kernel route reflection. */ +int +kernel_read (struct thread *thread) +{ + int ret; + int sock; + + sock = THREAD_FD (thread); + ret = netlink_parse_info (netlink_information_fetch, &netlink); + thread_add_read (master, kernel_read, NULL, netlink.sock); + + return 0; +} + +/* Exported interface function. This function simply calls + netlink_socket (). */ +void +kernel_init () +{ + unsigned long groups; + + groups = RTMGRP_LINK|RTMGRP_IPV4_ROUTE|RTMGRP_IPV4_IFADDR; +#ifdef HAVE_IPV6 + groups |= RTMGRP_IPV6_ROUTE|RTMGRP_IPV6_IFADDR; +#endif /* HAVE_IPV6 */ + netlink_socket (&netlink, groups); + netlink_socket (&netlink_cmd, 0); + + /* Register kernel socket. */ + if (netlink.sock > 0) + thread_add_read (master, kernel_read, NULL, netlink.sock); +} diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c new file mode 100644 index 00000000..fe88be81 --- /dev/null +++ b/zebra/rt_socket.c @@ -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 + +#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 index 00000000..8f4b3778 --- /dev/null +++ b/zebra/rtadv.c @@ -0,0 +1,1112 @@ +/* Router advertisement + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "memory.h" +#include "sockopt.h" +#include "thread.h" +#include "if.h" +#include "log.h" +#include "prefix.h" +#include "linklist.h" +#include "command.h" + +#include "zebra/interface.h" +#include "zebra/rtadv.h" +#include "zebra/debug.h" + +#if defined (HAVE_IPV6) && defined (RTADV) + +/* If RFC2133 definition is used. */ +#ifndef IPV6_JOIN_GROUP +#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP +#endif +#ifndef IPV6_LEAVE_GROUP +#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP +#endif + +#define ALLNODE "ff02::1" +#define ALLROUTER "ff02::2" + +enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER, RTADV_READ}; + +void rtadv_event (enum rtadv_event, int); + +int if_join_all_router (int, struct interface *); +int if_leave_all_router (int, struct interface *); + +/* Structure which hold status of router advertisement. */ +struct rtadv +{ + int sock; + + int adv_if_count; + + struct thread *ra_read; + struct thread *ra_timer; +}; + +struct rtadv *rtadv = NULL; + +struct rtadv * +rtadv_new () +{ + struct rtadv *new; + new = XMALLOC (MTYPE_TMP, sizeof (struct rtadv)); + memset (new, 0, sizeof (struct rtadv)); + return new; +} + +void +rtadv_free (struct rtadv *rtadv) +{ + XFREE (MTYPE_TMP, rtadv); +} + +int +rtadv_recv_packet (int sock, u_char *buf, int buflen, + struct sockaddr_in6 *from, unsigned int *ifindex, + int *hoplimit) +{ + int ret; + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsgptr; + struct in6_addr dst; + + char adata[1024]; + + /* Fill in message and iovec. */ + msg.msg_name = (void *) from; + msg.msg_namelen = sizeof (struct sockaddr_in6); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = (void *) adata; + msg.msg_controllen = sizeof adata; + iov.iov_base = buf; + iov.iov_len = buflen; + + /* If recvmsg fail return minus value. */ + ret = recvmsg (sock, &msg, 0); + if (ret < 0) + return ret; + + for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; + cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) + { + /* I want interface index which this packet comes from. */ + if (cmsgptr->cmsg_level == IPPROTO_IPV6 && + cmsgptr->cmsg_type == IPV6_PKTINFO) + { + struct in6_pktinfo *ptr; + + ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr); + *ifindex = ptr->ipi6_ifindex; + memcpy(&dst, &ptr->ipi6_addr, sizeof(ptr->ipi6_addr)); + } + + /* Incoming packet's hop limit. */ + if (cmsgptr->cmsg_level == IPPROTO_IPV6 && + cmsgptr->cmsg_type == IPV6_HOPLIMIT) + *hoplimit = *((int *) CMSG_DATA (cmsgptr)); + } + return ret; +} + +#define RTADV_MSG_SIZE 4096 + +/* Send router advertisement packet. */ +void +rtadv_send_packet (int sock, struct interface *ifp) +{ + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsgptr; + struct in6_pktinfo *pkt; + struct sockaddr_in6 addr; +#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; +} + +struct rtadv_prefix * +rtadv_prefix_new () +{ + struct rtadv_prefix *new; + + new = XMALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix)); + memset (new, 0, sizeof (struct rtadv_prefix)); + + return new; +} + +void +rtadv_prefix_free (struct rtadv_prefix *rtadv_prefix) +{ + XFREE (MTYPE_RTADV_PREFIX, rtadv_prefix); +} + +struct rtadv_prefix * +rtadv_prefix_lookup (list rplist, struct prefix *p) +{ + listnode node; + struct rtadv_prefix *rprefix; + + for (node = listhead (rplist); node; node = nextnode (node)) + { + rprefix = getdata (node); + if (prefix_same (&rprefix->prefix, p)) + return rprefix; + } + return NULL; +} + +struct rtadv_prefix * +rtadv_prefix_get (list rplist, struct prefix *p) +{ + struct rtadv_prefix *rprefix; + + rprefix = rtadv_prefix_lookup (rplist, p); + if (rprefix) + return rprefix; + + rprefix = rtadv_prefix_new (); + memcpy (&rprefix->prefix, p, sizeof (struct prefix)); + listnode_add (rplist, rprefix); + + return rprefix; +} + +void +rtadv_prefix_set (struct zebra_if *zif, struct rtadv_prefix *rp) +{ + struct rtadv_prefix *rprefix; + + rprefix = rtadv_prefix_get (zif->rtadv.AdvPrefixList, &rp->prefix); + + /* Set parameters. */ + rprefix->AdvValidLifetime = rp->AdvValidLifetime; + rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime; + rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag; + rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag; +} + +int +rtadv_prefix_reset (struct zebra_if *zif, struct rtadv_prefix *rp) +{ + struct rtadv_prefix *rprefix; + + rprefix = rtadv_prefix_lookup (zif->rtadv.AdvPrefixList, &rp->prefix); + if (rprefix != NULL) + { + listnode_delete (zif->rtadv.AdvPrefixList, (void *) rprefix); + rtadv_prefix_free (rprefix); + return 1; + } + else + return 0; +} + +DEFUN (ipv6_nd_suppress_ra, + ipv6_nd_suppress_ra_cmd, + "ipv6 nd suppress-ra", + IP_STR + "Neighbor discovery\n" + "Suppress Router Advertisement\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = vty->index; + zif = ifp->info; + + if (if_is_loopback (ifp)) + { + vty_out (vty, "Invalid interface%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (zif->rtadv.AdvSendAdvertisements) + { + zif->rtadv.AdvSendAdvertisements = 0; + zif->rtadv.AdvIntervalTimer = 0; + rtadv->adv_if_count--; + + if_leave_all_router (rtadv->sock, ifp); + + if (rtadv->adv_if_count == 0) + rtadv_event (RTADV_STOP, 0); + } + + return CMD_SUCCESS; +} + +ALIAS (ipv6_nd_suppress_ra, + no_ipv6_nd_send_ra_cmd, + "no ipv6 nd send-ra", + NO_STR + IP_STR + "Neighbor discovery\n" + "Send Router Advertisement\n") + +DEFUN (no_ipv6_nd_suppress_ra, + no_ipv6_nd_suppress_ra_cmd, + "no ipv6 nd suppress-ra", + NO_STR + IP_STR + "Neighbor discovery\n" + "Suppress Router Advertisement\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = vty->index; + zif = ifp->info; + + if (if_is_loopback (ifp)) + { + vty_out (vty, "Invalid interface%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (! zif->rtadv.AdvSendAdvertisements) + { + zif->rtadv.AdvSendAdvertisements = 1; + zif->rtadv.AdvIntervalTimer = 0; + rtadv->adv_if_count++; + + if_join_all_router (rtadv->sock, ifp); + + if (rtadv->adv_if_count == 1) + rtadv_event (RTADV_START, rtadv->sock); + } + + return CMD_SUCCESS; +} + +ALIAS (no_ipv6_nd_suppress_ra, + ipv6_nd_send_ra_cmd, + "ipv6 nd send-ra", + IP_STR + "Neighbor discovery\n" + "Send Router Advertisement\n") + +DEFUN (ipv6_nd_ra_interval, + ipv6_nd_ra_interval_cmd, + "ipv6 nd ra-interval SECONDS", + IP_STR + "Neighbor discovery\n" + "Router Advertisement interval\n" + "Router Advertisement interval in seconds\n") +{ + int interval; + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + interval = atoi (argv[0]); + + if (interval < 0) + { + vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE); + return CMD_WARNING; + } + + zif->rtadv.MaxRtrAdvInterval = interval; + zif->rtadv.MinRtrAdvInterval = 0.33 * interval; + zif->rtadv.AdvIntervalTimer = 0; + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_nd_ra_interval, + no_ipv6_nd_ra_interval_cmd, + "no ipv6 nd ra-interval", + NO_STR + IP_STR + "Neighbor discovery\n" + "Router Advertisement interval\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL; + zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL; + zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval; + + return CMD_SUCCESS; +} + +DEFUN (ipv6_nd_ra_lifetime, + ipv6_nd_ra_lifetime_cmd, + "ipv6 nd ra-lifetime SECONDS", + IP_STR + "Neighbor discovery\n" + "Router lifetime\n" + "Router lifetime in seconds\n") +{ + int lifetime; + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + lifetime = atoi (argv[0]); + + if (lifetime < 0 || lifetime > 0xffff) + { + vty_out (vty, "Invalid Router Lifetime%s", VTY_NEWLINE); + return CMD_WARNING; + } + + zif->rtadv.AdvDefaultLifetime = lifetime; + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_nd_ra_lifetime, + no_ipv6_nd_ra_lifetime_cmd, + "no ipv6 nd ra-lifetime", + NO_STR + IP_STR + "Neighbor discovery\n" + "Router lifetime\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + zif->rtadv.AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME; + + return CMD_SUCCESS; +} + +DEFUN (ipv6_nd_reachable_time, + ipv6_nd_reachable_time_cmd, + "ipv6 nd reachable-time MILLISECONDS", + IP_STR + "Neighbor discovery\n" + "Reachable time\n" + "Reachable time in milliseconds\n") +{ + u_int32_t rtime; + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + rtime = (u_int32_t) atol (argv[0]); + + if (rtime > RTADV_MAX_REACHABLE_TIME) + { + vty_out (vty, "Invalid Reachable time%s", VTY_NEWLINE); + return CMD_WARNING; + } + + zif->rtadv.AdvReachableTime = rtime; + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_nd_reachable_time, + no_ipv6_nd_reachable_time_cmd, + "no ipv6 nd reachable-time", + NO_STR + IP_STR + "Neighbor discovery\n" + "Reachable time\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + zif->rtadv.AdvReachableTime = 0; + + return CMD_SUCCESS; +} + +DEFUN (ipv6_nd_managed_config_flag, + ipv6_nd_managed_config_flag_cmd, + "ipv6 nd managed-config-flag", + IP_STR + "Neighbor discovery\n" + "Managed address configuration flag\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + zif->rtadv.AdvManagedFlag = 1; + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_nd_managed_config_flag, + no_ipv6_nd_managed_config_flag_cmd, + "no ipv6 nd managed-config-flag", + NO_STR + IP_STR + "Neighbor discovery\n" + "Managed address configuration flag\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + zif->rtadv.AdvManagedFlag = 0; + + return CMD_SUCCESS; +} + +DEFUN (ipv6_nd_other_config_flag, + ipv6_nd_other_config_flag_cmd, + "ipv6 nd other-config-flag", + IP_STR + "Neighbor discovery\n" + "Other statefull configuration flag\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + zif->rtadv.AdvOtherConfigFlag = 1; + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_nd_other_config_flag, + no_ipv6_nd_other_config_flag_cmd, + "no ipv6 nd other-config-flag", + NO_STR + IP_STR + "Neighbor discovery\n" + "Other statefull configuration flag\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + zif->rtadv.AdvOtherConfigFlag = 0; + + return CMD_SUCCESS; +} + +DEFUN (ipv6_nd_prefix_advertisement, + ipv6_nd_prefix_advertisement_cmd, + "ipv6 nd prefix-advertisement IPV6PREFIX VALID PREFERRED [onlink] [autoconfig]", + IP_STR + "Neighbor discovery\n" + "Prefix information\n" + "IPv6 prefix\n" + "Valid lifetime in seconds\n" + "Preferred lifetime in seconds\n" + "On link flag\n" + "Autonomous address-configuration flag\n") +{ + int i; + int ret; + struct interface *ifp; + struct zebra_if *zebra_if; + struct rtadv_prefix rp; + + ifp = (struct interface *) vty->index; + zebra_if = ifp->info; + + ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix); + if (!ret) + { + vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc == 1) + { + rp.AdvValidLifetime = RTADV_VALID_LIFETIME; + rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME; + rp.AdvOnLinkFlag = 1; + rp.AdvAutonomousFlag = 1; + } + else + { + rp.AdvValidLifetime = (u_int32_t) atol (argv[1]); + rp.AdvPreferredLifetime = (u_int32_t) atol (argv[2]); + if (rp.AdvPreferredLifetime > rp.AdvValidLifetime) + { + vty_out (vty, "Invalid preferred lifetime%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rp.AdvOnLinkFlag = 0; + rp.AdvAutonomousFlag = 0; + for (i = 3; i < argc; i++) + { + if (! strcmp (argv[i], "onlink")) + rp.AdvOnLinkFlag = 1; + else if (! strcmp (argv[i], "autoconfig")) + rp.AdvAutonomousFlag = 1; + } + } + + rtadv_prefix_set (zebra_if, &rp); + + return CMD_SUCCESS; +} + +ALIAS (ipv6_nd_prefix_advertisement, + ipv6_nd_prefix_advertisement_no_val_cmd, + "ipv6 nd prefix-advertisement IPV6PREFIX", + IP_STR + "Neighbor discovery\n" + "Prefix information\n" + "IPv6 prefix\n") + +DEFUN (no_ipv6_nd_prefix_advertisement, + no_ipv6_nd_prefix_advertisement_cmd, + "no ipv6 nd prefix-advertisement IPV6PREFIX", + NO_STR + IP_STR + "Neighbor discovery\n" + "Prefix information\n" + "IPv6 prefix\n") +{ + int ret; + struct interface *ifp; + struct zebra_if *zebra_if; + struct rtadv_prefix rp; + + ifp = (struct interface *) vty->index; + zebra_if = ifp->info; + + ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix); + if (!ret) + { + vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = rtadv_prefix_reset (zebra_if, &rp); + if (!ret) + { + vty_out (vty, "Non-exist IPv6 prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +/* Write configuration about router advertisement. */ +void +rtadv_config_write (struct vty *vty, struct interface *ifp) +{ + struct zebra_if *zif; + listnode node; + struct rtadv_prefix *rprefix; + u_char buf[INET6_ADDRSTRLEN]; + + if (! rtadv) + return; + + zif = ifp->info; + + if (! if_is_loopback (ifp)) + { + if (zif->rtadv.AdvSendAdvertisements) + vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE); + else + vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE); + } + + if (zif->rtadv.MaxRtrAdvInterval != RTADV_MAX_RTR_ADV_INTERVAL) + vty_out (vty, " ipv6 nd ra-interval %d%s", zif->rtadv.MaxRtrAdvInterval, + VTY_NEWLINE); + + if (zif->rtadv.AdvDefaultLifetime != RTADV_ADV_DEFAULT_LIFETIME) + vty_out (vty, " ipv6 nd ra-lifetime %d%s", zif->rtadv.AdvDefaultLifetime, + VTY_NEWLINE); + + if (zif->rtadv.AdvReachableTime) + vty_out (vty, " ipv6 nd reachable-time %d%s", zif->rtadv.AdvReachableTime, + VTY_NEWLINE); + + if (zif->rtadv.AdvManagedFlag) + vty_out (vty, " ipv6 nd managed-config-flag%s", VTY_NEWLINE); + + if (zif->rtadv.AdvOtherConfigFlag) + vty_out (vty, " ipv6 nd other-config-flag%s", VTY_NEWLINE); + + for (node = listhead(zif->rtadv.AdvPrefixList); node; node = nextnode (node)) + { + rprefix = getdata (node); + vty_out (vty, " ipv6 nd prefix-advertisement %s/%d %d %d", + inet_ntop (AF_INET6, &rprefix->prefix.u.prefix6, + buf, INET6_ADDRSTRLEN), + rprefix->prefix.prefixlen, + rprefix->AdvValidLifetime, + rprefix->AdvPreferredLifetime); + if (rprefix->AdvOnLinkFlag) + vty_out (vty, " onlink"); + if (rprefix->AdvAutonomousFlag) + vty_out (vty, " autoconfig"); + vty_out (vty, "%s", VTY_NEWLINE); + } +} + +extern struct thread_master *master; + +void +rtadv_event (enum rtadv_event event, int val) +{ + switch (event) + { + case RTADV_START: + if (! rtadv->ra_read) + rtadv->ra_read = thread_add_read (master, rtadv_read, NULL, val); + if (! rtadv->ra_timer) + rtadv->ra_timer = thread_add_event (master, rtadv_timer, NULL, 0); + break; + case RTADV_STOP: + if (rtadv->ra_timer) + { + thread_cancel (rtadv->ra_timer); + rtadv->ra_timer = NULL; + } + if (rtadv->ra_read) + { + thread_cancel (rtadv->ra_read); + rtadv->ra_read = NULL; + } + break; + case RTADV_TIMER: + if (! rtadv->ra_timer) + rtadv->ra_timer = thread_add_timer (master, rtadv_timer, NULL, val); + break; + case RTADV_READ: + if (! rtadv->ra_read) + rtadv->ra_read = thread_add_read (master, rtadv_read, NULL, val); + break; + default: + break; + } + return; +} + +void +rtadv_init () +{ + int sock; + + sock = rtadv_make_socket (); + if (sock < 0) + return; + + rtadv = rtadv_new (); + rtadv->sock = sock; + + install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd); + install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_send_ra_cmd); + install_element (INTERFACE_NODE, &no_ipv6_nd_send_ra_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd); + install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd); + install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd); + install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd); + install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd); + install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_prefix_advertisement_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_prefix_advertisement_no_val_cmd); + install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_advertisement_cmd); +} + +int +if_join_all_router (int sock, struct interface *ifp) +{ + int ret; + + struct ipv6_mreq mreq; + + memset (&mreq, 0, sizeof (struct ipv6_mreq)); + inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr); + mreq.ipv6mr_interface = ifp->ifindex; + + ret = setsockopt (sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, + (char *) &mreq, sizeof mreq); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", strerror (errno)); + + zlog_info ("rtadv: %s join to all-routers multicast group", ifp->name); + + return 0; +} + +int +if_leave_all_router (int sock, struct interface *ifp) +{ + int ret; + + struct ipv6_mreq mreq; + + memset (&mreq, 0, sizeof (struct ipv6_mreq)); + inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr); + mreq.ipv6mr_interface = ifp->ifindex; + + ret = setsockopt (sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, + (char *) &mreq, sizeof mreq); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s", strerror (errno)); + + zlog_info ("rtadv: %s leave from all-routers multicast group", ifp->name); + + return 0; +} + +#else +void +rtadv_init () +{ + /* Empty.*/; +} +#endif /* RTADV && HAVE_IPV6 */ diff --git a/zebra/rtadv.h b/zebra/rtadv.h new file mode 100644 index 00000000..859b2d7e --- /dev/null +++ b/zebra/rtadv.h @@ -0,0 +1,49 @@ +/* Router advertisement + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RTADV_H +#define _ZEBRA_RTADV_H + +/* Router advertisement prefix. */ +struct rtadv_prefix +{ + /* Prefix to be advertised. */ + struct prefix prefix; + + /* The value to be placed in the Valid Lifetime in the Prefix */ + u_int32_t AdvValidLifetime; +#define RTADV_VALID_LIFETIME 2592000 + + /* The value to be placed in the on-link flag */ + int AdvOnLinkFlag; + + /* The value to be placed in the Preferred Lifetime in the Prefix + Information option, in seconds.*/ + u_int32_t AdvPreferredLifetime; +#define RTADV_PREFERRED_LIFETIME 604800 + + /* The value to be placed in the Autonomous Flag. */ + int AdvAutonomousFlag; +}; + +void rtadv_config_write (struct vty *, struct interface *); + +#endif /* _ZEBRA_RTADV_H */ diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c new file mode 100644 index 00000000..435eed80 --- /dev/null +++ b/zebra/rtread_getmsg.c @@ -0,0 +1,229 @@ +/* + * Kernel routing table readup by getmsg(2) + * Copyright (C) 1999 Michael Handler + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "log.h" +#include "if.h" + +#include "zebra/rib.h" + +#include +#include + +/* Solaris defines these in both and , sigh */ +#ifdef SUNOS_5 +#include +#ifndef T_CURRENT +#define T_CURRENT MI_T_CURRENT +#endif /* T_CURRENT */ +#ifndef IRE_CACHE +#define IRE_CACHE 0x0020 /* Cached Route entry */ +#endif /* IRE_CACHE */ +#ifndef IRE_HOST_REDIRECT +#define IRE_HOST_REDIRECT 0x0200 /* Host route entry from redirects */ +#endif /* IRE_HOST_REDIRECT */ +#ifndef IRE_CACHETABLE +#define IRE_CACHETABLE (IRE_CACHE | IRE_BROADCAST | IRE_LOCAL | \ + IRE_LOOPBACK) +#endif /* IRE_CACHETABLE */ +#undef IPOPT_EOL +#undef IPOPT_NOP +#undef IPOPT_LSRR +#undef IPOPT_RR +#undef IPOPT_SSRR +#endif /* SUNOS_5 */ + +#include +#include +#include + +/* device to read IP routing table from */ +#ifndef _PATH_GETMSG_ROUTE +#define _PATH_GETMSG_ROUTE "/dev/ip" +#endif /* _PATH_GETMSG_ROUTE */ + +#define RT_BUFSIZ 8192 + +void handle_route_entry (mib2_ipRouteEntry_t *routeEntry) +{ + struct prefix_ipv4 prefix; + struct in_addr tmpaddr, gateway; + u_char zebra_flags = 0; + + if (routeEntry->ipRouteInfo.re_ire_type & IRE_CACHETABLE) + return; + + if (routeEntry->ipRouteInfo.re_ire_type & IRE_HOST_REDIRECT) + zebra_flags |= ZEBRA_FLAG_SELFROUTE; + + prefix.family = AF_INET; + + tmpaddr.s_addr = routeEntry->ipRouteDest; + prefix.prefix = tmpaddr; + + tmpaddr.s_addr = routeEntry->ipRouteMask; + prefix.prefixlen = ip_masklen (tmpaddr); + + gateway.s_addr = routeEntry->ipRouteNextHop; + + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &prefix, + &gateway, 0, 0, 0, 0); +} + +void route_read () +{ + char storage[RT_BUFSIZ]; + + struct T_optmgmt_req *TLIreq = (struct T_optmgmt_req *) storage; + struct T_optmgmt_ack *TLIack = (struct T_optmgmt_ack *) storage; + struct T_error_ack *TLIerr = (struct T_error_ack *) storage; + + struct opthdr *MIB2hdr; + + mib2_ipRouteEntry_t *routeEntry, *lastRouteEntry; + + struct strbuf msgdata; + int flags, dev, retval, process; + + if ((dev = open (_PATH_GETMSG_ROUTE, O_RDWR)) == -1) { + zlog_warn ("can't open %s: %s", _PATH_GETMSG_ROUTE, + strerror (errno)); + return; + } + + TLIreq->PRIM_type = T_OPTMGMT_REQ; + TLIreq->OPT_offset = sizeof (struct T_optmgmt_req); + TLIreq->OPT_length = sizeof (struct opthdr); + TLIreq->MGMT_flags = T_CURRENT; + + MIB2hdr = (struct opthdr *) &TLIreq[1]; + + MIB2hdr->level = MIB2_IP; + MIB2hdr->name = 0; + MIB2hdr->len = 0; + + msgdata.buf = storage; + msgdata.len = sizeof (struct T_optmgmt_req) + sizeof (struct opthdr); + + flags = 0; + + if (putmsg (dev, &msgdata, NULL, flags) == -1) { + zlog_warn ("putmsg failed: %s", strerror (errno)); + goto exit; + } + + MIB2hdr = (struct opthdr *) &TLIack[1]; + msgdata.maxlen = sizeof (storage); + + while (1) { + flags = 0; + retval = getmsg (dev, &msgdata, NULL, &flags); + + if (retval == -1) { + zlog_warn ("getmsg(ctl) failed: %s", strerror (errno)); + goto exit; + } + + /* This is normal loop termination */ + if (retval == 0 && + msgdata.len >= sizeof (struct T_optmgmt_ack) && + TLIack->PRIM_type == T_OPTMGMT_ACK && + TLIack->MGMT_flags == T_SUCCESS && + MIB2hdr->len == 0) + break; + + if (msgdata.len >= sizeof (struct T_error_ack) && + TLIerr->PRIM_type == T_ERROR_ACK) { + zlog_warn ("getmsg(ctl) returned T_ERROR_ACK: %s", + strerror ((TLIerr->TLI_error == TSYSERR) + ? TLIerr->UNIX_error : EPROTO)); + break; + } + + /* should dump more debugging info to the log statement, + like what GateD does in this instance, but not + critical yet. */ + if (retval != MOREDATA || + msgdata.len < sizeof (struct T_optmgmt_ack) || + TLIack->PRIM_type != T_OPTMGMT_ACK || + TLIack->MGMT_flags != T_SUCCESS) { + errno = ENOMSG; + zlog_warn ("getmsg(ctl) returned bizarreness"); + break; + } + + /* MIB2_IP_21 is the the pseudo-MIB2 ipRouteTable + entry, see . "This isn't the MIB data + you're looking for." */ + process = (MIB2hdr->level == MIB2_IP && + MIB2hdr->name == MIB2_IP_21) ? 1 : 0; + + /* getmsg writes the data buffer out completely, not + to the closest smaller multiple. Unless reassembling + data structures across buffer boundaries is your idea + of a good time, set maxlen to the closest smaller + multiple of the size of the datastructure you're + retrieving. */ + msgdata.maxlen = sizeof (storage) - (sizeof (storage) + % sizeof (mib2_ipRouteEntry_t)); + + msgdata.len = 0; + flags = 0; + + do { + retval = getmsg (dev, NULL, &msgdata, &flags); + + if (retval == -1) { + zlog_warn ("getmsg(data) failed: %s", + strerror (errno)); + goto exit; + } + + if (!(retval == 0 || retval == MOREDATA)) { + zlog_warn ("getmsg(data) returned %d", retval); + goto exit; + } + + if (process) { + if (msgdata.len % + sizeof (mib2_ipRouteEntry_t) != 0) { + zlog_warn ("getmsg(data) returned " +"msgdata.len = %d (%% sizeof (mib2_ipRouteEntry_t) != 0)", msgdata.len); + goto exit; + } + + routeEntry = (mib2_ipRouteEntry_t *) + msgdata.buf; + lastRouteEntry = (mib2_ipRouteEntry_t *) + (msgdata.buf + msgdata.len); + do { + handle_route_entry (routeEntry); + } while (++routeEntry < lastRouteEntry); + } + } while (retval == MOREDATA); + } + +exit: + close (dev); +} diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c new file mode 100644 index 00000000..0b255a53 --- /dev/null +++ b/zebra/rtread_netlink.c @@ -0,0 +1,31 @@ +/* + * Kernel routing table readup by netlink + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +/* Extern from rt_netlink.c */ +void netlink_route_read (); + +void route_read () +{ + netlink_route_read (); +} diff --git a/zebra/rtread_proc.c b/zebra/rtread_proc.c new file mode 100644 index 00000000..320152e7 --- /dev/null +++ b/zebra/rtread_proc.c @@ -0,0 +1,169 @@ +/* + * Kernel routing readup by /proc filesystem + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "log.h" +#include "if.h" +#include "rib.h" + +/* Proc file system to read IPv4 routing table. */ +#ifndef _PATH_PROCNET_ROUTE +#define _PATH_PROCNET_ROUTE "/proc/net/route" +#endif /* _PATH_PROCNET_ROUTE */ + +/* Proc file system to read IPv6 routing table. */ +#ifndef _PATH_PROCNET_ROUTE6 +#define _PATH_PROCNET_ROUTE6 "/proc/net/ipv6_route" +#endif /* _PATH_PROCNET_ROUTE6 */ + +/* To read interface's name */ +#define INTERFACE_NAMSIZ 20 + +/* Reading buffer for one routing entry. */ +#define RT_BUFSIZ 1024 + +/* Kernel routing table read up by /proc filesystem. */ +int +proc_route_read () +{ + FILE *fp; + char buf[RT_BUFSIZ]; + char iface[INTERFACE_NAMSIZ], dest[9], gate[9], mask[9]; + int flags, refcnt, use, metric, mtu, window, rtt; + + /* Open /proc filesystem */ + fp = fopen (_PATH_PROCNET_ROUTE, "r"); + if (fp == NULL) + { + zlog_warn ("Can't open %s : %s\n", _PATH_PROCNET_ROUTE, strerror (errno)); + return -1; + } + + /* Drop first label line. */ + fgets (buf, RT_BUFSIZ, fp); + + while (fgets (buf, RT_BUFSIZ, fp) != NULL) + { + int n; + struct prefix_ipv4 p; + struct in_addr tmpmask; + struct in_addr gateway; + u_char zebra_flags = 0; + + n = sscanf (buf, "%s %s %s %x %d %d %d %s %d %d %d", + iface, dest, gate, &flags, &refcnt, &use, &metric, + mask, &mtu, &window, &rtt); + if (n != 11) + { + zlog_warn ("can't read all of routing information\n"); + continue; + } + if (! (flags & RTF_UP)) + continue; + if (! (flags & RTF_GATEWAY)) + continue; + + if (flags & RTF_DYNAMIC) + zebra_flags |= ZEBRA_FLAG_SELFROUTE; + + p.family = AF_INET; + sscanf (dest, "%lX", (unsigned long *)&p.prefix); + sscanf (mask, "%lX", (unsigned long *)&tmpmask); + p.prefixlen = ip_masklen (tmpmask); + sscanf (gate, "%lX", (unsigned long *)&gateway); + + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, 0, 0, 0, 0); + } + + return 0; +} + +#ifdef HAVE_IPV6 +int +proc_ipv6_route_read () +{ + FILE *fp; + char buf [RT_BUFSIZ]; + + /* Open /proc filesystem */ + fp = fopen (_PATH_PROCNET_ROUTE6, "r"); + if (fp == NULL) + { + zlog_warn ("Can't open %s : %s", _PATH_PROCNET_ROUTE6, + strerror (errno)); + return -1; + } + + /* There is no title line, so we don't drop first line. */ + while (fgets (buf, RT_BUFSIZ, fp) != NULL) + { + int n; + char dest[33], src[33], gate[33]; + char iface[INTERFACE_NAMSIZ]; + int dest_plen, src_plen; + int metric, use, refcnt, flags; + struct prefix_ipv6 p; + struct in6_addr gateway; + u_char zebra_flags = 0; + + /* Linux 2.1.x write this information at net/ipv6/route.c + rt6_info_node () */ + n = sscanf (buf, "%32s %02x %32s %02x %32s %08x %08x %08x %08x %s", + dest, &dest_plen, src, &src_plen, gate, + &metric, &use, &refcnt, &flags, iface); + + if (n != 10) + { + /* zlog_warn ("can't read all of routing information %d\n%s\n", n, buf); */ + continue; + } + + if (! (flags & RTF_UP)) + continue; + if (! (flags & RTF_GATEWAY)) + continue; + + if (flags & RTF_DYNAMIC) + zebra_flags |= ZEBRA_FLAG_SELFROUTE; + + p.family = AF_INET6; + str2in6_addr (dest, &p.prefix); + str2in6_addr (gate, &gateway); + p.prefixlen = dest_plen; + + rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, 0, 0); + } + + return 0; +} +#endif /* HAVE_IPV6 */ + +void +route_read () +{ + proc_route_read (); +#ifdef HAVE_IPV6 + proc_ipv6_route_read (); +#endif /* HAVE_IPV6 */ +} diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c new file mode 100644 index 00000000..970c0aa1 --- /dev/null +++ b/zebra/rtread_sysctl.c @@ -0,0 +1,75 @@ +/* + * Kernel routing table read by sysctl function. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "memory.h" +#include "log.h" + +/* Kernel routing table read up by sysctl function. */ +int +route_read () +{ + caddr_t buf, end, ref; + size_t bufsiz; + struct rt_msghdr *rtm; + void rtm_read (struct rt_msghdr *); + +#define MIBSIZ 6 + int mib[MIBSIZ] = + { + CTL_NET, + PF_ROUTE, + 0, + 0, + NET_RT_DUMP, + 0 + }; + + /* Get buffer size. */ + if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) + { + zlog_warn ("sysctl fail: %s", strerror (errno)); + return -1; + } + + /* Allocate buffer. */ + ref = buf = XMALLOC (MTYPE_TMP, bufsiz); + + /* Read routing table information by calling sysctl(). */ + if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0) + { + zlog_warn ("sysctl() fail by %s", strerror (errno)); + return -1; + } + + for (end = buf + bufsiz; buf < end; buf += rtm->rtm_msglen) + { + rtm = (struct rt_msghdr *) buf; + rtm_read (rtm); + } + + /* Free buffer. */ + XFREE (MTYPE_TMP, ref); + + return 0; +} diff --git a/zebra/zebra.conf.sample b/zebra/zebra.conf.sample new file mode 100644 index 00000000..a5d0732f --- /dev/null +++ b/zebra/zebra.conf.sample @@ -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 index 00000000..ec07e2e3 --- /dev/null +++ b/zebra/zebra_rib.c @@ -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 + +#include "prefix.h" +#include "table.h" +#include "memory.h" +#include "str.h" +#include "command.h" +#include "if.h" +#include "log.h" +#include "sockunion.h" + +#include "zebra/rib.h" +#include "zebra/rt.h" +#include "zebra/zserv.h" +#include "zebra/redistribute.h" +#include "zebra/debug.h" + +/* Default rtm_table for all clients */ +extern int rtm_table_default; + +/* Each route type's string and default distance value. */ +struct +{ + int key; + int distance; +} route_info[] = +{ + {ZEBRA_ROUTE_SYSTEM, 0}, + {ZEBRA_ROUTE_KERNEL, 0}, + {ZEBRA_ROUTE_CONNECT, 0}, + {ZEBRA_ROUTE_STATIC, 1}, + {ZEBRA_ROUTE_RIP, 120}, + {ZEBRA_ROUTE_RIPNG, 120}, + {ZEBRA_ROUTE_OSPF, 110}, + {ZEBRA_ROUTE_OSPF6, 110}, + {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */} +}; + +/* Vector for routing table. */ +vector vrf_vector; + +/* Allocate new VRF. */ +struct vrf * +vrf_alloc (char *name) +{ + struct vrf *vrf; + + vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf)); + + /* Put name. */ + if (name) + vrf->name = XSTRDUP (MTYPE_VRF_NAME, name); + + /* Allocate routing table and static table. */ + vrf->table[AFI_IP][SAFI_UNICAST] = route_table_init (); + vrf->table[AFI_IP6][SAFI_UNICAST] = route_table_init (); + vrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init (); + vrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init (); + + return vrf; +} + +/* Free VRF. */ +void +vrf_free (struct vrf *vrf) +{ + if (vrf->name) + XFREE (MTYPE_VRF_NAME, vrf->name); + XFREE (MTYPE_VRF, vrf); +} + +/* Lookup VRF by identifier. */ +struct vrf * +vrf_lookup (u_int32_t id) +{ + return vector_lookup (vrf_vector, id); +} + +/* Lookup VRF by name. */ +struct vrf * +vrf_lookup_by_name (char *name) +{ + int i; + struct vrf *vrf; + + for (i = 0; i < vector_max (vrf_vector); i++) + if ((vrf = vector_slot (vrf_vector, i)) != NULL) + if (vrf->name && name && strcmp (vrf->name, name) == 0) + return vrf; + return NULL; +} + +/* Initialize VRF. */ +void +vrf_init () +{ + struct vrf *default_table; + + /* Allocate VRF vector. */ + vrf_vector = vector_init (1); + + /* Allocate default main table. */ + default_table = vrf_alloc ("Default-IP-Routing-Table"); + + /* Default table index must be 0. */ + vector_set_index (vrf_vector, 0, default_table); +} + +/* Lookup route table. */ +struct route_table * +vrf_table (afi_t afi, safi_t safi, u_int32_t id) +{ + struct vrf *vrf; + + vrf = vrf_lookup (id); + if (! vrf) + return NULL; + + return vrf->table[afi][safi]; +} + +/* Lookup static route table. */ +struct route_table * +vrf_static_table (afi_t afi, safi_t safi, u_int32_t id) +{ + struct vrf *vrf; + + vrf = vrf_lookup (id); + if (! vrf) + return NULL; + + return vrf->stable[afi][safi]; +} + +/* Add nexthop to the end of the list. */ +void +nexthop_add (struct rib *rib, struct nexthop *nexthop) +{ + struct nexthop *last; + + for (last = rib->nexthop; last && last->next; last = last->next) + ; + if (last) + last->next = nexthop; + else + rib->nexthop = nexthop; + nexthop->prev = last; + + rib->nexthop_num++; +} + +/* Delete specified nexthop from the list. */ +void +nexthop_delete (struct rib *rib, struct nexthop *nexthop) +{ + if (nexthop->next) + nexthop->next->prev = nexthop->prev; + if (nexthop->prev) + nexthop->prev->next = nexthop->next; + else + rib->nexthop = nexthop->next; + rib->nexthop_num--; +} + +/* Free nexthop. */ +void +nexthop_free (struct nexthop *nexthop) +{ + if (nexthop->type == NEXTHOP_TYPE_IFNAME && nexthop->ifname) + free (nexthop->ifname); + XFREE (MTYPE_NEXTHOP, nexthop); +} + +struct nexthop * +nexthop_ifindex_add (struct rib *rib, unsigned int ifindex) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IFINDEX; + nexthop->ifindex = ifindex; + + nexthop_add (rib, nexthop); + + return nexthop; +} + +struct nexthop * +nexthop_ifname_add (struct rib *rib, char *ifname) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IFNAME; + nexthop->ifname = strdup (ifname); + + nexthop_add (rib, nexthop); + + return nexthop; +} + +struct nexthop * +nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IPV4; + nexthop->gate.ipv4 = *ipv4; + + nexthop_add (rib, nexthop); + + return nexthop; +} + +struct nexthop * +nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, + unsigned int ifindex) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX; + nexthop->gate.ipv4 = *ipv4; + nexthop->ifindex = ifindex; + + nexthop_add (rib, nexthop); + + return nexthop; +} + +#ifdef HAVE_IPV6 +struct nexthop * +nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IPV6; + nexthop->gate.ipv6 = *ipv6; + + nexthop_add (rib, nexthop); + + return nexthop; +} + +struct nexthop * +nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6, + char *ifname) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IPV6_IFNAME; + nexthop->gate.ipv6 = *ipv6; + nexthop->ifname = XSTRDUP (0, ifname); + + nexthop_add (rib, nexthop); + + return nexthop; +} + +struct nexthop * +nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6, + unsigned int ifindex) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; + nexthop->gate.ipv6 = *ipv6; + nexthop->ifindex = ifindex; + + nexthop_add (rib, nexthop); + + return nexthop; +} +#endif /* HAVE_IPV6 */ + + +struct nexthop * +nexthop_blackhole_add (struct rib *rib) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_BLACKHOLE; + SET_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE); + + nexthop_add (rib, nexthop); + + return nexthop; +} + +/* If force flag is not set, do not modify falgs at all for uninstall + the route from FIB. */ +int +nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, + struct route_node *top) +{ + struct prefix_ipv4 p; + struct route_table *table; + struct route_node *rn; + struct rib *match; + struct nexthop *newhop; + + if (nexthop->type == NEXTHOP_TYPE_IPV4) + nexthop->ifindex = 0; + + if (set) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + + /* Make lookup prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = nexthop->gate.ipv4; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return 0; + + rn = route_node_match (table, (struct prefix *) &p); + while (rn) + { + route_unlock_node (rn); + + /* If lookup self prefix return immidiately. */ + if (rn == top) + return 0; + + /* Pick up selected route. */ + for (match = rn->info; match; match = match->next) + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + + /* If there is no selected route or matched route is EGP, go up + tree. */ + if (! match + || match->type == ZEBRA_ROUTE_BGP) + { + do { + rn = rn->parent; + } while (rn && rn->info == NULL); + if (rn) + route_lock_node (rn); + } + else + { + if (match->type == ZEBRA_ROUTE_CONNECT) + { + /* Directly point connected route. */ + newhop = match->nexthop; + if (newhop && nexthop->type == NEXTHOP_TYPE_IPV4) + nexthop->ifindex = newhop->ifindex; + + return 1; + } + else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) + { + for (newhop = match->nexthop; newhop; newhop = newhop->next) + if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) + && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + if (set) + { + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + nexthop->rtype = newhop->type; + if (newhop->type == NEXTHOP_TYPE_IPV4 || + newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) + nexthop->rgate.ipv4 = newhop->gate.ipv4; + if (newhop->type == NEXTHOP_TYPE_IFINDEX + || newhop->type == NEXTHOP_TYPE_IFNAME + || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) + nexthop->rifindex = newhop->ifindex; + } + return 1; + } + return 0; + } + else + { + return 0; + } + } + } + return 0; +} + +#ifdef HAVE_IPV6 +/* If force flag is not set, do not modify falgs at all for uninstall + the route from FIB. */ +int +nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, + struct route_node *top) +{ + struct prefix_ipv6 p; + struct route_table *table; + struct route_node *rn; + struct rib *match; + struct nexthop *newhop; + + if (nexthop->type == NEXTHOP_TYPE_IPV6) + nexthop->ifindex = 0; + + if (set) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + + /* Make lookup prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_PREFIXLEN; + p.prefix = nexthop->gate.ipv6; + + /* Lookup table. */ + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (! table) + return 0; + + rn = route_node_match (table, (struct prefix *) &p); + while (rn) + { + route_unlock_node (rn); + + /* If lookup self prefix return immidiately. */ + if (rn == top) + return 0; + + /* Pick up selected route. */ + for (match = rn->info; match; match = match->next) + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + + /* If there is no selected route or matched route is EGP, go up + tree. */ + if (! match + || match->type == ZEBRA_ROUTE_BGP) + { + do { + rn = rn->parent; + } while (rn && rn->info == NULL); + if (rn) + route_lock_node (rn); + } + else + { + if (match->type == ZEBRA_ROUTE_CONNECT) + { + /* Directly point connected route. */ + newhop = match->nexthop; + + if (newhop && nexthop->type == NEXTHOP_TYPE_IPV6) + nexthop->ifindex = newhop->ifindex; + + return 1; + } + else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) + { + for (newhop = match->nexthop; newhop; newhop = newhop->next) + if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) + && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + if (set) + { + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + nexthop->rtype = newhop->type; + if (newhop->type == NEXTHOP_TYPE_IPV6 + || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX + || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) + nexthop->rgate.ipv6 = newhop->gate.ipv6; + if (newhop->type == NEXTHOP_TYPE_IFINDEX + || newhop->type == NEXTHOP_TYPE_IFNAME + || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX + || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) + nexthop->rifindex = newhop->ifindex; + } + return 1; + } + return 0; + } + else + { + return 0; + } + } + } + return 0; +} +#endif /* HAVE_IPV6 */ + +struct rib * +rib_match_ipv4 (struct in_addr addr) +{ + struct prefix_ipv4 p; + struct route_table *table; + struct route_node *rn; + struct rib *match; + struct nexthop *newhop; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return 0; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = addr; + + rn = route_node_match (table, (struct prefix *) &p); + + while (rn) + { + route_unlock_node (rn); + + /* Pick up selected route. */ + for (match = rn->info; match; match = match->next) + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + + /* If there is no selected route or matched route is EGP, go up + tree. */ + if (! match + || match->type == ZEBRA_ROUTE_BGP) + { + do { + rn = rn->parent; + } while (rn && rn->info == NULL); + if (rn) + route_lock_node (rn); + } + else + { + if (match->type == ZEBRA_ROUTE_CONNECT) + /* Directly point connected route. */ + return match; + else + { + for (newhop = match->nexthop; newhop; newhop = newhop->next) + if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) + return match; + return NULL; + } + } + } + return NULL; +} + +struct rib * +rib_lookup_ipv4 (struct prefix_ipv4 *p) +{ + struct route_table *table; + struct route_node *rn; + struct rib *match; + struct nexthop *nexthop; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return 0; + + rn = route_node_lookup (table, (struct prefix *) p); + + /* No route for this prefix. */ + if (! rn) + return NULL; + + /* Unlock node. */ + route_unlock_node (rn); + + /* Pick up selected route. */ + for (match = rn->info; match; match = match->next) + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + + if (! match || match->type == ZEBRA_ROUTE_BGP) + return NULL; + + if (match->type == ZEBRA_ROUTE_CONNECT) + return match; + + for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + return match; + + return NULL; +} + +#ifdef HAVE_IPV6 +struct rib * +rib_match_ipv6 (struct in6_addr *addr) +{ + struct prefix_ipv6 p; + struct route_table *table; + struct route_node *rn; + struct rib *match; + struct nexthop *newhop; + + /* Lookup table. */ + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (! table) + return 0; + + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_PREFIXLEN; + IPV6_ADDR_COPY (&p.prefix, addr); + + rn = route_node_match (table, (struct prefix *) &p); + + while (rn) + { + route_unlock_node (rn); + + /* Pick up selected route. */ + for (match = rn->info; match; match = match->next) + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + + /* If there is no selected route or matched route is EGP, go up + tree. */ + if (! match + || match->type == ZEBRA_ROUTE_BGP) + { + do { + rn = rn->parent; + } while (rn && rn->info == NULL); + if (rn) + route_lock_node (rn); + } + else + { + if (match->type == ZEBRA_ROUTE_CONNECT) + /* Directly point connected route. */ + return match; + else + { + for (newhop = match->nexthop; newhop; newhop = newhop->next) + if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) + return match; + return NULL; + } + } + } + return NULL; +} +#endif /* HAVE_IPV6 */ + +int +nexthop_active_check (struct route_node *rn, struct rib *rib, + struct nexthop *nexthop, int set) +{ + struct interface *ifp; + + switch (nexthop->type) + { + case NEXTHOP_TYPE_IFINDEX: + ifp = if_lookup_by_index (nexthop->ifindex); + if (ifp && if_is_up (ifp)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + break; + case NEXTHOP_TYPE_IFNAME: + case NEXTHOP_TYPE_IPV6_IFNAME: + ifp = if_lookup_by_name (nexthop->ifname); + if (ifp && if_is_up (ifp)) + { + if (set) + nexthop->ifindex = ifp->ifindex; + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } + else + { + if (set) + nexthop->ifindex = 0; + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } + break; + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + if (nexthop_active_ipv4 (rib, nexthop, set, rn)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + break; +#ifdef HAVE_IPV6 + case NEXTHOP_TYPE_IPV6: + if (nexthop_active_ipv6 (rib, nexthop, set, rn)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6)) + { + ifp = if_lookup_by_index (nexthop->ifindex); + if (ifp && if_is_up (ifp)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } + else + { + if (nexthop_active_ipv6 (rib, nexthop, set, rn)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } + break; +#endif /* HAVE_IPV6 */ + case NEXTHOP_TYPE_BLACKHOLE: + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + break; + default: + break; + } + return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); +} + +int +nexthop_active_update (struct route_node *rn, struct rib *rib, int set) +{ + struct nexthop *nexthop; + int active; + + rib->nexthop_active_num = 0; + UNSET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); + + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + rib->nexthop_active_num += nexthop_active_check (rn, rib, nexthop, set); + if (active != CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); + } + return rib->nexthop_active_num; +} + +#define RIB_SYSTEM_ROUTE(R) \ + ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) + +void +newrib_free (struct rib *rib) +{ + struct nexthop *nexthop; + struct nexthop *next; + + for (nexthop = rib->nexthop; nexthop; nexthop = next) + { + next = nexthop->next; + nexthop_free (nexthop); + } + XFREE (MTYPE_RIB, rib); +} + +void +rib_install_kernel (struct route_node *rn, struct rib *rib) +{ + int ret = 0; + struct nexthop *nexthop; + + switch (PREFIX_FAMILY (&rn->p)) + { + case AF_INET: + ret = kernel_add_ipv4 (&rn->p, rib); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + ret = kernel_add_ipv6 (&rn->p, rib); + break; +#endif /* HAVE_IPV6 */ + } + + if (ret < 0) + { + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + } +} + +/* Uninstall the route from kernel. */ +int +rib_uninstall_kernel (struct route_node *rn, struct rib *rib) +{ + int ret = 0; + struct nexthop *nexthop; + + switch (PREFIX_FAMILY (&rn->p)) + { + case AF_INET: + ret = kernel_delete_ipv4 (&rn->p, rib); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + ret = kernel_delete_ipv6 (&rn->p, rib); + break; +#endif /* HAVE_IPV6 */ + } + + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + return ret; +} + +/* Uninstall the route from kernel. */ +void +rib_uninstall (struct route_node *rn, struct rib *rib) +{ + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + { + redistribute_delete (&rn->p, rib); + if (! RIB_SYSTEM_ROUTE (rib)) + rib_uninstall_kernel (rn, rib); + UNSET_FLAG (rib->flags, ZEBRA_FLAG_SELECTED); + } +} + +/* Core function for processing routing information base. */ +void +rib_process (struct route_node *rn, struct rib *del) +{ + struct rib *rib; + struct rib *next; + struct rib *fib = NULL; + struct rib *select = NULL; + + for (rib = rn->info; rib; rib = next) + { + next = rib->next; + + /* Currently installed rib. */ + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + fib = rib; + + /* Skip unreachable nexthop. */ + if (! nexthop_active_update (rn, rib, 0)) + continue; + + /* Infinit distance. */ + if (rib->distance == DISTANCE_INFINITY) + continue; + + /* Newly selected rib. */ + if (! select || rib->distance < select->distance + || rib->type == ZEBRA_ROUTE_CONNECT) + select = rib; + } + + /* Deleted route check. */ + if (del && CHECK_FLAG (del->flags, ZEBRA_FLAG_SELECTED)) + fib = del; + + /* Same route is selected. */ + if (select && select == fib) + { + if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) + { + redistribute_delete (&rn->p, select); + if (! RIB_SYSTEM_ROUTE (select)) + rib_uninstall_kernel (rn, select); + + /* Set real nexthop. */ + nexthop_active_update (rn, select, 1); + + if (! RIB_SYSTEM_ROUTE (select)) + rib_install_kernel (rn, select); + redistribute_add (&rn->p, select); + } + return; + } + + /* Uninstall old rib from forwarding table. */ + if (fib) + { + redistribute_delete (&rn->p, fib); + if (! RIB_SYSTEM_ROUTE (fib)) + rib_uninstall_kernel (rn, fib); + UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); + + /* Set real nexthop. */ + nexthop_active_update (rn, fib, 1); + } + + /* Install new rib into forwarding table. */ + if (select) + { + /* Set real nexthop. */ + nexthop_active_update (rn, select, 1); + + if (! RIB_SYSTEM_ROUTE (select)) + rib_install_kernel (rn, select); + SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED); + redistribute_add (&rn->p, select); + } +} + +/* Add RIB to head of the route node. */ +void +rib_addnode (struct route_node *rn, struct rib *rib) +{ + struct rib *head; + + head = rn->info; + if (head) + head->prev = rib; + rib->next = head; + rn->info = rib; +} + +void +rib_delnode (struct route_node *rn, struct rib *rib) +{ + if (rib->next) + rib->next->prev = rib->prev; + if (rib->prev) + rib->prev->next = rib->next; + else + rn->info = rib->next; +} + +int +rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, + struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id, + u_int32_t metric, u_char distance) +{ + struct rib *rib; + struct rib *same = NULL; + struct route_table *table; + struct route_node *rn; + struct nexthop *nexthop; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return 0; + + /* Make it sure prefixlen is applied to the prefix. */ + apply_mask_ipv4 (p); + + /* Set default distance by route type. */ + if (distance == 0) + { + distance = route_info[type].distance; + + /* iBGP distance is 200. */ + if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP)) + distance = 200; + } + + /* Lookup route node.*/ + rn = route_node_get (table, (struct prefix *) p); + + /* If same type of route are installed, treat it as a implicit + withdraw. */ + for (rib = rn->info; rib; rib = rib->next) + { + if (rib->type == ZEBRA_ROUTE_CONNECT) + { + nexthop = rib->nexthop; + + /* Duplicate connected route comes in. */ + if (rib->type == type + && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX + && nexthop->ifindex == ifindex) + { + rib->refcnt++; + return 0 ; + } + } + else if (rib->type == type) + { + same = rib; + rib_delnode (rn, same); + route_unlock_node (rn); + break; + } + } + + /* Allocate new rib structure. */ + rib = XMALLOC (MTYPE_RIB, sizeof (struct rib)); + memset (rib, 0, sizeof (struct rib)); + rib->type = type; + rib->distance = distance; + rib->flags = flags; + rib->metric = metric; + rib->nexthop_num = 0; + rib->uptime = time (NULL); + + /* Nexthop settings. */ + if (gate) + { + if (ifindex) + nexthop_ipv4_ifindex_add (rib, gate, ifindex); + else + nexthop_ipv4_add (rib, gate); + } + else + nexthop_ifindex_add (rib, ifindex); + + /* If this route is kernel route, set FIB flag to the route. */ + if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT) + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + /* Link new rib to node.*/ + rib_addnode (rn, rib); + + /* Process this route node. */ + rib_process (rn, same); + + /* Free implicit route.*/ + if (same) + newrib_free (same); + + return 0; +} + +int +rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib) +{ + struct route_table *table; + struct route_node *rn; + struct rib *same; + struct nexthop *nexthop; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return 0; + + /* Make it sure prefixlen is applied to the prefix. */ + apply_mask_ipv4 (p); + + /* Set default distance by route type. */ + if (rib->distance == 0) + { + rib->distance = route_info[rib->type].distance; + + /* iBGP distance is 200. */ + if (rib->type == ZEBRA_ROUTE_BGP + && CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP)) + rib->distance = 200; + } + + /* Lookup route node.*/ + rn = route_node_get (table, (struct prefix *) p); + + /* If same type of route are installed, treat it as a implicit + withdraw. */ + for (same = rn->info; same; same = same->next) + { + if (same->type == rib->type && same->table == rib->table + && same->type != ZEBRA_ROUTE_CONNECT) + { + rib_delnode (rn, same); + route_unlock_node (rn); + break; + } + } + + /* If this route is kernel route, set FIB flag to the route. */ + if (rib->type == ZEBRA_ROUTE_KERNEL || rib->type == ZEBRA_ROUTE_CONNECT) + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + /* Link new rib to node.*/ + rib_addnode (rn, rib); + + /* Process this route node. */ + rib_process (rn, same); + + /* Free implicit route.*/ + if (same) + newrib_free (same); + + return 0; +} + +int +rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, + struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id) +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + struct rib *fib = NULL; + struct rib *same = NULL; + struct nexthop *nexthop; + char buf1[BUFSIZ]; + char buf2[BUFSIZ]; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return 0; + + /* Apply mask. */ + apply_mask_ipv4 (p); + + /* Lookup route node. */ + rn = route_node_lookup (table, (struct prefix *) p); + if (! rn) + { + if (IS_ZEBRA_DEBUG_KERNEL) + { + if (gate) + zlog_info ("route %s/%d via %s ifindex %d doesn't exist in rib", + inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + inet_ntop (AF_INET, gate, buf2, BUFSIZ), + ifindex); + else + zlog_info ("route %s/%d ifindex %d doesn't exist in rib", + inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + ifindex); + } + return ZEBRA_ERR_RTNOEXIST; + } + + /* Lookup same type route. */ + for (rib = rn->info; rib; rib = rib->next) + { + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + fib = rib; + + if (rib->type == ZEBRA_ROUTE_CONNECT) + { + nexthop = rib->nexthop; + + if (rib->type == type + && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX + && nexthop->ifindex == ifindex) + { + if (rib->refcnt) + { + rib->refcnt--; + route_unlock_node (rn); + route_unlock_node (rn); + return 0; + } + same = rib; + break; + } + } + else + { + if (rib->type == type) + { + same = rib; + break; + } + } + } + + /* If same type of route can't be found and this message is from + kernel. */ + if (! same) + { + if (fib && type == ZEBRA_ROUTE_KERNEL) + { + /* Unset flags. */ + for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); + } + else + { + if (IS_ZEBRA_DEBUG_KERNEL) + { + if (gate) + zlog_info ("route %s/%d via %s ifindex %d type %d doesn't exist in rib", + inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + inet_ntop (AF_INET, gate, buf2, BUFSIZ), + ifindex, + type); + else + zlog_info ("route %s/%d ifindex %d type %d doesn't exist in rib", + inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + ifindex, + type); + } + route_unlock_node (rn); + return ZEBRA_ERR_RTNOEXIST; + } + } + + if (same) + rib_delnode (rn, same); + + /* Process changes. */ + rib_process (rn, same); + + if (same) + { + newrib_free (same); + route_unlock_node (rn); + } + + route_unlock_node (rn); + + return 0; +} + +/* Install static route into rib. */ +void +static_install_ipv4 (struct prefix *p, struct static_ipv4 *si) +{ + struct rib *rib; + struct route_node *rn; + struct route_table *table; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return; + + /* Lookup existing route */ + rn = route_node_get (table, p); + for (rib = rn->info; rib; rib = rib->next) + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) + break; + + if (rib) + { + /* Same distance static route is there. Update it with new + nexthop. */ + rib_uninstall (rn, rib); + route_unlock_node (rn); + + switch (si->type) + { + case STATIC_IPV4_GATEWAY: + nexthop_ipv4_add (rib, &si->gate.ipv4); + break; + case STATIC_IPV4_IFNAME: + nexthop_ifname_add (rib, si->gate.ifname); + break; + case STATIC_IPV4_BLACKHOLE: + nexthop_blackhole_add (rib); + break; + } + rib_process (rn, NULL); + } + else + { + /* This is new static route. */ + rib = XMALLOC (MTYPE_RIB, sizeof (struct rib)); + memset (rib, 0, sizeof (struct rib)); + + rib->type = ZEBRA_ROUTE_STATIC; + rib->distance = si->distance; + rib->metric = 0; + rib->nexthop_num = 0; + + switch (si->type) + { + case STATIC_IPV4_GATEWAY: + nexthop_ipv4_add (rib, &si->gate.ipv4); + break; + case STATIC_IPV4_IFNAME: + nexthop_ifname_add (rib, si->gate.ifname); + break; + case STATIC_IPV4_BLACKHOLE: + nexthop_blackhole_add (rib); + break; + } + + /* Link this rib to the tree. */ + rib_addnode (rn, rib); + + /* Process this prefix. */ + rib_process (rn, NULL); + } +} + +int +static_ipv4_nexthop_same (struct nexthop *nexthop, struct static_ipv4 *si) +{ + if (nexthop->type == NEXTHOP_TYPE_IPV4 + && si->type == STATIC_IPV4_GATEWAY + && IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->gate.ipv4)) + return 1; + if (nexthop->type == NEXTHOP_TYPE_IFNAME + && si->type == STATIC_IPV4_IFNAME + && strcmp (nexthop->ifname, si->gate.ifname) == 0) + return 1; + if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE + && si->type == STATIC_IPV4_BLACKHOLE) + return 1; + return 0;; +} + +/* Uninstall static route from RIB. */ +void +static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si) +{ + struct route_node *rn; + struct rib *rib; + struct nexthop *nexthop; + struct route_table *table; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return; + + /* Lookup existing route with type and distance. */ + rn = route_node_lookup (table, p); + if (! rn) + return; + + for (rib = rn->info; rib; rib = rib->next) + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) + break; + + if (! rib) + { + route_unlock_node (rn); + return; + } + + /* Lookup nexthop. */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + if (static_ipv4_nexthop_same (nexthop, si)) + break; + + /* Can't find nexthop. */ + if (! nexthop) + { + route_unlock_node (rn); + return; + } + + /* Check nexthop. */ + if (rib->nexthop_num == 1) + { + rib_delnode (rn, rib); + rib_process (rn, rib); + newrib_free (rib); + route_unlock_node (rn); + } + else + { + rib_uninstall (rn, rib); + nexthop_delete (rib, nexthop); + nexthop_free (nexthop); + rib_process (rn, rib); + } + + /* Unlock node. */ + route_unlock_node (rn); +} + +/* Add static route into static route configuration. */ +int +static_add_ipv4 (struct prefix *p, struct in_addr *gate, char *ifname, + u_char distance, u_int32_t vrf_id) +{ + u_char type = 0; + struct route_node *rn; + struct static_ipv4 *si; + struct static_ipv4 *pp; + struct static_ipv4 *cp; + struct static_ipv4 *update = NULL; + struct route_table *stable; + + /* Lookup table. */ + stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id); + if (! stable) + return -1; + + /* Lookup static route prefix. */ + rn = route_node_get (stable, p); + + /* Make flags. */ + if (gate) + type = STATIC_IPV4_GATEWAY; + else if (ifname) + type = STATIC_IPV4_IFNAME; + else + type = STATIC_IPV4_BLACKHOLE; + + /* Do nothing if there is a same static route. */ + for (si = rn->info; si; si = si->next) + { + if (type == si->type + && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4)) + && (! ifname || strcmp (ifname, si->gate.ifname) == 0)) + { + if (distance == si->distance) + { + route_unlock_node (rn); + return 0; + } + else + update = si; + } + } + + /* Distance chaged. */ + if (update) + static_delete_ipv4 (p, gate, ifname, update->distance, vrf_id); + + /* Make new static route structure. */ + si = XMALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4)); + memset (si, 0, sizeof (struct static_ipv4)); + + si->type = type; + si->distance = distance; + + if (gate) + si->gate.ipv4 = *gate; + if (ifname) + si->gate.ifname = XSTRDUP (0, ifname); + + /* Add new static route information to the tree with sort by + distance value and gateway address. */ + for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next) + { + if (si->distance < cp->distance) + break; + if (si->distance > cp->distance) + continue; + if (si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY) + { + if (ntohl (si->gate.ipv4.s_addr) < ntohl (cp->gate.ipv4.s_addr)) + break; + if (ntohl (si->gate.ipv4.s_addr) > ntohl (cp->gate.ipv4.s_addr)) + continue; + } + } + + /* Make linked list. */ + if (pp) + pp->next = si; + else + rn->info = si; + if (cp) + cp->prev = si; + si->prev = pp; + si->next = cp; + + /* Install into rib. */ + static_install_ipv4 (p, si); + + return 1; +} + +/* Delete static route from static route configuration. */ +int +static_delete_ipv4 (struct prefix *p, struct in_addr *gate, char *ifname, + u_char distance, u_int32_t vrf_id) +{ + u_char type = 0; + struct route_node *rn; + struct static_ipv4 *si; + struct route_table *stable; + + /* Lookup table. */ + stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id); + if (! stable) + return -1; + + /* Lookup static route prefix. */ + rn = route_node_lookup (stable, p); + if (! rn) + return 0; + + /* Make flags. */ + if (gate) + type = STATIC_IPV4_GATEWAY; + else if (ifname) + type = STATIC_IPV4_IFNAME; + else + type = STATIC_IPV4_BLACKHOLE; + + /* Find same static route is the tree */ + for (si = rn->info; si; si = si->next) + if (type == si->type + && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4)) + && (! ifname || strcmp (ifname, si->gate.ifname) == 0)) + break; + + /* Can't find static route. */ + if (! si) + { + route_unlock_node (rn); + return 0; + } + + /* Install into rib. */ + static_uninstall_ipv4 (p, si); + + /* Unlink static route from linked list. */ + if (si->prev) + si->prev->next = si->next; + else + rn->info = si->next; + if (si->next) + si->next->prev = si->prev; + + /* Free static route configuration. */ + XFREE (MTYPE_STATIC_IPV4, si); + + return 1; +} + + +#ifdef HAVE_IPV6 +int +rib_bogus_ipv6 (int type, struct prefix_ipv6 *p, + struct in6_addr *gate, unsigned int ifindex, int table) +{ + if (type == ZEBRA_ROUTE_CONNECT && IN6_IS_ADDR_UNSPECIFIED (&p->prefix)) + return 1; + if (type == ZEBRA_ROUTE_KERNEL && IN6_IS_ADDR_UNSPECIFIED (&p->prefix) + && p->prefixlen == 96 && gate && IN6_IS_ADDR_UNSPECIFIED (gate)) + { + kernel_delete_ipv6_old (p, gate, ifindex, 0, table); + return 1; + } + return 0; +} + +int +rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, + struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id) +{ + struct rib *rib; + struct rib *same = NULL; + struct route_table *table; + struct route_node *rn; + struct nexthop *nexthop; + + int distance; + u_int32_t metric = 0; + + /* Lookup table. */ + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (! table) + return 0; + + /* Make sure mask is applied. */ + apply_mask_ipv6 (p); + + /* Set default distance by route type. */ + distance = route_info[type].distance; + + if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP)) + distance = 200; + + /* Filter bogus route. */ + if (rib_bogus_ipv6 (type, p, gate, ifindex, 0)) + return 0; + + /* Lookup route node.*/ + rn = route_node_get (table, (struct prefix *) p); + + /* If same type of route are installed, treat it as a implicit + withdraw. */ + for (rib = rn->info; rib; rib = rib->next) + { + if (rib->type == ZEBRA_ROUTE_CONNECT) + { + nexthop = rib->nexthop; + + if (rib->type == type + && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX + && nexthop->ifindex == ifindex) + { + rib->refcnt++; + return 0; + } + } + else if (rib->type == type) + { + same = rib; + rib_delnode (rn, same); + route_unlock_node (rn); + break; + } + } + + /* Allocate new rib structure. */ + rib = XMALLOC (MTYPE_RIB, sizeof (struct rib)); + memset (rib, 0, sizeof (struct rib)); + rib->type = type; + rib->distance = distance; + rib->flags = flags; + rib->metric = metric; + rib->nexthop_num = 0; + rib->uptime = time (NULL); + + /* Nexthop settings. */ + if (gate) + { + if (ifindex) + nexthop_ipv6_ifindex_add (rib, gate, ifindex); + else + nexthop_ipv6_add (rib, gate); + } + else + nexthop_ifindex_add (rib, ifindex); + + /* If this route is kernel route, set FIB flag to the route. */ + if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT) + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + /* Link new rib to node.*/ + rib_addnode (rn, rib); + + /* Process this route node. */ + rib_process (rn, same); + + /* Free implicit route.*/ + if (same) + newrib_free (same); + + return 0; +} + +int +rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, + struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id) +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + struct rib *fib = NULL; + struct rib *same = NULL; + struct nexthop *nexthop; + char buf1[BUFSIZ]; + char buf2[BUFSIZ]; + + /* Apply mask. */ + apply_mask_ipv6 (p); + + /* Lookup table. */ + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (! table) + return 0; + + /* Lookup route node. */ + rn = route_node_lookup (table, (struct prefix *) p); + if (! rn) + { + if (IS_ZEBRA_DEBUG_KERNEL) + { + if (gate) + zlog_info ("route %s/%d via %s ifindex %d doesn't exist in rib", + inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + inet_ntop (AF_INET6, gate, buf2, BUFSIZ), + ifindex); + else + zlog_info ("route %s/%d ifindex %d doesn't exist in rib", + inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + ifindex); + } + return ZEBRA_ERR_RTNOEXIST; + } + + /* Lookup same type route. */ + for (rib = rn->info; rib; rib = rib->next) + { + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + fib = rib; + + if (rib->type == ZEBRA_ROUTE_CONNECT) + { + nexthop = rib->nexthop; + + if (rib->type == type + && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX + && nexthop->ifindex == ifindex) + { + if (rib->refcnt) + { + rib->refcnt--; + route_unlock_node (rn); + route_unlock_node (rn); + return 0; + } + same = rib; + break; + } + } + else + { + if (rib->type == type) + { + same = rib; + break; + } + } + } + + /* If same type of route can't be found and this message is from + kernel. */ + if (! same) + { + if (fib && type == ZEBRA_ROUTE_KERNEL) + { + /* Unset flags. */ + for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); + } + else + { + if (IS_ZEBRA_DEBUG_KERNEL) + { + if (gate) + zlog_info ("route %s/%d via %s ifindex %d type %d doesn't exist in rib", + inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + inet_ntop (AF_INET6, gate, buf2, BUFSIZ), + ifindex, + type); + else + zlog_info ("route %s/%d ifindex %d type %d doesn't exist in rib", + inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + ifindex, + type); + } + route_unlock_node (rn); + return ZEBRA_ERR_RTNOEXIST; + } + } + + if (same) + rib_delnode (rn, same); + + /* Process changes. */ + rib_process (rn, same); + + if (same) + { + newrib_free (same); + route_unlock_node (rn); + } + + route_unlock_node (rn); + + return 0; +} + +/* Install static route into rib. */ +void +static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) +{ + struct rib *rib; + struct route_table *table; + struct route_node *rn; + + /* Lookup table. */ + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (! table) + return; + + /* Lookup existing route */ + rn = route_node_get (table, p); + for (rib = rn->info; rib; rib = rib->next) + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) + break; + + if (rib) + { + /* Same distance static route is there. Update it with new + nexthop. */ + rib_uninstall (rn, rib); + route_unlock_node (rn); + + switch (si->type) + { + case STATIC_IPV6_GATEWAY: + nexthop_ipv6_add (rib, &si->ipv6); + break; + case STATIC_IPV6_IFNAME: + nexthop_ifname_add (rib, si->ifname); + break; + case STATIC_IPV6_GATEWAY_IFNAME: + nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname); + break; + } + 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 */ + +/* RIB update function. */ +void +rib_update () +{ + struct route_node *rn; + struct route_table *table; + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (table) + for (rn = route_top (table); rn; rn = route_next (rn)) + rib_process (rn, NULL); + + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (table) + for (rn = route_top (table); rn; rn = route_next (rn)) + rib_process (rn, NULL); +} + +/* Interface goes up. */ +void +rib_if_up (struct interface *ifp) +{ + rib_update (); +} + +/* Interface goes down. */ +void +rib_if_down (struct interface *ifp) +{ + rib_update (); +} + +/* Remove all routes which comes from non main table. */ +void +rib_weed_table (struct route_table *table) +{ + struct route_node *rn; + struct rib *rib; + struct rib *next; + + if (table) + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = next) + { + next = rib->next; + + if (rib->table != rtm_table_default && + rib->table != RT_TABLE_MAIN) + { + rib_delnode (rn, rib); + newrib_free (rib); + route_unlock_node (rn); + } + } +} + +/* Delete all routes from non main table. */ +void +rib_weed_tables () +{ + rib_weed_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); + rib_weed_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); +} + +/* Delete self installed routes after zebra is relaunched. */ +void +rib_sweep_table (struct route_table *table) +{ + struct route_node *rn; + struct rib *rib; + struct rib *next; + int ret = 0; + + if (table) + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = next) + { + next = rib->next; + + if (rib->type == ZEBRA_ROUTE_KERNEL && + CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELFROUTE)) + { + ret = rib_uninstall_kernel (rn, rib); + if (! ret) + { + rib_delnode (rn, rib); + newrib_free (rib); + route_unlock_node (rn); + } + } + } +} + +/* Sweep all RIB tables. */ +void +rib_sweep_route () +{ + rib_sweep_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); + rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); +} + +/* Close RIB and clean up kernel routes. */ +void +rib_close_table (struct route_table *table) +{ + struct route_node *rn; + struct rib *rib; + + if (table) + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + if (! RIB_SYSTEM_ROUTE (rib) + && CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + rib_uninstall_kernel (rn, rib); +} + +/* Close all RIB tables. */ +void +rib_close () +{ + rib_close_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); + rib_close_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); +} + +/* Routing information base initialize. */ +void +rib_init () +{ + /* VRF initialization. */ + vrf_init (); +} diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c new file mode 100644 index 00000000..d160bfa7 --- /dev/null +++ b/zebra/zebra_snmp.c @@ -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 + +#ifdef HAVE_SNMP +#include +#include +#include + +#include "if.h" +#include "log.h" +#include "prefix.h" +#include "command.h" +#include "smux.h" +#include "table.h" + +#include "zebra/rib.h" + +#define IPFWMIB 1,3,6,1,2,1,4,24 +#define ZEBRAOID 1,3,6,1,4,1,3317,1,2,1 + +/* ipForwardTable */ +#define IPFORWARDDEST 1 +#define IPFORWARDMASK 2 +#define IPFORWARDPOLICY 3 +#define IPFORWARDNEXTHOP 4 +#define IPFORWARDIFINDEX 5 +#define IPFORWARDTYPE 6 +#define IPFORWARDPROTO 7 +#define IPFORWARDAGE 8 +#define IPFORWARDINFO 9 +#define IPFORWARDNEXTHOPAS 10 +#define IPFORWARDMETRIC1 11 +#define IPFORWARDMETRIC2 12 +#define IPFORWARDMETRIC3 13 +#define IPFORWARDMETRIC4 14 +#define IPFORWARDMETRIC5 15 + +/* ipCidrRouteTable */ +#define IPCIDRROUTEDEST 1 +#define IPCIDRROUTEMASK 2 +#define IPCIDRROUTETOS 3 +#define IPCIDRROUTENEXTHOP 4 +#define IPCIDRROUTEIFINDEX 5 +#define IPCIDRROUTETYPE 6 +#define IPCIDRROUTEPROTO 7 +#define IPCIDRROUTEAGE 8 +#define IPCIDRROUTEINFO 9 +#define IPCIDRROUTENEXTHOPAS 10 +#define IPCIDRROUTEMETRIC1 11 +#define IPCIDRROUTEMETRIC2 12 +#define IPCIDRROUTEMETRIC3 13 +#define IPCIDRROUTEMETRIC4 14 +#define IPCIDRROUTEMETRIC5 15 +#define IPCIDRROUTESTATUS 16 + +#define INTEGER32 ASN_INTEGER +#define GAUGE32 ASN_GAUGE +#define ENUMERATION ASN_INTEGER +#define ROWSTATUS ASN_INTEGER +#define IPADDRESS ASN_IPADDRESS +#define OBJECTIDENTIFIER ASN_OBJECT_ID + +oid ipfw_oid [] = { IPFWMIB }; +oid zebra_oid [] = { ZEBRAOID }; + +/* Hook functions. */ +u_char * ipFwNumber (); +u_char * ipFwTable (); +u_char * ipCidrNumber (); +u_char * ipCidrTable (); + +struct variable zebra_variables[] = +{ + {0, GAUGE32, RONLY, ipFwNumber, 1, {1}}, + {IPFORWARDDEST, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 1}}, + {IPFORWARDMASK, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 2}}, + {IPFORWARDPOLICY, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 3}}, + {IPFORWARDNEXTHOP, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 4}}, + {IPFORWARDIFINDEX, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 5}}, + {IPFORWARDTYPE, ENUMERATION, RONLY, ipFwTable, 3, {2, 1, 6}}, + {IPFORWARDPROTO, ENUMERATION, RONLY, ipFwTable, 3, {2, 1, 7}}, + {IPFORWARDAGE, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 8}}, + {IPFORWARDINFO, OBJECTIDENTIFIER, RONLY, ipFwTable, 3, {2, 1, 9}}, + {IPFORWARDNEXTHOPAS, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 10}}, + {IPFORWARDMETRIC1, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 11}}, + {IPFORWARDMETRIC2, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 12}}, + {IPFORWARDMETRIC3, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 13}}, + {IPFORWARDMETRIC4, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 14}}, + {IPFORWARDMETRIC5, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 15}}, + {0, GAUGE32, RONLY, ipCidrNumber, 1, {3}}, + {IPCIDRROUTEDEST, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 1}}, + {IPCIDRROUTEMASK, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 2}}, + {IPCIDRROUTETOS, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 3}}, + {IPCIDRROUTENEXTHOP, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 4}}, + {IPCIDRROUTEIFINDEX, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 5}}, + {IPCIDRROUTETYPE, ENUMERATION, RONLY, ipCidrTable, 3, {4, 1, 6}}, + {IPCIDRROUTEPROTO, ENUMERATION, RONLY, ipCidrTable, 3, {4, 1, 7}}, + {IPCIDRROUTEAGE, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 8}}, + {IPCIDRROUTEINFO, OBJECTIDENTIFIER, RONLY, ipCidrTable, 3, {4, 1, 9}}, + {IPCIDRROUTENEXTHOPAS, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 10}}, + {IPCIDRROUTEMETRIC1, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 11}}, + {IPCIDRROUTEMETRIC2, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 12}}, + {IPCIDRROUTEMETRIC3, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 13}}, + {IPCIDRROUTEMETRIC4, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 14}}, + {IPCIDRROUTEMETRIC5, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 15}}, + {IPCIDRROUTESTATUS, ROWSTATUS, RONLY, ipCidrTable, 3, {4, 1, 16}} +}; + + +u_char * +ipFwNumber (struct variable *v, oid objid[], size_t *objid_len, + int exact, size_t *val_len, WriteMethod **write_method) +{ + static int result; + struct route_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 index 00000000..f6e7f51d --- /dev/null +++ b/zebra/zebra_vty.c @@ -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 + +#include "if.h" +#include "prefix.h" +#include "command.h" +#include "table.h" +#include "rib.h" + +/* Return route type string for VTY output. */ +const char * +route_type_str (u_char type) +{ + switch (type) + { + case ZEBRA_ROUTE_SYSTEM: + return "system"; + case ZEBRA_ROUTE_KERNEL: + return "kernel"; + case ZEBRA_ROUTE_CONNECT: + return "connected"; + case ZEBRA_ROUTE_STATIC: + return "static"; + case ZEBRA_ROUTE_RIP: + return "rip"; + case ZEBRA_ROUTE_RIPNG: + return "rip"; + case ZEBRA_ROUTE_OSPF: + return "ospf"; + case ZEBRA_ROUTE_OSPF6: + return "ospf"; + case ZEBRA_ROUTE_BGP: + return "bgp"; + default: + return "unknown"; + } +}; + +/* Return route type string for VTY output. */ +const char +route_type_char (u_char type) +{ + switch (type) + { + case ZEBRA_ROUTE_SYSTEM: + return 'S'; + case ZEBRA_ROUTE_KERNEL: + return 'K'; + case ZEBRA_ROUTE_CONNECT: + return 'C'; + case ZEBRA_ROUTE_STATIC: + return 'S'; + case ZEBRA_ROUTE_RIP: + return 'R'; + case ZEBRA_ROUTE_RIPNG: + return 'R'; + case ZEBRA_ROUTE_OSPF: + return 'O'; + case ZEBRA_ROUTE_OSPF6: + return 'O'; + case ZEBRA_ROUTE_BGP: + return 'B'; + default: + return '?'; + } +}; + +/* General fucntion for static route. */ +int +zebra_static_ipv4 (struct vty *vty, int add_cmd, + char *dest_str, char *mask_str, char *gate_str, + char *distance_str) +{ + int ret; + u_char distance; + struct prefix p; + struct in_addr gate; + struct in_addr mask; + char *ifname; + + ret = str2prefix (dest_str, &p); + if (ret <= 0) + { + vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Cisco like mask notation. */ + if (mask_str) + { + ret = inet_aton (mask_str, &mask); + if (ret == 0) + { + vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + p.prefixlen = ip_masklen (mask); + } + + /* Apply mask for given prefix. */ + apply_mask (&p); + + /* Administrative distance. */ + if (distance_str) + distance = atoi (distance_str); + else + distance = ZEBRA_STATIC_DISTANCE_DEFAULT; + + /* Null0 static route. */ + if (strncasecmp (gate_str, "Null0", strlen (gate_str)) == 0) + { + if (add_cmd) + static_add_ipv4 (&p, NULL, NULL, distance, 0); + else + static_delete_ipv4 (&p, NULL, NULL, distance, 0); + return CMD_SUCCESS; + } + + /* When gateway is A.B.C.D format, gate is treated as nexthop + address other case gate is treated as interface name. */ + ret = inet_aton (gate_str, &gate); + if (ret) + ifname = NULL; + else + ifname = gate_str; + + if (add_cmd) + static_add_ipv4 (&p, ifname ? NULL : &gate, ifname, distance, 0); + else + static_delete_ipv4 (&p, ifname ? NULL : &gate, ifname, distance, 0); + + return CMD_SUCCESS; +} + +/* Static route configuration. */ +DEFUN (ip_route, + ip_route_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0)", + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n") +{ + return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL); +} + +/* Mask as A.B.C.D format. */ +DEFUN (ip_route_mask, + ip_route_mask_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0)", + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n") +{ + return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL); +} + +/* Distance option value. */ +DEFUN (ip_route_distance, + ip_route_distance_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>", + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2]); +} + +DEFUN (ip_route_mask_distance, + ip_route_mask_distance_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>", + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3]); +} + +DEFUN (no_ip_route, + no_ip_route_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0)", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n") +{ + return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL); +} + +DEFUN (no_ip_route_mask, + no_ip_route_mask_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0)", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n") +{ + return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL); +} + +DEFUN (no_ip_route_distance, + no_ip_route_distance_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], argv[2]); +} + +DEFUN (no_ip_route_mask_distance, + no_ip_route_mask_distance_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], argv[3]); +} + +/* New RIB. Detailed information for IPv4 route. */ +void +vty_show_ip_route_detail (struct vty *vty, struct route_node *rn) +{ + struct rib *rib; + struct nexthop *nexthop; + + for (rib = rn->info; rib; rib = rib->next) + { + vty_out (vty, "Routing entry for %s/%d%s", + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, + VTY_NEWLINE); + vty_out (vty, " Known via \"%s\"", route_type_str (rib->type)); + vty_out (vty, ", distance %d, metric %d", rib->distance, rib->metric); + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + vty_out (vty, ", best"); + if (rib->refcnt) + vty_out (vty, ", refcnt %ld", rib->refcnt); + vty_out (vty, "%s", VTY_NEWLINE); + +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + if (rib->type == ZEBRA_ROUTE_RIP + || rib->type == ZEBRA_ROUTE_OSPF + || rib->type == ZEBRA_ROUTE_BGP) + { + time_t uptime; + struct tm *tm; + + uptime = time (NULL); + uptime -= rib->uptime; + tm = gmtime (&uptime); + + vty_out (vty, " Last update "); + + if (uptime < ONE_DAY_SECOND) + vty_out (vty, "%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (uptime < ONE_WEEK_SECOND) + vty_out (vty, "%dd%02dh%02dm", + tm->tm_yday, tm->tm_hour, tm->tm_min); + else + vty_out (vty, "%02dw%dd%02dh", + tm->tm_yday/7, + tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + vty_out (vty, " ago%s", VTY_NEWLINE); + } + + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + vty_out (vty, " %c", + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' '); + + switch (nexthop->type) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out (vty, " %s", inet_ntoa (nexthop->gate.ipv4)); + if (nexthop->ifindex) + vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFINDEX: + vty_out (vty, " directly connected, %s", + ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFNAME: + vty_out (vty, " directly connected, %s", nexthop->ifname); + break; + case NEXTHOP_TYPE_BLACKHOLE: + vty_out (vty, " directly connected, via Null0"); + break; + default: + break; + } + if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + vty_out (vty, " inactive"); + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + vty_out (vty, " (recursive"); + + switch (nexthop->rtype) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out (vty, " via %s)", inet_ntoa (nexthop->rgate.ipv4)); + break; + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_IFNAME: + vty_out (vty, " is directly connected, %s)", + ifindex2ifname (nexthop->rifindex)); + break; + default: + break; + } + } + vty_out (vty, "%s", VTY_NEWLINE); + } + vty_out (vty, "%s", VTY_NEWLINE); + } +} + +void +vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) +{ + struct nexthop *nexthop; + int len = 0; + char buf[BUFSIZ]; + + /* Nexthop information. */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + if (nexthop == rib->nexthop) + { + /* Prefix information. */ + len = vty_out (vty, "%c%c%c %s/%d", + route_type_char (rib->type), + CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) + ? '>' : ' ', + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) + ? '*' : ' ', + inet_ntop (AF_INET, &rn->p.u.prefix, buf, BUFSIZ), + rn->p.prefixlen); + + /* Distance and metric display. */ + if (rib->type != ZEBRA_ROUTE_CONNECT + && rib->type != ZEBRA_ROUTE_KERNEL) + len += vty_out (vty, " [%d/%d]", rib->distance, + rib->metric); + } + else + vty_out (vty, " %c%*c", + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) + ? '*' : ' ', + len - 3, ' '); + + switch (nexthop->type) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4)); + if (nexthop->ifindex) + vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFINDEX: + vty_out (vty, " is directly connected, %s", + ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFNAME: + vty_out (vty, " is directly connected, %s", nexthop->ifname); + break; + case NEXTHOP_TYPE_BLACKHOLE: + vty_out (vty, " is directly connected, Null0"); + default: + break; + } + if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + vty_out (vty, " inactive"); + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + vty_out (vty, " (recursive"); + + switch (nexthop->rtype) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out (vty, " via %s)", inet_ntoa (nexthop->rgate.ipv4)); + break; + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_IFNAME: + vty_out (vty, " is directly connected, %s)", + ifindex2ifname (nexthop->rifindex)); + break; + default: + break; + } + } + + if (rib->type == ZEBRA_ROUTE_RIP + || rib->type == ZEBRA_ROUTE_OSPF + || rib->type == ZEBRA_ROUTE_BGP) + { + time_t uptime; + struct tm *tm; + + uptime = time (NULL); + uptime -= rib->uptime; + tm = gmtime (&uptime); + +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + + if (uptime < ONE_DAY_SECOND) + vty_out (vty, ", %02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (uptime < ONE_WEEK_SECOND) + vty_out (vty, ", %dd%02dh%02dm", + tm->tm_yday, tm->tm_hour, tm->tm_min); + else + vty_out (vty, ", %02dw%dd%02dh", + tm->tm_yday/7, + tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + } + vty_out (vty, "%s", VTY_NEWLINE); + } +} + +#define SHOW_ROUTE_V4_HEADER "Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF,%s B - BGP, > - selected route, * - FIB route%s%s" + +DEFUN (show_ip_route, + show_ip_route_cmd, + "show ip route", + SHOW_STR + IP_STR + "IP routing table\n") +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + int first = 1; + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + /* Show all IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, VTY_NEWLINE, + VTY_NEWLINE); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +DEFUN (show_ip_route_prefix_longer, + show_ip_route_prefix_longer_cmd, + "show ip route A.B.C.D/M longer-prefixes", + SHOW_STR + IP_STR + "IP routing table\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Show route matching the specified Network/Mask pair only\n") +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + struct prefix p; + int ret; + int first = 1; + + ret = str2prefix (argv[0], &p); + if (! ret) + { + vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + /* Show matched type IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + if (prefix_match (&p, &rn->p)) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, + VTY_NEWLINE, VTY_NEWLINE); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +DEFUN (show_ip_route_supernets, + show_ip_route_supernets_cmd, + "show ip route supernets-only", + SHOW_STR + IP_STR + "IP routing table\n" + "Show supernet entries only\n") +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + u_int32_t addr; + int first = 1; + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + /* Show matched type IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + { + addr = ntohl (rn->p.u.prefix4.s_addr); + + if ((IN_CLASSC (addr) && rn->p.prefixlen < 24) + || (IN_CLASSB (addr) && rn->p.prefixlen < 16) + || (IN_CLASSA (addr) && rn->p.prefixlen < 8)) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, + VTY_NEWLINE, VTY_NEWLINE); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + } + return CMD_SUCCESS; +} + +DEFUN (show_ip_route_protocol, + show_ip_route_protocol_cmd, + "show ip route (bgp|connected|kernel|ospf|rip|static)", + SHOW_STR + IP_STR + "IP routing table\n" + "Border Gateway Protocol (BGP)\n" + "Connected\n" + "Kernel\n" + "Open Shortest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n") +{ + int type; + struct route_table *table; + struct route_node *rn; + struct rib *rib; + int first = 1; + + if (strncmp (argv[0], "b", 1) == 0) + type = ZEBRA_ROUTE_BGP; + else if (strncmp (argv[0], "c", 1) == 0) + type = ZEBRA_ROUTE_CONNECT; + else if (strncmp (argv[0], "k", 1) ==0) + type = ZEBRA_ROUTE_KERNEL; + else if (strncmp (argv[0], "o", 1) == 0) + type = ZEBRA_ROUTE_OSPF; + else if (strncmp (argv[0], "r", 1) == 0) + type = ZEBRA_ROUTE_RIP; + else if (strncmp (argv[0], "s", 1) == 0) + type = ZEBRA_ROUTE_STATIC; + else + { + vty_out (vty, "Unknown route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + /* Show matched type IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + if (rib->type == type) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER, + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +DEFUN (show_ip_route_addr, + show_ip_route_addr_cmd, + "show ip route A.B.C.D", + SHOW_STR + IP_STR + "IP routing table\n" + "Network in the IP routing table to display\n") +{ + int ret; + struct prefix_ipv4 p; + struct route_table *table; + struct route_node *rn; + + ret = str2prefix_ipv4 (argv[0], &p); + if (ret <= 0) + { + vty_out (vty, "%% Malformed IPv4 address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + rn = route_node_match (table, (struct prefix *) &p); + if (! rn) + { + vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); + return CMD_WARNING; + } + + vty_show_ip_route_detail (vty, rn); + + route_unlock_node (rn); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_route_prefix, + show_ip_route_prefix_cmd, + "show ip route A.B.C.D/M", + SHOW_STR + IP_STR + "IP routing table\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + int ret; + struct prefix_ipv4 p; + struct route_table *table; + struct route_node *rn; + + ret = str2prefix_ipv4 (argv[0], &p); + if (ret <= 0) + { + vty_out (vty, "%% Malformed IPv4 address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + rn = route_node_match (table, (struct prefix *) &p); + if (! rn || rn->p.prefixlen != p.prefixlen) + { + vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); + return CMD_WARNING; + } + + vty_show_ip_route_detail (vty, rn); + + route_unlock_node (rn); + + return CMD_SUCCESS; +} + +void +zebra_show_ip_route (struct vty *vty, struct vrf *vrf) +{ + vty_out (vty, "IP routing table name is %s(%d)%s", + vrf->name ? vrf->name : "", vrf->id, VTY_NEWLINE); + + vty_out (vty, "Route Source Networks%s", VTY_NEWLINE); + vty_out (vty, "connected %d%s", 0, VTY_NEWLINE); + vty_out (vty, "static %d%s", 0, VTY_NEWLINE); + vty_out (vty, "rip %d%s", 0, VTY_NEWLINE); + + vty_out (vty, "bgp %d%s", 0, VTY_NEWLINE); + vty_out (vty, " External: %d Internal: %d Local: %d%s", + 0, 0, 0, VTY_NEWLINE); + + vty_out (vty, "ospf %d%s", 0, VTY_NEWLINE); + vty_out (vty, + " Intra-area: %d Inter-area: %d External-1: %d External-2: %d%s", + 0, 0, 0, 0, VTY_NEWLINE); + vty_out (vty, " NSSA External-1: %d NSSA External-2: %d%s", + 0, 0, VTY_NEWLINE); + + vty_out (vty, "internal %d%s", 0, VTY_NEWLINE); + vty_out (vty, "Total %d%s", 0, VTY_NEWLINE); +} + +/* Show route summary. */ +DEFUN (show_ip_route_summary, + show_ip_route_summary_cmd, + "show ip route summary", + SHOW_STR + IP_STR + "IP routing table\n" + "Summary of all routes\n") +{ + struct vrf *vrf; + + /* Default table id is zero. */ + vrf = vrf_lookup (0); + if (! vrf) + { + vty_out (vty, "%% No Default-IP-Routing-Table%s", VTY_NEWLINE); + return CMD_WARNING; + } + + zebra_show_ip_route (vty, vrf); + + return CMD_SUCCESS; +} + +/* Write IPv4 static route configuration. */ +int +static_config_ipv4 (struct vty *vty) +{ + struct route_node *rn; + struct static_ipv4 *si; + struct route_table *stable; + int write; + + write = 0; + + /* Lookup table. */ + stable = vrf_static_table (AFI_IP, SAFI_UNICAST, 0); + if (! stable) + return -1; + + for (rn = route_top (stable); rn; rn = route_next (rn)) + for (si = rn->info; si; si = si->next) + { + vty_out (vty, "ip route %s/%d", inet_ntoa (rn->p.u.prefix4), + rn->p.prefixlen); + + switch (si->type) + { + case STATIC_IPV4_GATEWAY: + vty_out (vty, " %s", inet_ntoa (si->gate.ipv4)); + break; + case STATIC_IPV4_IFNAME: + vty_out (vty, " %s", si->gate.ifname); + break; + case STATIC_IPV4_BLACKHOLE: + vty_out (vty, " Null0"); + break; + } + + if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) + vty_out (vty, " %d", si->distance); + vty_out (vty, "%s", VTY_NEWLINE); + + write = 1; + } + return write; +} + +#ifdef HAVE_IPV6 +/* General fucntion for IPv6 static route. */ +int +static_ipv6_func (struct vty *vty, int add_cmd, char *dest_str, + char *gate_str, char *ifname, char *distance_str) +{ + int ret; + u_char distance; + struct prefix p; + struct in6_addr *gate = NULL; + struct in6_addr gate_addr; + u_char type = 0; + int table = 0; + + ret = str2prefix (dest_str, &p); + if (ret <= 0) + { + vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Apply mask for given prefix. */ + apply_mask (&p); + + /* Administrative distance. */ + if (distance_str) + distance = atoi (distance_str); + else + distance = ZEBRA_STATIC_DISTANCE_DEFAULT; + + /* 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 index 00000000..47114ab3 --- /dev/null +++ b/zebra/zserv.c @@ -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 + +#include "prefix.h" +#include "command.h" +#include "if.h" +#include "thread.h" +#include "stream.h" +#include "memory.h" +#include "table.h" +#include "rib.h" +#include "network.h" +#include "sockunion.h" +#include "log.h" +#include "zclient.h" + +#include "zebra/zserv.h" +#include "zebra/redistribute.h" +#include "zebra/debug.h" +#include "zebra/ipforward.h" + +/* Event list of zebra. */ +enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; + +/* Zebra client list. */ +list client_list; + +/* Default rtm_table for all clients */ +int rtm_table_default = 0; + +void zebra_event (enum event event, int sock, struct zserv *client); + +/* 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" +}; + +/* 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)); +} + +/* 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 + +/* zebra server UNIX domain socket. */ +void +zebra_serv_un (char *path) +{ + int ret; + int sock, len; + struct sockaddr_un serv; + mode_t old_mask; + + /* First of all, unlink existing socket */ + unlink (path); + + /* Set umask */ + old_mask = umask (0077); + + /* Make UNIX domain socket. */ + sock = socket (AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + { + perror ("sock"); + return; + } + + /* Make server socket. */ + memset (&serv, 0, sizeof (struct sockaddr_un)); + serv.sun_family = AF_UNIX; + strncpy (serv.sun_path, path, strlen (path)); +#ifdef HAVE_SUN_LEN + len = serv.sun_len = SUN_LEN(&serv); +#else + len = sizeof (serv.sun_family) + strlen (serv.sun_path); +#endif /* HAVE_SUN_LEN */ + + ret = bind (sock, (struct sockaddr *) &serv, len); + if (ret < 0) + { + perror ("bind"); + close (sock); + return; + } + + ret = listen (sock, 5); + if (ret < 0) + { + perror ("listen"); + close (sock); + return; + } + + umask (old_mask); + + zebra_event (ZEBRA_SERV, sock, NULL); +} + +/* Zebra's event management function. */ +extern struct thread_master *master; + +void +zebra_event (enum event event, int sock, struct zserv *client) +{ + switch (event) + { + case ZEBRA_SERV: + thread_add_read (master, zebra_accept, client, sock); + break; + case ZEBRA_READ: + client->t_read = + thread_add_read (master, zebra_client_read, client, sock); + break; + case ZEBRA_WRITE: + /**/ + break; + } +} + +/* Display default rtm_table for all clients. */ +DEFUN (show_table, + show_table_cmd, + "show table", + SHOW_STR + "default routing table to use for all clients\n") +{ + vty_out (vty, "table %d%s", rtm_table_default, + VTY_NEWLINE); + return CMD_SUCCESS; +} + +DEFUN (config_table, + config_table_cmd, + "table TABLENO", + "Configure target kernel routing table\n" + "TABLE integer\n") +{ + rtm_table_default = strtol (argv[0], (char**)0, 10); + return CMD_SUCCESS; +} + +DEFUN (no_ip_forwarding, + no_ip_forwarding_cmd, + "no ip forwarding", + NO_STR + IP_STR + "Turn off IP forwarding") +{ + int ret; + + ret = ipforward (); + + if (ret == 0) + { + vty_out (vty, "IP forwarding is already off%s", VTY_NEWLINE); + return CMD_ERR_NOTHING_TODO; + } + + ret = ipforward_off (); + if (ret != 0) + { + vty_out (vty, "Can't turn off IP forwarding%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +/* This command is for debugging purpose. */ +DEFUN (show_zebra_client, + show_zebra_client_cmd, + "show zebra client", + SHOW_STR + "Zebra information" + "Client information") +{ + listnode node; + struct zserv *client; + + for (node = listhead (client_list); node; nextnode (node)) + { + client = getdata (node); + vty_out (vty, "Client fd %d%s", client->sock, VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +/* Table configuration write function. */ +int +config_write_table (struct vty *vty) +{ + if (rtm_table_default) + vty_out (vty, "table %d%s", rtm_table_default, + VTY_NEWLINE); + return 0; +} + +/* table node for routing tables. */ +struct cmd_node table_node = +{ + TABLE_NODE, + "", /* This node has no interface. */ + 1 +}; + +/* Only display ip forwarding is enabled or not. */ +DEFUN (show_ip_forwarding, + show_ip_forwarding_cmd, + "show ip forwarding", + SHOW_STR + IP_STR + "IP forwarding status\n") +{ + int ret; + + ret = ipforward (); + + if (ret == 0) + vty_out (vty, "IP forwarding is off%s", VTY_NEWLINE); + else + vty_out (vty, "IP forwarding is on%s", VTY_NEWLINE); + return CMD_SUCCESS; +} + +#ifdef HAVE_IPV6 +/* Only display ipv6 forwarding is enabled or not. */ +DEFUN (show_ipv6_forwarding, + show_ipv6_forwarding_cmd, + "show ipv6 forwarding", + SHOW_STR + "IPv6 information\n" + "Forwarding status\n") +{ + int ret; + + ret = ipforward_ipv6 (); + + switch (ret) + { + case -1: + vty_out (vty, "ipv6 forwarding is unknown%s", VTY_NEWLINE); + break; + case 0: + vty_out (vty, "ipv6 forwarding is %s%s", "off", VTY_NEWLINE); + break; + case 1: + vty_out (vty, "ipv6 forwarding is %s%s", "on", VTY_NEWLINE); + break; + default: + vty_out (vty, "ipv6 forwarding is %s%s", "off", VTY_NEWLINE); + break; + } + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_forwarding, + no_ipv6_forwarding_cmd, + "no ipv6 forwarding", + NO_STR + IP_STR + "Doesn't forward IPv6 protocol packet") +{ + int ret; + + ret = ipforward_ipv6_off (); + if (ret != 0) + { + vty_out (vty, "Can't turn off IPv6 forwarding%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +#endif /* HAVE_IPV6 */ + +/* IPForwarding configuration write function. */ +int +config_write_forwarding (struct vty *vty) +{ + if (! ipforward ()) + vty_out (vty, "no ip forwarding%s", VTY_NEWLINE); +#ifdef HAVE_IPV6 + if (! ipforward_ipv6 ()) + vty_out (vty, "no ipv6 forwarding%s", VTY_NEWLINE); +#endif /* HAVE_IPV6 */ + vty_out (vty, "!%s", VTY_NEWLINE); + return 0; +} + +/* table node for routing tables. */ +struct cmd_node forwarding_node = +{ + FORWARDING_NODE, + "", /* This node has no interface. */ + 1 +}; + + +/* Initialisation of zebra and installation of commands. */ +void +zebra_init () +{ + /* Client list init. */ + client_list = list_new (); + + /* Forwarding is on by default. */ + ipforward_on (); +#ifdef HAVE_IPV6 + ipforward_ipv6_on (); +#endif /* HAVE_IPV6 */ + + /* Make zebra server socket. */ +#ifdef HAVE_TCP_ZEBRA + zebra_serv (); +#else + zebra_serv_un (ZEBRA_SERV_PATH); +#endif /* HAVE_TCP_ZEBRA */ + + /* Install configuration write function. */ + install_node (&table_node, config_write_table); + install_node (&forwarding_node, config_write_forwarding); + + install_element (VIEW_NODE, &show_ip_forwarding_cmd); + install_element (ENABLE_NODE, &show_ip_forwarding_cmd); + install_element (CONFIG_NODE, &no_ip_forwarding_cmd); + install_element (ENABLE_NODE, &show_zebra_client_cmd); + +#ifdef HAVE_NETLINK + install_element (VIEW_NODE, &show_table_cmd); + install_element (ENABLE_NODE, &show_table_cmd); + install_element (CONFIG_NODE, &config_table_cmd); +#endif /* HAVE_NETLINK */ + +#ifdef HAVE_IPV6 + install_element (VIEW_NODE, &show_ipv6_forwarding_cmd); + install_element (ENABLE_NODE, &show_ipv6_forwarding_cmd); + install_element (CONFIG_NODE, &no_ipv6_forwarding_cmd); +#endif /* HAVE_IPV6 */ +} diff --git a/zebra/zserv.h b/zebra/zserv.h new file mode 100644 index 00000000..c7622808 --- /dev/null +++ b/zebra/zserv.h @@ -0,0 +1,132 @@ +/* Zebra daemon server header. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_ZSERV_H +#define _ZEBRA_ZSERV_H + +/* Default port information. */ +#define ZEBRA_PORT 2600 +#define ZEBRA_VTY_PORT 2601 +#define ZEBRA_VTYSH_PATH "/tmp/.zebra" +#define ZEBRA_SERV_PATH "/tmp/.zserv" + +/* Default configuration filename. */ +#define DEFAULT_CONFIG_FILE "zebra.conf" + +/* Client structure. */ +struct zserv +{ + /* Client file descriptor. */ + int sock; + + /* Input/output buffer to the client. */ + struct stream *ibuf; + struct stream *obuf; + + /* Threads for read/write. */ + struct thread *t_read; + struct thread *t_write; + + /* default routing table this client munges */ + int rtm_table; + + /* This client's redistribute flag. */ + u_char redist[ZEBRA_ROUTE_MAX]; + + /* Redistribute default route flag. */ + u_char redist_default; + + /* Interface information. */ + u_char ifinfo; +}; + +/* Count prefix size from mask length */ +#define PSIZE(a) (((a) + 7) / (8)) + +/* Prototypes. */ +void zebra_init (); +void zebra_if_init (); +void hostinfo_get (); +void rib_init (); +void interface_list (); +void kernel_init (); +void route_read (); +void rtadv_init (); +void zebra_snmp_init (); + +int +zsend_interface_add (struct zserv *, struct interface *); +int +zsend_interface_delete (struct zserv *, struct interface *); + +int +zsend_interface_address_add (struct zserv *, struct interface *, + struct connected *); + +int +zsend_interface_address_delete (struct zserv *, struct interface *, + struct connected *); + +int +zsend_interface_up (struct zserv *, struct interface *); + +int +zsend_interface_down (struct zserv *, struct interface *); + +int +zsend_ipv4_add (struct zserv *client, int type, int flags, + struct prefix_ipv4 *p, struct in_addr *nexthop, + unsigned int ifindex); + +int +zsend_ipv4_delete (struct zserv *client, int type, int flags, + struct prefix_ipv4 *p, struct in_addr *nexthop, + unsigned int ifindex); + +int +zsend_ipv4_add_multipath (struct zserv *, struct prefix *, struct rib *); + +int +zsend_ipv4_delete_multipath (struct zserv *, struct prefix *, struct rib *); + +#ifdef HAVE_IPV6 +int +zsend_ipv6_add (struct zserv *client, int type, int flags, + struct prefix_ipv6 *p, struct in6_addr *nexthop, + unsigned int ifindex); + +int +zsend_ipv6_delete (struct zserv *client, int type, int flags, + struct prefix_ipv6 *p, struct in6_addr *nexthop, + unsigned int ifindex); + +int +zsend_ipv6_add_multipath (struct zserv *, struct prefix *, struct rib *); + +int +zsend_ipv6_delete_multipath (struct zserv *, struct prefix *, struct rib *); + +#endif /* HAVE_IPV6 */ + +extern pid_t pid; +extern pid_t old_pid; + +#endif /* _ZEBRA_ZEBRA_H */ -- cgit v1.2.1