summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpaul <paul>2002-12-13 20:15:29 +0000
committerpaul <paul>2002-12-13 20:15:29 +0000
commit718e3744195351130f4ce7dbe0613f4b3e23df93 (patch)
treebac2ad39971cd43f31241ef123bd4e470f695ac9
Initial revision
-rw-r--r--.cvsignore10
-rw-r--r--AUTHORS6
-rw-r--r--COPYING339
-rw-r--r--COPYING.LIB482
-rw-r--r--ChangeLog674
-rw-r--r--INSTALL181
-rw-r--r--Makefile.am16
-rw-r--r--Makefile.in548
-rw-r--r--NEWS2338
-rw-r--r--README12
-rw-r--r--REPORTING-BUGS28
-rw-r--r--SERVICES17
-rw-r--r--TODO29
-rw-r--r--acconfig.h161
-rw-r--r--aclocal.m4811
-rw-r--r--bgpd/.cvsignore8
-rw-r--r--bgpd/BGP4-MIB.txt929
-rw-r--r--bgpd/ChangeLog2368
-rw-r--r--bgpd/Makefile.am44
-rw-r--r--bgpd/Makefile.in534
-rw-r--r--bgpd/bgp_advertise.c405
-rw-r--r--bgpd/bgp_advertise.h178
-rw-r--r--bgpd/bgp_aspath.c1186
-rw-r--r--bgpd/bgp_aspath.h77
-rw-r--r--bgpd/bgp_attr.c1838
-rw-r--r--bgpd/bgp_attr.h125
-rw-r--r--bgpd/bgp_btoa.c291
-rw-r--r--bgpd/bgp_clist.c905
-rw-r--r--bgpd/bgp_clist.h143
-rw-r--r--bgpd/bgp_community.c629
-rw-r--r--bgpd/bgp_community.h68
-rw-r--r--bgpd/bgp_damp.c648
-rw-r--r--bgpd/bgp_damp.h141
-rw-r--r--bgpd/bgp_debug.c732
-rw-r--r--bgpd/bgp_debug.h113
-rw-r--r--bgpd/bgp_dump.c741
-rw-r--r--bgpd/bgp_dump.h34
-rw-r--r--bgpd/bgp_ecommunity.c641
-rw-r--r--bgpd/bgp_ecommunity.h72
-rw-r--r--bgpd/bgp_filter.c658
-rw-r--r--bgpd/bgp_filter.h31
-rw-r--r--bgpd/bgp_fsm.c864
-rw-r--r--bgpd/bgp_fsm.h42
-rw-r--r--bgpd/bgp_main.c285
-rw-r--r--bgpd/bgp_mplsvpn.c741
-rw-r--r--bgpd/bgp_mplsvpn.h45
-rw-r--r--bgpd/bgp_network.c381
-rw-r--r--bgpd/bgp_network.h23
-rw-r--r--bgpd/bgp_nexthop.c1405
-rw-r--r--bgpd/bgp_nexthop.h52
-rw-r--r--bgpd/bgp_open.c793
-rw-r--r--bgpd/bgp_open.h69
-rw-r--r--bgpd/bgp_packet.c2240
-rw-r--r--bgpd/bgp_packet.h49
-rw-r--r--bgpd/bgp_regex.c93
-rw-r--r--bgpd/bgp_regex.h31
-rw-r--r--bgpd/bgp_route.c9053
-rw-r--r--bgpd/bgp_route.h159
-rw-r--r--bgpd/bgp_routemap.c3207
-rw-r--r--bgpd/bgp_snmp.c875
-rw-r--r--bgpd/bgp_snmp.h23
-rw-r--r--bgpd/bgp_table.c489
-rw-r--r--bgpd/bgp_table.h65
-rw-r--r--bgpd/bgp_view.c258
-rw-r--r--bgpd/bgp_vty.c9416
-rw-r--r--bgpd/bgp_vty.h21
-rw-r--r--bgpd/bgp_zebra.c1001
-rw-r--r--bgpd/bgp_zebra.h39
-rw-r--r--bgpd/bgpd.c4601
-rw-r--r--bgpd/bgpd.conf.sample29
-rw-r--r--bgpd/bgpd.conf.sample277
-rw-r--r--bgpd/bgpd.h824
-rwxr-xr-xconfig.guess1321
-rw-r--r--config.h.in367
-rwxr-xr-xconfig.sub1332
-rwxr-xr-xconfigure8114
-rwxr-xr-xconfigure.in873
-rwxr-xr-xdepcomp423
-rw-r--r--doc/.cvsignore3
-rw-r--r--doc/BGP-TypeCode24
-rw-r--r--doc/ChangeLog90
-rw-r--r--doc/Makefile.am14
-rw-r--r--doc/Makefile.in482
-rw-r--r--doc/appendix.texi238
-rw-r--r--doc/basic.texi510
-rw-r--r--doc/bgpd.8169
-rw-r--r--doc/bgpd.texi1288
-rw-r--r--doc/draft-zebra-00.ms209
-rw-r--r--doc/filter.texi192
-rw-r--r--doc/install.texi218
-rw-r--r--doc/ipv6.texi32
-rw-r--r--doc/kernel.texi48
-rw-r--r--doc/main.texi186
-rw-r--r--doc/ospf6d.8127
-rw-r--r--doc/ospf6d.texi102
-rw-r--r--doc/ospfd.8131
-rw-r--r--doc/ospfd.texi345
-rw-r--r--doc/overview.texi352
-rw-r--r--doc/protocol.texi52
-rw-r--r--doc/ripd.8212
-rw-r--r--doc/ripd.texi584
-rw-r--r--doc/ripngd.8143
-rw-r--r--doc/ripngd.texi85
-rw-r--r--doc/routemap.texi91
-rw-r--r--doc/snmp.texi68
-rw-r--r--doc/texinfo.tex5625
-rw-r--r--doc/vtysh.168
-rw-r--r--doc/vtysh.texi27
-rw-r--r--doc/zebra.8146
-rw-r--r--doc/zebra.info170
-rw-r--r--doc/zebra.texi150
-rw-r--r--guile/.cvsignore3
-rw-r--r--guile/ChangeLog26
-rw-r--r--guile/Makefile.am9
-rw-r--r--guile/Makefile.in299
-rw-r--r--guile/README17
-rw-r--r--guile/guile-bgp.c117
-rw-r--r--guile/zebra-guile.c71
-rw-r--r--guile/zebra-guile.h21
-rw-r--r--guile/zebra-support.c19
-rw-r--r--init/.cvsignore2
-rw-r--r--init/ChangeLog39
-rw-r--r--init/redhat/bgpd.init45
-rw-r--r--init/redhat/ospf6d.init45
-rw-r--r--init/redhat/ospfd.init45
-rw-r--r--init/redhat/ripd.init45
-rw-r--r--init/redhat/ripngd.init45
-rw-r--r--init/redhat/zebra.init45
-rw-r--r--init/redhat/zebra.logrotate47
-rw-r--r--init/redhat/zebra.spec.in128
-rwxr-xr-xinstall-sh251
-rw-r--r--lib/.cvsignore4
-rw-r--r--lib/ChangeLog1926
-rw-r--r--lib/Makefile.am29
-rw-r--r--lib/Makefile.in469
-rw-r--r--lib/buffer.c568
-rw-r--r--lib/buffer.h77
-rw-r--r--lib/checksum.c47
-rw-r--r--lib/command.c2981
-rw-r--r--lib/command.h308
-rw-r--r--lib/daemon.c80
-rw-r--r--lib/distribute.c709
-rw-r--r--lib/distribute.h57
-rw-r--r--lib/filter.c2058
-rw-r--r--lib/filter.h67
-rw-r--r--lib/getopt.c1054
-rw-r--r--lib/getopt.h133
-rw-r--r--lib/getopt1.c190
-rw-r--r--lib/hash.c182
-rw-r--r--lib/hash.h71
-rw-r--r--lib/if.c713
-rw-r--r--lib/if.h222
-rw-r--r--lib/if_rmap.c305
-rw-r--r--lib/if_rmap.h47
-rw-r--r--lib/keychain.c1001
-rw-r--r--lib/keychain.h56
-rw-r--r--lib/linklist.c312
-rw-r--r--lib/linklist.h101
-rw-r--r--lib/log.c483
-rw-r--r--lib/log.h128
-rw-r--r--lib/md5-gnu.h156
-rw-r--r--lib/md5.c447
-rw-r--r--lib/memory.c493
-rw-r--r--lib/memory.h245
-rw-r--r--lib/network.c71
-rw-r--r--lib/network.h29
-rw-r--r--lib/pid_output.c77
-rw-r--r--lib/plist.c2881
-rw-r--r--lib/plist.h78
-rw-r--r--lib/prefix.c696
-rw-r--r--lib/prefix.h161
-rw-r--r--lib/print_version.c31
-rw-r--r--lib/regex-gnu.h542
-rw-r--r--lib/regex.c5891
-rw-r--r--lib/routemap.c1077
-rw-r--r--lib/routemap.h194
-rw-r--r--lib/smux.c1501
-rw-r--r--lib/smux.h159
-rw-r--r--lib/sockopt.c199
-rw-r--r--lib/sockopt.h41
-rw-r--r--lib/sockunion.c756
-rw-r--r--lib/sockunion.h128
-rw-r--r--lib/str.c62
-rw-r--r--lib/str.h24
-rw-r--r--lib/stream.c479
-rw-r--r--lib/stream.h113
-rw-r--r--lib/table.c503
-rw-r--r--lib/table.h74
-rw-r--r--lib/tcpfilter.c69
-rw-r--r--lib/tcpfilter.h21
-rw-r--r--lib/thread.c668
-rw-r--r--lib/thread.h139
-rw-r--r--lib/vector.c189
-rw-r--r--lib/vector.h58
-rw-r--r--lib/version.h39
-rw-r--r--lib/vty.c2792
-rw-r--r--lib/vty.h205
-rw-r--r--lib/zclient.c901
-rw-r--r--lib/zclient.h164
-rw-r--r--lib/zebra.h312
-rwxr-xr-xmissing336
-rwxr-xr-xmkinstalldirs101
-rw-r--r--ospf6d/.cvsignore8
-rw-r--r--ospf6d/ChangeLog809
-rw-r--r--ospf6d/Makefile.am48
-rw-r--r--ospf6d/Makefile.in549
-rw-r--r--ospf6d/README85
-rw-r--r--ospf6d/ospf6_abr.c655
-rw-r--r--ospf6d/ospf6_abr.h56
-rw-r--r--ospf6d/ospf6_area.c332
-rw-r--r--ospf6d/ospf6_area.h90
-rw-r--r--ospf6d/ospf6_asbr.c1040
-rw-r--r--ospf6d/ospf6_asbr.h112
-rw-r--r--ospf6d/ospf6_bintree.c436
-rw-r--r--ospf6d/ospf6_bintree.h47
-rw-r--r--ospf6d/ospf6_damp.c748
-rw-r--r--ospf6d/ospf6_damp.h109
-rw-r--r--ospf6d/ospf6_dbex.c704
-rw-r--r--ospf6d/ospf6_dbex.h59
-rw-r--r--ospf6d/ospf6_dump.c314
-rw-r--r--ospf6d/ospf6_dump.h95
-rw-r--r--ospf6d/ospf6_hook.c174
-rw-r--r--ospf6d/ospf6_hook.h87
-rw-r--r--ospf6d/ospf6_interface.c1028
-rw-r--r--ospf6d/ospf6_interface.h153
-rw-r--r--ospf6d/ospf6_intra.c896
-rw-r--r--ospf6d/ospf6_intra.h31
-rw-r--r--ospf6d/ospf6_ism.c519
-rw-r--r--ospf6d/ospf6_ism.h53
-rw-r--r--ospf6d/ospf6_linklist.c193
-rw-r--r--ospf6d/ospf6_linklist.h35
-rw-r--r--ospf6d/ospf6_lsa.c1926
-rw-r--r--ospf6d/ospf6_lsa.h426
-rw-r--r--ospf6d/ospf6_lsdb.c723
-rw-r--r--ospf6d/ospf6_lsdb.h88
-rw-r--r--ospf6d/ospf6_main.c326
-rw-r--r--ospf6d/ospf6_message.c1972
-rw-r--r--ospf6d/ospf6_message.h202
-rw-r--r--ospf6d/ospf6_neighbor.c602
-rw-r--r--ospf6d/ospf6_neighbor.h161
-rw-r--r--ospf6d/ospf6_network.c501
-rw-r--r--ospf6d/ospf6_network.h58
-rw-r--r--ospf6d/ospf6_nsm.c391
-rw-r--r--ospf6d/ospf6_nsm.h67
-rw-r--r--ospf6d/ospf6_prefix.c213
-rw-r--r--ospf6d/ospf6_prefix.h83
-rw-r--r--ospf6d/ospf6_proto.c40
-rw-r--r--ospf6d/ospf6_proto.h75
-rw-r--r--ospf6d/ospf6_route.c1130
-rw-r--r--ospf6d/ospf6_route.h209
-rw-r--r--ospf6d/ospf6_routemap.c359
-rw-r--r--ospf6d/ospf6_routemap.h27
-rw-r--r--ospf6d/ospf6_spf.c1454
-rw-r--r--ospf6d/ospf6_spf.h105
-rw-r--r--ospf6d/ospf6_top.c401
-rw-r--r--ospf6d/ospf6_top.h96
-rw-r--r--ospf6d/ospf6_types.h43
-rw-r--r--ospf6d/ospf6_zebra.c727
-rw-r--r--ospf6d/ospf6_zebra.h46
-rw-r--r--ospf6d/ospf6d.c826
-rw-r--r--ospf6d/ospf6d.conf.sample54
-rw-r--r--ospf6d/ospf6d.h175
-rw-r--r--ospfd/.cvsignore7
-rw-r--r--ospfd/ChangeLog2970
-rw-r--r--ospfd/Makefile.am44
-rw-r--r--ospfd/Makefile.in532
-rw-r--r--ospfd/OSPF-MIB.txt2723
-rw-r--r--ospfd/OSPF-TRAP-MIB.txt443
-rw-r--r--ospfd/ospf_abr.c1741
-rw-r--r--ospfd/ospf_abr.h84
-rw-r--r--ospfd/ospf_asbr.c287
-rw-r--r--ospfd/ospf_asbr.h75
-rw-r--r--ospfd/ospf_ase.c838
-rw-r--r--ospfd/ospf_ase.h42
-rw-r--r--ospfd/ospf_dump.c1673
-rw-r--r--ospfd/ospf_dump.h139
-rw-r--r--ospfd/ospf_flood.c1048
-rw-r--r--ospfd/ospf_flood.h65
-rw-r--r--ospfd/ospf_ia.c726
-rw-r--r--ospfd/ospf_ia.h42
-rw-r--r--ospfd/ospf_interface.c1045
-rw-r--r--ospfd/ospf_interface.h245
-rw-r--r--ospfd/ospf_ism.h88
-rw-r--r--ospfd/ospf_lsa.c3315
-rw-r--r--ospfd/ospf_lsa.h326
-rw-r--r--ospfd/ospf_lsdb.c299
-rw-r--r--ospfd/ospf_lsdb.h83
-rw-r--r--ospfd/ospf_main.c293
-rw-r--r--ospfd/ospf_neighbor.h106
-rw-r--r--ospfd/ospf_network.c192
-rw-r--r--ospfd/ospf_network.h34
-rw-r--r--ospfd/ospf_nsm.h91
-rw-r--r--ospfd/ospf_opaque.c2392
-rw-r--r--ospfd/ospf_opaque.h155
-rw-r--r--ospfd/ospf_packet.c3243
-rw-r--r--ospfd/ospf_packet.h171
-rw-r--r--ospfd/ospf_route.c1026
-rw-r--r--ospfd/ospf_route.h165
-rw-r--r--ospfd/ospf_routemap.c828
-rw-r--r--ospfd/ospf_snmp.c2443
-rw-r--r--ospfd/ospf_snmp.h33
-rw-r--r--ospfd/ospf_spf.c1088
-rw-r--r--ospfd/ospf_spf.h50
-rw-r--r--ospfd/ospf_te.c1921
-rw-r--r--ospfd/ospf_te.h193
-rw-r--r--ospfd/ospf_vty.c7571
-rw-r--r--ospfd/ospf_vty.h85
-rw-r--r--ospfd/ospf_zebra.c1180
-rw-r--r--ospfd/ospf_zebra.h78
-rw-r--r--ospfd/ospfd.c1603
-rw-r--r--ospfd/ospfd.conf.sample13
-rw-r--r--ospfd/ospfd.h559
-rw-r--r--ports/Makefile58
-rw-r--r--ports/README1
-rw-r--r--ports/files/md51
-rw-r--r--ports/pkg/COMMENT1
-rw-r--r--ports/pkg/DESCR75
-rw-r--r--ports/pkg/PLIST8
-rw-r--r--ripd/.cvsignore7
-rw-r--r--ripd/ChangeLog749
-rw-r--r--ripd/Makefile.am37
-rw-r--r--ripd/Makefile.in489
-rw-r--r--ripd/RIPv2-MIB.txt530
-rw-r--r--ripd/rip_debug.c290
-rw-r--r--ripd/rip_debug.h54
-rw-r--r--ripd/rip_interface.c2001
-rw-r--r--ripd/rip_main.c270
-rw-r--r--ripd/rip_offset.c414
-rw-r--r--ripd/rip_peer.c211
-rw-r--r--ripd/rip_routemap.c898
-rw-r--r--ripd/rip_snmp.c577
-rw-r--r--ripd/rip_zebra.c691
-rw-r--r--ripd/ripd.c3536
-rw-r--r--ripd/ripd.conf.sample24
-rw-r--r--ripd/ripd.h408
-rw-r--r--ripngd/.cvsignore7
-rw-r--r--ripngd/ChangeLog216
-rw-r--r--ripngd/Makefile.am37
-rw-r--r--ripngd/Makefile.in487
-rw-r--r--ripngd/ripng_debug.c292
-rw-r--r--ripngd/ripng_debug.h52
-rw-r--r--ripngd/ripng_interface.c835
-rw-r--r--ripngd/ripng_main.c252
-rw-r--r--ripngd/ripng_route.c157
-rw-r--r--ripngd/ripng_route.h53
-rw-r--r--ripngd/ripng_routemap.c342
-rw-r--r--ripngd/ripng_zebra.c877
-rw-r--r--ripngd/ripngd.c2526
-rw-r--r--ripngd/ripngd.conf.sample22
-rw-r--r--ripngd/ripngd.h318
-rw-r--r--stamp-h.in1
-rwxr-xr-xtools/mrlg.cgi395
-rw-r--r--tools/rrcheck.pl135
-rw-r--r--tools/rrlookup.pl123
-rwxr-xr-xtools/zc.pl111
-rw-r--r--tools/zebra.el108
-rwxr-xr-xupdate-autotools14
-rw-r--r--vtysh/.cvsignore6
-rw-r--r--vtysh/ChangeLog173
-rw-r--r--vtysh/Makefile.am22
-rw-r--r--vtysh/Makefile.in453
-rwxr-xr-xvtysh/extract.pl171
-rw-r--r--vtysh/vtysh.c1803
-rw-r--r--vtysh/vtysh.conf.sample4
-rw-r--r--vtysh/vtysh.h83
-rw-r--r--vtysh/vtysh_cmd.c14710
-rw-r--r--vtysh/vtysh_config.c426
-rw-r--r--vtysh/vtysh_main.c288
-rw-r--r--vtysh/vtysh_user.c191
-rw-r--r--vtysh/vtysh_user.h27
-rw-r--r--zebra/.cvsignore8
-rw-r--r--zebra/ChangeLog1221
-rw-r--r--zebra/GNOME-PRODUCT-ZEBRA-MIB78
-rw-r--r--zebra/GNOME-SMI53
-rw-r--r--zebra/Makefile.am57
-rw-r--r--zebra/Makefile.in493
-rw-r--r--zebra/client_main.c225
-rw-r--r--zebra/connected.c394
-rw-r--r--zebra/connected.h60
-rw-r--r--zebra/debug.c272
-rw-r--r--zebra/debug.h52
-rw-r--r--zebra/if_ioctl.c438
-rw-r--r--zebra/if_netlink.c33
-rw-r--r--zebra/if_proc.c246
-rw-r--r--zebra/if_sysctl.c148
-rw-r--r--zebra/interface.c1387
-rw-r--r--zebra/interface.h180
-rw-r--r--zebra/ioctl.c540
-rw-r--r--zebra/ioctl.h46
-rw-r--r--zebra/ipforward.h35
-rw-r--r--zebra/ipforward_aix.c64
-rw-r--r--zebra/ipforward_ews.c60
-rw-r--r--zebra/ipforward_proc.c155
-rw-r--r--zebra/ipforward_solaris.c77
-rw-r--r--zebra/ipforward_sysctl.c146
-rw-r--r--zebra/irdp.c569
-rw-r--r--zebra/irdp.h148
-rw-r--r--zebra/kernel_netlink.c20
-rw-r--r--zebra/kernel_socket.c811
-rw-r--r--zebra/main.c316
-rw-r--r--zebra/mtu_kvm.c97
-rw-r--r--zebra/redistribute.c410
-rw-r--r--zebra/redistribute.h49
-rw-r--r--zebra/rib.h251
-rw-r--r--zebra/rt.h40
-rw-r--r--zebra/rt_ioctl.c558
-rw-r--r--zebra/rt_netlink.c1482
-rw-r--r--zebra/rt_socket.c441
-rw-r--r--zebra/rtadv.c1112
-rw-r--r--zebra/rtadv.h49
-rw-r--r--zebra/rtread_getmsg.c229
-rw-r--r--zebra/rtread_netlink.c31
-rw-r--r--zebra/rtread_proc.c169
-rw-r--r--zebra/rtread_sysctl.c75
-rw-r--r--zebra/zebra.conf.sample25
-rw-r--r--zebra/zebra_rib.c2199
-rw-r--r--zebra/zebra_snmp.c550
-rw-r--r--zebra/zebra_vty.c1554
-rw-r--r--zebra/zserv.c1806
-rw-r--r--zebra/zserv.h132
420 files changed, 243853 insertions, 0 deletions
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 <kunihiro@zebra.org>
+Toshiaki Takada <takada@zebra.org>
+Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+Alex D. Zinin <azinin@hotmail.com>
+Gleb Natapov <gleb@nbase.co.il>
+Akihiro Mizutani <mizutani@dml.com>
diff --git a/COPYING b/COPYING
new file mode 100644
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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/COPYING.LIB b/COPYING.LIB
new file mode 100644
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.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 00000000..7448bfe1
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,674 @@
+2002-07-07 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.93 released.
+
+2002-06-28 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * update-autotools: Change file name from update-auto-tools.sh.
+
+2002-06-21 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * update-auto-tools.sh: Add a new script to clean up build
+ environment.
+
+2002-06-18 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * Shift to the latest build environment autoconf-2.53 and
+ automake-1.6.2.
+
+2001-10-22 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * Integrate Glen Turner <glen.turner@aarnet.edu.au>'s pid option.
+
+2001-08-19 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92a released.
+
+2001-08-19 "Peter Galbavy" <peter.galbavy@knowtion.net>
+
+ * configure.in: SNMP library check problem fix when the library is
+ installed under /usr/local/lib.
+
+2001-08-15 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92 released.
+
+2001-04-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in (LIBPAM): Use ZEBRA_AC_C_BIGENDIAN to avoid a
+ warning.
+ (IF_METHOD): Use test -r instead of AC_CHECK_FILE to avoid
+ warnings.
+
+ * config.guess: Update to 2000-11-10 version.
+
+2001-04-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Use AC_TRY_COMPILE instead of AC_EGREP_HEADER to
+ detect in_pktinfo structure. Suggested by: Vlad Lungu
+ <vlad@rls.roknet.ro>.
+
+2001-03-07 Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+ * configure.in: Add check for structure in_pktinfo.
+
+2001-02-07 "Bjoern A. Zeeb" <bzeeb+zebra@zabbadoz.net>
+
+ * configure.in (USE_PAM): Fix PAM library detection code.
+
+2001-02-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.91 is released.
+
+2001-01-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Remove guile related definition.
+
+2001-01-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in (ac_cv_htonl_works): HAVE_REPAIRABLE_HTONL is
+ removed. htonl should work fine on any platform.
+
+2001-01-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Remove --enable-oldrib option.
+
+ * acconfig.h: OLD_RIB definition is removed.
+
+ * zebra-0.90 is released.
+
+ * configure.in (LIBS): Add check for sun_len field in struct
+ sun_len.
+
+2001-01-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am: Include init/redhat files to distribution.
+
+2001-01-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * configure.in: check libm.a for BGPd compile error.
+ AC_CHECK_LIB(m, main) was added.
+
+2000-12-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: --enable-unixdomain becomes default. Add
+ --enable-tcp-zebra for TCP/IP communication between protocol
+ daemon and zebra.
+
+ * COPYING.LIB: Added for lib/getopt.c, lib/getopt.h,
+ lib/getopt1.c, lib/md5-gnu.h, lib/md5.c, lib/regex-gnu.h,
+ lib/regex.c.
+
+ * Makefile.am (dist-hook): Include tools/*.cgi to distribution.
+
+2000-12-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in (MULTIPATH_NUM): --enable-multipath=ARG specify
+ multipath number. ARG must be digit.
+
+2000-12-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Add --enable-newrib for test new RIB code.
+
+2000-11-25 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * configure.in, config.h.in: Add check for libutil.h and
+ setproctitle().
+
+2000-10-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Add --enable-nssa for OSPF NSSA option.
+
+ * acconfig.h: Define HAVE_NSSA.
+
+2000-10-25 "Bjoern A. Zeeb" <bzeeb+zebra@zabbadoz.net>
+
+ * configure.in: pam_misc is only linked when the platform is
+ GNU/Linux.
+
+2000-10-24 Arkadiusz Miskiewicz <misiek@pld.org.pl>
+
+ * configure.in (LIBS): Add check for crypto library. test x`ls
+ ${ac_snmp}` is replaced with sipmle test -f.
+
+2000-10-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Add --enable-unixdomain option. This will be
+ default behavior in zebra-0.90.
+
+2000-10-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.89 is released.
+
+2000-09-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Add check for Intel CPU for Solaris on x86 check.
+
+2000-09-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Add check for getifaddrs().
+ Set AM_INIT_AUTOMAKE version to 0.89.
+
+2000-09-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * config.guess: Update to the latest version.
+
+ * config.sub: Likewise
+
+2000-09-14 David Lipovkov <dlipovkov@OpticalAccess.com>
+
+ * REPORTING-BUGS: New file is added.
+
+2000-08-27 itojun@iijlab.net
+
+ * configure.in: Add ncurses library check when --enable-vtysh is
+ specified.
+
+2000-08-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Add check for readline/history.h.
+
+ * acconfig.h: Remove pthread related variables.
+
+ * configure.in: Add --with-libpam option for vtysh PAM
+ authentication. Remove --disable-pthread because we don't support
+ pthread.
+
+2000-08-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.88 is released.
+
+ * configure.in: Add Solaris -lcurses for vtysh.
+
+2000-08-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Add check for ncurses for compiling on Solaris.
+
+2000-07-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Add check for libreadline when --enable-vtysh is
+ specified.
+
+2000-07-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Add AC_DEFINE(OPEN_BSD). When OS is OpenBSD
+ interface method is if_ioctl.o
+
+2000-07-09 Chris Dunlop <chris@onthe.net.au>
+
+ * acconfig.h: Add HAVE_BROKEN_ALIASES.
+
+ * configure.in: Add --enable-broken-aliases.
+
+2000-06-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Set version to zebra-0.87.
+
+2000-06-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Remove --enable-mpls-vpn. Now MPLS-VPN support is
+ default.
+
+ * Set version to zebra-0.87-pre
+
+ * Makefile.am: Likewise.
+
+2000-04-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Set version to 0.86.
+
+2000-03-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Set version to 0.85b for ospfd test.
+
+2000-03-20 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Set version to 0.85a for ospfd test.
+
+2000-03-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Set version to 0.85.
+
+2000-01-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.in: Regenerated by patched automake for fixing "make
+ clean" problem on FreeBSD.
+
+1999-12-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Set version to 0.83a. This is for *BSD static route lookup
+ problem.
+
+1999-12-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Set version to 0.83.
+
+1999-11-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Set version to 0.82.
+
+1999-11-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * aczebra.m4: New file added.
+
+1999-11-21 Michael Handler <handler@sub-rosa.com>
+
+ * configure.in (LIBS): Add sa_len check of sockaddr.
+
+ * acconfig.h: Add HAVE_SA_LEN.
+
+1999-11-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: Update version to zebra-0.81b for bgpd test.
+
+1999-11-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Add --enable-mbgp.
+
+1999-11-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am (EXTRA_DIST): Add TODO to the distribution.
+
+1999-11-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * TODO: New file is added.
+
+1999-11-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: Update version to zebra-0.81a for ospfd test.
+
+1999-10-28 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: New option --enable-snmp is added.
+
+1999-10-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: Update version to zebra-0.80.
+
+1999-10-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: Update version to zebra-0.80-pre3
+
+1999-10-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in (LIBS): SNMP check is done by ucd-snmp/asn1.h.
+
+1999-10-10 Peter Galbavy <Peter.Galbavy@knowledge.com>
+
+ * configure.in: Add support of OpenBSD.
+
+1999-10-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: Update version to zebra-0.80-pre2.
+
+1999-09-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: Update version to zebra-0.80-pre. From this version,
+ access-list and prefix-list's name space is divided into IPv4 and
+ IPv6.
+
+1999-09-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: For test recent fixes Set version to zebra-0.79a.
+
+1999-09-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: zebra-0.79 is out.
+
+1999-09-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: For ospfd's virtual link test. Set version to 0.78h.
+
+1999-09-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: For ospfd test. Set version to 0.78g.
+
+1999-09-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: For internal test of ospfd. Set version to 0.78f.
+
+1999-09-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: To test ospfd's fix, set version to 0.78e.
+
+1999-09-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: To test ospfd's area related bug fix, set version
+ to 0.78d.
+
+1999-09-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: To test ospfd, set version to 0.78c.
+
+1999-08-31 Janos Farkas <chexum@shadow.banki.hu>
+
+ * Many misspelling correction.
+
+1999-08-31 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: To test ospfd, set version to 0.78b.
+
+1999-08-31 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in (LIBS): Add UCD-SNMP include path check.
+
+1999-08-31 Lars Fenneberg <lf@elemental.net>
+
+ * configure.in: The logic which detects the UCD-SNMP library
+ should first check in the default system locations for the library
+ and then in /usr/local.
+
+1999-08-27 itojun@iijlab.net
+
+ * configure.in (LIBS): Fix problem about libsnmp.a check.
+
+1999-08-26 kay <kay@v6.access.co.jp>
+
+ * configure.in (CFLAGS): Add <sys/socket.h> to check socklen_t.
+
+1999-08-24 VOP <vop@unity.net>
+
+ * filter.c: Include "sockunion.h".
+ plist.c: Likewise.
+ table.c: Likewise.
+
+1999-08-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Add netinet6/in6.h check.
+
+1999-08-21 Masaki Minami <masaki@minami.org>
+
+ * BSD/OS 4.0 porting.
+
+1999-08-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Add --enable-netlink option to force to use Linux
+ netlink interface.
+ (CFLAGS): Add ucd-snmp library check.
+
+ * acconfig.h: If socklen_t is not defined, typedef int to
+ socklen_t.
+
+1999-08-15 Arkadiusz Miskiewicz <misiek@misiek.eu.org>
+
+ * configure.in: When --enable-ipv6 specified, then only kernel
+ version is checked.
+
+1999-08-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Add GNU libc 2.1 check.
+
+1999-08-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Fix privious Linux IPv6 check changes.
+
+1999-08-02 Arkadiusz Miskiewicz <misiek@misiek.eu.org>
+
+ * configure.in: Improve Linux IPv6 feature check.
+
+1999-07-29 Rick Payne <rickp@rossfell.co.uk>
+
+ * Changed route-maps to behave in a more cisco-like fashion
+
+1999-07-27 Gerhard Poul <gpoul@gnu.org>
+
+ * SERVICES: New file added.
+
+1999-07-12 itojun@iijlab.net
+
+ * configure.in: Add check for getaddrinfo. Improve Kame related
+ library check.
+
+1999-07-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * configure.in, acconfig.h: Add check for FreeBSD 3.2.
+
+1999-07-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Delete check for netinet/ip6.h.
+
+1999-06-30 Gerhard Poul <gpoul@gnu.org>
+
+ * README: remixed the old files and added some new parts.
+ moved some INSTALL stuff into INSTALL file.
+ moved some other stuff to doc/zebra.texi
+
+1999-06-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in (LIBS): Add libresolv check.
+ Change --enabe-all-in-one option to --enable-one-vty.
+
+1999-06-20 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Add --enabe-all-in-one option.
+
+1999-06-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Add socklen_t check.
+
+1999-06-16 Gerhard Poul <gpoul@gnu.org>
+
+ * Many compile warnings fixed.
+
+1999-05-31 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Change message from Linux 2.2.X IPv6 to Linux IPv6.
+ OpenBSD (NRL) check is enabled.
+
+1999-05-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in (LIBS): Add crypt library check.
+
+1999-05-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Add sin6_scope_id in struct sockaddr_in6 check.
+
+1999-04-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Set version to 0.63 for first beta package.
+
+1999-04-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * guile.m4: Added from guile package.
+
+1999-04-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Set version to 0.60 for beta package preparation.
+
+1999-04-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am: Add noninst_LIBRARIES each directory's Makefile.am.
+ This change is for linking these libraries to guile.
+
+1999-04-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in (LIBS): Add struct rt_addrinfo check.
+
+1999-04-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: AC_STDC_HEADERS added.
+
+1999-03-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Add dependencies to each directory's Makefile.am.
+
+1999-03-02 Peter Galbavy <Peter.Galbavy@knowledge.com>
+
+ * reworked include file structure, and configure so that all
+ source files get all system-dependent include files by including
+ <zebra.h> which is really lib/zebra.h. This means that the
+ different programs include files are now available as #include
+ "zebra/zebra.h" - note the use of quotes, not <> as delimiters.
+
+ In practical terms, if I haven't really screwed up, the main file
+ that maintainers for other OSes have to change is lib/zebra.h for
+ all the conditional includes etc.
+
+ * added --disable-pthread for those systems that seem to have
+ POSIX threads, but do not work. OpenBSD 2.4+ is like that just
+ now. Changed all occurance of #ifdef PTHREAD to use HAVE_PTHREAD
+ instead.
+
+1999-02-24 <kunihiro@zebra.org>
+
+ * configure.in: update to AC_PREREQ(1.13).
+ Change message from Linux 2.1.x to Linux 2.2.x.
+ * Added ospf6d directory support.
+
+1999-02-22 Peter Galbavy <Peter.Galbavy@knowledge.com>
+
+ * added a "log" element to the BGPd peer structure, enabling us to
+ start thinging about a log stream per peer. This is currently
+ ignored by the wrapper code, but developers should try to use the
+ "appropriate" ZLOG stream. Documentation will follow, when the
+ real routines start to exist.
+
+ The current plan is to use a copy of the BSD syslog() routines and
+ replace the syslog library function with our own. I will need
+ feedback from users of other platforms as this work is done to see
+ if all is well elsewhere.
+
+ * preliminary work on zlog() library. directly replaces syslog()
+ currently with zlog(ZLOG *, ...) where the new first argument
+ is a pointer to a ZLOG structure (defined in lib/log.h) and will
+ encapsulate all the information necessary to maintain multiple
+ logging streams.
+
+1999-02-19 Peter Galbavy <Peter.Galbavy@knowledge.com>
+
+ * added vsnprintf() macro to lib/str.h if required and removed
+ #ifdef SUNOS_5 dependency on it
+
+1999-02-18 Peter Galbavy <Peter.Galbavy@knowledge.com>
+
+ * syslog support added
+
+1999-02-18 Peter Galbavy <Peter.Galbavy@knowledge.com>
+
+ * configure.in: Add daemon function check.
+
+1999-01-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Add --disable-ipv6, --disable-zebra,
+ --disable-bgpd, --disable-ripd, --disable-ripngd, --disable-ospfd
+ options to configure.
+
+1998-12-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Check /usr/inet6/lib/libinet6.a exists or not.
+
+1998-10-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Comment out FreeBSD's libc_r detect section. At
+ this moment it doesn't work correctly with zebra.
+
+ Netlink interface is only enabled when Linux kernel version is
+ upper than 2.1.0.
+
+1998-09-15 HEO SeonMeyong <seirios@matrix.iri.co.jp>
+
+ * Hydrangea is now called KAME, so change all defines.
+
+1998-08-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: ifaliasreq check added.
+
+1998-08-12 Katsuhiro Kondou <kondou@nec.co.jp>
+
+ * Patch is applied for compile under EWS4800
+
+1998-06-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: delete old mtu_method check.
+
+ * doc/zebra.texi (Kernel interface): chapter `Kernel interface' added
+
+1998-06-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: add new netlink check for GNU/Linux
+
+1998-06-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * doc/zebra.texi: Update Linux netlink chapter.
+
+1998-05-18 Yamashita TAKAO <jargon@lares.dti.ne.jp>
+
+ * config.h.in: define PTHREAD if work on Solaris 2.6
+ why delete the definition? I miss?
+
+1998-05-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: add net/if.h header check.
+
+1998-05-02 SeonMeyong HEO <seirios@Matrix.iri.co.jp>
+
+ * zebra.tex,archfig.tex,zebra.sty: Manual file is added.
+ * zebra.texi: Modify Introduction text.
+ * RIPngd.c: Patch Hydrangea code.
+
+1998-05-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * .cvsignore: added.
+
+ * Makerule.in: is gone.
+ * Makefile.am: Now we use automake to generate Makefile.in
+
+1998-03-19 Yamashita TAKAO <jargon@lares.dti.ne.jp>
+
+ * lib/vty.c: modified the definition of *master
+ * lib/sockunion.c (inet_aton): add, but don't work. uum...
+
+
+1998-03-15 Yamashita TAKAO <jargon@lares.dti.ne.jp>
+
+ * configure.in: define PTHREAD if work on Solaris 2.6
+ * config.h.in: likewise
+ * lib/thread.c: likewise
+ * lib/vty.c: likewise
+
+1998-03-15 SeonMeyong HEO <seirios@Matrix.iri.co.jp>
+
+ * config.h.in: define INET6 if defined HAVE_IPV6 & HYDRANGEA
+ * bgpd/: remove include <netinet6/in6.h> line.
+ * lib/: remove include <netinet6/in6.h> line.
+ * ripbgd/: remove include <netinet6/in6.h> line.
+ * zebra/: remove include <netinet6/in6.h> line.
+ * ripd/*.c: remove include <netinet6/in6.h> line.
+ undefine IPV6 difinitions because RIPd is not worked for
+ IPv6 protocol.
+
+
+1998-01-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: Change routing socket check method from
+ AC_TRY_COMPILE to AC_TRY_RUN because GNU libc version 2 has
+ AF_ROUTE but over linux it's meenigless.
+
+1998-01-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * config.h.in: remove err_t define.
+
+1997-11-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in (canonical): add check of IF_METHOD
+
+1997-09-27 Kunihiro Ishiguro <kunihiro@note.digital-magic.co.jp>
+
+ * configure.in: add INRIA check
+
+1997-09-25 Kunihiro Ishiguro <kunihiro@note.digital-magic.co.jp>
+
+ * configure.in (canonical): change ipforward_snmp.o to ipforward_proc.o
+
+1997-09-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * configure.in: change IRDPD to NDPD
+
+1997-08-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * INSTALL: new file
+
+1997-08-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * config.h: add XCALLOC()
+
diff --git a/INSTALL b/INSTALL
new file mode 100644
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 <val>"
+ "show ip bgp community <val> exact-match"
+
+** EBGP multihop route treatment bug is fixed. Now nexthop is
+resolved by IGP routes.
+
+** Some commands are added to show routes by filter-list and community
+value.
+ "show ip bgp ipv4 (unicast|multicast) filter-list WORD"
+ "show ip bgp ipv4 (unicast|multicast) community"
+ "show ip bgp ipv4 (unicast|multicast) community-list WORD"
+ "show ip bgp ipv4 (unicast|multicast) community-list WORD exact-match"
+
+* Changes in zebra
+
+** zebra read interface's address information using getifaddrs() when
+it is available.
+
+** Reflect IPv6 interface's address change to protocol daemons.
+
+* 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
+ <takada@zebra.org>. DEFUN string is "X:X::X:X" for IPv6 address,
+ "X:X::X:X/M" for IPv6 prefix. You can use it like this.
+
+ DEFUN (func, cmd, "neighbor (A.B.C.D|X:X::X:X) remote-as <1-65535>")
+
+** VTY configuration is locked during configuration. This is for
+ avoiding unconditional crush from two terminals modify the
+ configuration at the same time. "who" command shows which termnal
+ lock the configuration. VTY which has '*' character at the head of
+ line is locking the configuration.
+
+** Old logging functions are removed. Functions like
+ log_open,log_close,openlog are deleted. Instead of that please use
+ zlog_* functions. zvlog_* used in ospf6d are deleted also.
+
+** "terminal monitor" command is added. "no terminal monitor" is for
+ disabling. This command simply display logging information to the
+ VTY.
+
+** dropline.[ch] files are deleted.
+
+* Changes in bgpd
+
+** BGP neighbor configuration are sorted by it's IP address.
+
+** BGP peer configuration and actual peer is separated. This is
+ preparation for Route Server support.
+
+** "no neighbor PEER" command is added. You can delete neighbor
+ without specifying AS number.
+
+** "no neighbor ebgp-multihop" command is added.
+
+** "no neighbor port PORT" command is added.
+
+** To conform RFC1771, "neighbor PEER send-community" is default
+ behavior. If you want to disable sending community attribute,
+ please specify "no neighbor PEER send-community" to the peer.
+
+** "neighbor maximum-prefix NUMBER" command is added.
+
+** Multi-protocol extention NLRI is proceeded only when the peer is
+ configured proper Address Family and Subsequent Address Family. If
+ not, those NLRI are simply ignored.
+
+** Aggregate-address support is improved. Currently below commands
+ works.
+
+ "aggregate-address"
+ "aggregate-address summary-only"
+ "no aggregate-address"
+ "no aggregate-address summary-only"
+
+ "ipv6 bgp aggregate-address"
+ "ipv6 bgp aggregate-address summary-only"
+ "no ipv6 bgp aggregate-address"
+ "no ipv6 bgp aggregate-address summary-only"
+
+** redistribute route-map bug is fixed.
+
+** MBGP support becomes default. "configure" option --enable-mbgp is
+ removed.
+
+** New command "neighbor PEER timers connect <1-65535>" is added.
+
+** New command "neighbor PEER override-capability" is added.
+
+** New command "show ip bgp neighbor A.B.C.D advertised-route" is added.
+
+** New command "show ip bgp neighbor A.B.C.D routes" is added. To use
+ this command, you have to configure neighbor with
+ "neighbor A.B.C.D soft-reconfiguration inbound" beforehand.
+
+
+* 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
+<handler@sub-rosa.com>.
+
+** MBGP support is added by Robert Olsson <Robert.Olsson@data.slu.se>.
+Please specify --enable-mbgp to configure script. This option will be
+removed in the future and MBGP support will be default.
+
+* Changes in zebra
+
+** When interface goes down, withdraw connected routes from routing
+table. When interface goes up, restore the routes to the routing
+table.
+
+** `show interface' show interface's statistics on Linux and BSD with
+routing socket.
+
+** Now zebra can get MTU value on BSDI/OS.
+
+* Changes in bgpd
+
+** Add capability option support based upon
+draft-ietf-idr-bgp4-cap-neg-04.txt.
+
+** Add `show ipv6 bgp prefix-list' command.
+
+** Check self AS appeared in received routes.
+
+** redistribute route-map support is added.
+
+** BGP packet dump feature compatible with MRT.
+
+* Changes in ripd
+
+** Fix bug of `timers basic' command's argument format.
+
+* Changes in ripngd
+
+** Calculate max RTE using interface's MTU value.
+
+* Changes in ospfd
+
+** Some correction to LSU processing.
+
+** Add check for lsa->refresh_list.
+
+* Changes in ospf6d
+
+** Many debug feature is added.
+
+* 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 <update> <timeout> <garbage>' added.
+
+* Changes in ripd
+
+** Reconstruct almost codes.
+
+** `network' configuration is dynamically reflected.
+
+** RIP timers now conforms to RFC2453. So user can configure update,
+timeout, garbage timer.
+
+** `timers basic <update> <timeout> <garbage>' works.
+
+* Changes in ospfd
+
+** Bug of originating network LSA is fixed.
+
+** `no router ospf' core dump bug is fixed.
+
+* Changes in ospf6d
+
+** Redistribute route works.
+
+* 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 <koppen@rhrk.uni-kl.de>
+
+* Changes in bgpd
+
+** Now `router zebra' is not needed to insert BGP routes into the
+kernel. It is default behavior. If you don't want to install the BGP
+routes to the kernel, please configure like below:
+
+!
+router zebra
+ no redistribute bgp
+!
+
+** redistribute connected works.
+
+** redistribute static now filter local loopback routes and link local
+network.
+
+* Changes in ripd
+
+** Some network check is added. Patch is done by Carlos Alberto
+Barcenilla <barce@frlp.utn.edu.ar>
+
+* Changes in ripngd
+
+** Sometimes ripngd install wrong nexthop into the kernel. This bug
+is fixed now.
+
+** Now `router zebra' is not needed to insert RIPng routes into the
+kernel. It is default behavior. If you don't want to install the BGP
+routes to the kernel, please configure like below:
+
+!
+router zebra
+ no redistribute ripng
+!
+
+* Changes in zebra-0.65
+
+* Changes in lib
+
+** `C-c' changes current node to ENABLE_NODE. Previously it doesn't.
+
+** In ENABLE_NODE, `exit' command close vty connection.
+
+** `service advanced-vty' enable advanced vty function. If this
+service is specified one can directly connect to ENABLE_NODE when
+enable password is not set.
+
+** `lines LINES' command is added by Stephen R. van den Berg
+<srb@cuci.nl>.
+
+* Changes in zebra
+
+** Basic Linux policy based routing table support is added by Stephen
+R. van den Berg <srb@cuci.nl>.
+
+* Changes in bgpd
+
+** route-map command is improved:
+ `match ip next-hop': New command.
+ `match metric': New command.
+ `set metric': Doc fixed.
+ `set local-preference': DEFUN added.
+
+* Changes in ripd
+
+** Check of announced network is added. Now multicast address is
+filtered. Reported by Carlos Alberto Barcenilla
+<barce@frlp.utn.edu.ar>
+
+** Check of network 127 is added. Reported by Carlos Alberto
+Barcenilla <barce@frlp.utn.edu.ar>
+
+* Changes in ripngd
+
+** Aging route bug is fixed.
+
+** `router zebra' semantics changed. ripngd automatically connect to
+zebra.
+
+* Changes in ospfd
+
+** `no router ospf' works.
+
+* Changes in ospf6d
+
+** Bug fix about network vertex.
+
+* Changes in zebra-0.64.1.
+
+This is bug fix release.
+
+* Changes in lib
+
+** Add check of sin6_scope_id in struct sockaddr_in6. For compilation
+on implementation which doesn't have sin6_scope_id. Reported by Wim
+Biemolt <Wim.Biemolt@ipv6.surfnet.nl>.
+
+* Changes in zebra
+
+** Fix bug of display BGP routes as "O" instead of "B". Reported by
+"William F. Maton" <wmaton@enterprise.ic.gc.ca> and Dave Hartzell
+<hartzell@greatplains.net>.
+
+* Changes in bgpd
+
+** `no network IPV6_NETWORK' statement and `no neighbor IP_ADDR timers
+holdtime [TIMER]' statement doesn't work. Reported by Georg Hitsch
+<georg@atnet.at>. Now both statement work.
+
+* Changes in ospfd
+
+** Last interface is not updated by ospf_if_update(). Reported by
+Dave Hartzell <hartzell@greatplains.net>.
+
+* Changes in ospf6d
+
+** Byte order of ifid is changed. Due to this change, this code will
+not work with previous version, sorry.
+
+** Fix `show ip route' route type mismatch.
+
+** Fix bug of no network IPV6_NETWORK.
+
+** Important bug fix about intra-area-prefix-lsa.
+
+* 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
+<barce@frip.utn.edu.ar>.
+
+* Changes in ospfd
+
+** DR and BDR election works.
+
+** OSPF Hello simple authentication works.
+
+* Changes in ospf6d
+
+** Now ospf6d can be compiled on both Linux and *BSD system.
+
+* Changes in zebra-19990420 snapshot
+
+** `make dist' at top directory works now.
+
+* Changes in lib
+
+** VTY has now access-class to restrict remote connection.
+Implemented by Alex Bligh <amb@gxn.net>.
+
+!
+line vty
+ access-class ACCESS-LIST-NAME
+!
+
+** `show version' command added. Implemented by Carlos Alberto
+Barcenilla <barce@frlp.utn.edu.ar>
+
+* Changes in zebra
+
+** `ip address' command on *BSD bug is fixed.
+
+** `no ip address' works now for IPv4 address.
+
+** Now `write terminal' display `ip address' configuration.
+
+* Changes in bgpd
+
+** Redistribute static works now. Please run both zebra and bgpd.
+bgpd.conf should be like this:
+
+!
+router zebra
+!
+router bgp ASN
+ redisitribute static
+!
+
+* Changes in guile
+
+** configure --enable-guile turns on zebra-guile build.
+
+** (router-bgp ASN) allocates real bgp structre.
+
+* Changes in zebra-19990416 snapshot
+
+** Set version to 0.60 for preparation of beta release.
+
+** New directory guile is added for linking with guile interpreter.
+
+* Changes in zebra
+
+** On GNU/Linux Kernel 2.2.x (with netlink support), zebra detects
+asynchronous routing updates. *BSD support is not yet finished.
+
+* Changes in bgpd
+
+** `show ip bgp regexp ASPATH_REGEX' uses CISCO like regular expression
+instead of RPSL like regular expression. I'm planing to provide RPSL
+like regular expression with `show ip bgp rpsl' or something.
+
+* Changes in lib
+
+** Press '?' at variable mandatory argument, vty prints nothing. Now
+vty outputs description about the argument. Fixed by Alex Bligh
+<amb@gxn.net>
+
+** buffer.c has some ugly bugs. Due to the bug, vty interface hangs
+when large output date exists. This bug is fixed. Reported by Alex
+Bligh <amb@gxn.net>.
+
+* Changes in ospfd
+
+** DR and BDR information is shown by `show ip ospf interface' command.
+
+* 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 <ap@bnc.net>.
+
+* 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 <asmodai@wxs.nl>.
+
+** syslog logging feature is added by Peter Galbavy
+ <Peter.Galbavy@knowledge.com>
+
+** Inclusion of standard header files is reworked by Peter Galbavy
+ <Peter.Galbavy@knowledge.com>
+
+** Change description from GNU/Linux 2.1.X to GNU/Linux 2.2.X
+
+** If daemon function exists in standard C library use it.
+
+** To generate configure script we upgrade autoconf to 2.13. To
+generate Makefile.in we upgrade automake to 1.4.
+
+** doc/texinfo.tex is added to distribution.
+
+** Update ports/pkg/DESCR description.
+
+** Update doc/zebra.texi.
+
+** logfile FILENAME statement deleted. Instead of that please use log
+file FILENAME.
+
+* Changes in zebra
+
+* Changes in bgpd
+
+** Communication between zebra and bgpd works now. So if there is
+ `router zebra' line in bgpd.conf, selected route is installed
+ into kernel routing table.
+
+** Delete all routes which inserted by bgpd when bgpd dies. If you
+want to retain routes even bgpd dies please specify [-r|--retain]
+option to bgpd.
+
+** BGP announcement code is reworked. Now bgpd announce selected
+ routes to other peer.
+
+** All output bgp packet is buffered. It's written to the socket when
+ it gets ready.
+
+** Output route-map works now. You can specify output route-map by:
+
+ neighbor IP_ADDR route-map ROUTE_MAP_NAME out
+
+** New route-map command added.
+
+ set ip nexthop IP_ADDR
+ set ipv6 nexthop global IP_ADDR
+
+** Fix bug about unlock of the route_node structure.
+
+** BGP-4+ support is added. bgpd can listen and speak BGP-4+ packet
+specified in RFC2283. You can view IPv6 bgp table by: `show ipv6 bgp'.
+
+** Meny packet overflow check is added.
+
+* Changes in ripd
+
+* Changes in ripngd
+
+* Changes in ospfd
+
+** ospfd work is started by Toshiaki Takada <takada@zebra.org>. Now
+several files are included in ospfd directory.
+
+** ospf6d codes are merged from Yasuhiro Ohara <yasu@sfc.wide.ad.jp>'s
+ospfd work. Now codes are located in ospf6d directory.
+
+
+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 <kunihiro@zebra.org>
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 <kunihiro@zebra.org> */
+
+/* Version of GNU Zebra */
+#undef VERSION
+
+/* Solaris on x86. */
+#undef SOLARIS_X86
+
+/* Package name of GNU Zebra */
+#undef PACKAGE
+
+/* Define if host is GNU/Linux */
+#undef GNU_LINUX
+
+/* Define if you have the AF_ROUTE socket. */
+#undef HAVE_AF_ROUTE
+
+/* Define if you have the inet_aton function. */
+#undef HAVE_INET_ATON
+
+/* Define if you have the inet_ntop function. */
+#undef HAVE_INET_NTOP
+
+/* Define if you have the inet_pton function. */
+#undef HAVE_INET_PTON
+
+/* Define if you have the setproctitle function. */
+#undef HAVE_SETPROCTITLE
+
+/* Define if you have ipv6 stack. */
+#undef HAVE_IPV6
+
+/* Define if you wish to support ipv6 router advertisment. */
+/* #undef HAVE_RTADV */
+
+/* whether system has GNU regex */
+#undef HAVE_GNU_REGEX
+
+/* whether system has SNMP library */
+#undef HAVE_SNMP
+
+/* whether sockaddr has a sa_len field */
+#undef HAVE_SA_LEN
+
+/* whether sockaddr_in has a sin_len field */
+#undef HAVE_SIN_LEN
+
+/* whether sockaddr_un has a sun_len field */
+#undef HAVE_SUN_LEN
+
+/* whether sockaddr_in6 has a sin6_scope_id field */
+#undef HAVE_SIN6_SCOPE_ID
+
+/* Define if there is socklen_t. */
+#undef HAVE_SOCKLEN_T
+
+/* Define if there is sockaddr_dl structure. */
+#undef HAVE_SOCKADDR_DL
+
+/* Define if there is ifaliasreq structure. */
+#undef HAVE_IFALIASREQ
+
+/* Define if there is in6_aliasreq structure. */
+#undef HAVE_IN6_ALIASREQ
+
+/* Define if there is rt_addrinfo structure. */
+#undef HAVE_RT_ADDRINFO
+
+/* Define if there is in_pktinfo structure. */
+#undef HAVE_INPKTINFO
+
+/* Define if you have the getrusage function. */
+#undef HAVE_RUSAGE
+
+/* Define if /proc/net/dev exists. */
+#undef HAVE_PROC_NET_DEV
+
+/* Define if /proc/net/if_inet6 exists. */
+#undef HAVE_PROC_NET_IF_INET6
+
+/* Define if NET_RT_IFLIST exists in sys/socket.h. */
+#undef HAVE_NET_RT_IFLIST
+
+/* Define if you have INRIA ipv6 stack. */
+#undef INRIA_IPV6
+
+/* Define if you have KAME project ipv6 stack. */
+#undef KAME
+
+/* Define if you have Linux ipv6 stack. */
+#undef LINUX_IPV6
+
+/* Define if you have NRL ipv6 stack. */
+#undef NRL
+
+/* Define if you have BSDI NRL IPv6 stack. */
+#undef BSDI_NRL
+
+/* Define if one-vty option is specified. */
+#undef VTYSH
+
+/* Define if interface aliases don't have distinct indeces */
+#undef HAVE_BROKEN_ALIASES
+
+/* Define if disable-bgp-announce option is specified. */
+#undef DISABLE_BGP_ANNOUNCE
+
+/* PAM support */
+#undef USE_PAM
+
+/* TCP/IP communication between zebra and protocol daemon. */
+#undef HAVE_TCP_ZEBRA
+
+/* The OSPF NSSA option (RFC1587). */
+#undef HAVE_NSSA
+
+/* The OSPF Opaque LSA option (RFC2370). */
+#undef HAVE_OPAQUE_LSA
+
+/* Traffic Engineering Extension to OSPF
+ (draft-katz-yeung-ospf-traffic-06.txt). */
+#undef HAVE_OSPF_TE
+
+/* Linux netlink. */
+#undef HAVE_NETLINK
+
+/* PATHS */
+#undef PATH_ZEBRA_PID
+#undef PATH_RIPD_PID
+#undef PATH_RIPNGD_PID
+#undef PATH_BGPD_PID
+#undef PATH_OSPFD_PID
+#undef PATH_OSPF6D_PID
+
+/* Define if Solaris */
+#undef SUNOS_5
+
+/* Define if FreeBSD 3.2 */
+#undef FREEBSD_32
+
+/* Define if OpenBSD */
+#undef OPEN_BSD
+
+#ifdef HAVE_IPV6
+#ifdef KAME
+#ifndef INET6
+#define INET6
+#endif /* INET6 */
+#endif /* KAME */
+#endif /* HAVE_IPV6 */
+
+#ifdef SUNOS_5
+typedef unsigned int u_int32_t;
+typedef unsigned short u_int16_t;
+typedef unsigned short u_int8_t;
+#endif /* SUNOS_5 */
+
+#ifndef HAVE_SOCKLEN_T
+typedef int socklen_t;
+#endif /* HAVE_SOCKLEN_T */
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
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
+ <type, length, value>.
+
+ The type is a 1-octet field which has two
+ possible values:
+ 1 AS_SET: unordered set of ASs a
+ route in the UPDATE message
+ has traversed
+ 2 AS_SEQUENCE: ordered set of ASs
+ a route in the UPDATE message
+ has traversed.
+
+ The length is a 1-octet field containing the
+ number of ASs in the value field.
+
+ The value field contains one or more AS
+ numbers, each AS is represented in the octet
+ string as a pair of octets according to the
+ following algorithm:
+
+ first-byte-of-pair = ASNumber / 256;
+ second-byte-of-pair = ASNumber & 255;"
+ ::= { bgp4PathAttrEntry 5 }
+
+ bgp4PathAttrNextHop OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The address of the border router that should
+ be used for the destination network."
+ ::= { bgp4PathAttrEntry 6 }
+
+ bgp4PathAttrMultiExitDisc OBJECT-TYPE
+ SYNTAX INTEGER (-1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "This metric is used to discriminate between
+ multiple exit points to an adjacent autonomous
+ system. A value of -1 indicates the absence of
+ this attribute."
+ ::= { bgp4PathAttrEntry 7 }
+
+ bgp4PathAttrLocalPref OBJECT-TYPE
+ SYNTAX INTEGER (-1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The originating BGP4 speaker's degree of
+ preference for an advertised route. A value of
+ -1 indicates the absence of this attribute."
+ ::= { bgp4PathAttrEntry 8 }
+
+ bgp4PathAttrAtomicAggregate OBJECT-TYPE
+ SYNTAX INTEGER {
+ lessSpecificRrouteNotSelected(1),
+ lessSpecificRouteSelected(2)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Whether or not a system has selected
+ a less specific route without selecting a
+ more specific route."
+ ::= { bgp4PathAttrEntry 9 }
+
+ bgp4PathAttrAggregatorAS OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The AS number of the last BGP4 speaker that
+ performed route aggregation. A value of zero (0)
+ indicates the absence of this attribute."
+ ::= { bgp4PathAttrEntry 10 }
+
+ bgp4PathAttrAggregatorAddr OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The IP address of the last BGP4 speaker that
+ performed route aggregation. A value of
+ 0.0.0.0 indicates the absence of this attribute."
+ ::= { bgp4PathAttrEntry 11 }
+
+ bgp4PathAttrCalcLocalPref OBJECT-TYPE
+ SYNTAX INTEGER (-1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The degree of preference calculated by the
+ receiving BGP4 speaker for an advertised route.
+ A value of -1 indicates the absence of this
+ attribute."
+ ::= { bgp4PathAttrEntry 12 }
+
+ bgp4PathAttrBest OBJECT-TYPE
+ SYNTAX INTEGER {
+ false(1),-- not chosen as best route
+ true(2) -- chosen as best route
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "An indication of whether or not this route
+ was chosen as the best BGP4 route."
+ ::= { bgp4PathAttrEntry 13 }
+
+ bgp4PathAttrUnknown OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..255))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "One or more path attributes not understood
+ by this BGP4 speaker. Size zero (0) indicates
+ the absence of such attribute(s). Octets
+ beyond the maximum size, if any, are not
+ recorded by this object."
+ ::= { bgp4PathAttrEntry 14 }
+
+
+ -- Traps.
+
+ -- note that in RFC 1657, bgpTraps was incorrectly
+ -- assigned a value of { bgp 7 }, and each of the
+ -- traps had the bgpPeerRemoteAddr object inappropriately
+ -- removed from their OBJECTS clause. The following
+ -- definitions restore the semantics of the traps as
+ -- they were initially defined in RFC 1269.
+
+ -- { bgp 7 } is unused
+
+ bgpTraps OBJECT IDENTIFIER ::= { bgp 0 }
+
+ bgpEstablished NOTIFICATION-TYPE
+ OBJECTS { bgpPeerRemoteAddr,
+ bgpPeerLastError,
+ bgpPeerState }
+ STATUS current
+ DESCRIPTION
+ "The BGP Established event is generated when
+ the BGP FSM enters the ESTABLISHED state."
+ ::= { bgpTraps 1 }
+
+ bgpBackwardTransition NOTIFICATION-TYPE
+ OBJECTS { bgpPeerRemoteAddr,
+ bgpPeerLastError,
+ bgpPeerState }
+ STATUS current
+ DESCRIPTION
+ "The BGPBackwardTransition Event is generated
+ when the BGP FSM moves from a higher numbered
+ state to a lower numbered state."
+ ::= { bgpTraps 2 }
+
+ -- conformance information
+
+ bgpMIBConformance OBJECT IDENTIFIER ::= { bgp 8 }
+ bgpMIBCompliances OBJECT IDENTIFIER ::= { bgpMIBConformance 1 }
+ bgpMIBGroups OBJECT IDENTIFIER ::= { bgpMIBConformance 2 }
+
+ -- compliance statements
+
+ bgpMIBCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for entities which
+ implement the BGP4 mib."
+ MODULE -- this module
+ MANDATORY-GROUPS { bgp4MIBGlobalsGroup,
+ bgp4MIBPeerGroup,
+ bgp4MIBPathAttrGroup,
+ bgp4MIBNotificationGroup }
+ ::= { bgpMIBCompliances 1 }
+
+ -- units of conformance
+
+ bgp4MIBGlobalsGroup OBJECT-GROUP
+ OBJECTS { bgpVersion,
+ bgpLocalAs,
+ bgpIdentifier }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing information
+ on global BGP state."
+ ::= { bgpMIBGroups 1 }
+
+ bgp4MIBPeerGroup OBJECT-GROUP
+ OBJECTS { bgpPeerIdentifier,
+ bgpPeerState,
+ bgpPeerAdminStatus,
+ bgpPeerNegotiatedVersion,
+ bgpPeerLocalAddr,
+ bgpPeerLocalPort,
+ bgpPeerRemoteAddr,
+ bgpPeerRemotePort,
+ bgpPeerRemoteAs,
+ bgpPeerInUpdates,
+ bgpPeerOutUpdates,
+ bgpPeerInTotalMessages,
+ bgpPeerOutTotalMessages,
+ bgpPeerLastError,
+ bgpPeerFsmEstablishedTransitions,
+ bgpPeerFsmEstablishedTime,
+ bgpPeerConnectRetryInterval,
+ bgpPeerHoldTime,
+ bgpPeerKeepAlive,
+ bgpPeerHoldTimeConfigured,
+ bgpPeerKeepAliveConfigured,
+ bgpPeerMinASOriginationInterval,
+ bgpPeerMinRouteAdvertisementInterval,
+ bgpPeerInUpdateElapsedTime }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects for managing
+ BGP peers."
+ ::= { bgpMIBGroups 2 }
+
+ bgp4MIBRcvdPathAttrGroup OBJECT-GROUP
+ OBJECTS { bgpPathAttrPeer,
+ bgpPathAttrDestNetwork,
+ bgpPathAttrOrigin,
+ bgpPathAttrASPath,
+ bgpPathAttrNextHop,
+ bgpPathAttrInterASMetric }
+ STATUS obsolete
+ DESCRIPTION
+ "A collection of objects for managing BGP
+ path entries.
+
+ This conformance group is obsolete,
+ replaced by bgp4MIBPathAttrGroup."
+ ::= { bgpMIBGroups 3 }
+
+ bgp4MIBPathAttrGroup OBJECT-GROUP
+ OBJECTS { bgp4PathAttrPeer,
+ bgp4PathAttrIpAddrPrefixLen,
+ bgp4PathAttrIpAddrPrefix,
+ bgp4PathAttrOrigin,
+ bgp4PathAttrASPathSegment,
+ bgp4PathAttrNextHop,
+ bgp4PathAttrMultiExitDisc,
+ bgp4PathAttrLocalPref,
+ bgp4PathAttrAtomicAggregate,
+ bgp4PathAttrAggregatorAS,
+ bgp4PathAttrAggregatorAddr,
+ bgp4PathAttrCalcLocalPref,
+ bgp4PathAttrBest,
+ bgp4PathAttrUnknown }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects for managing
+ BGP path entries."
+ ::= { bgpMIBGroups 4 }
+
+ bgp4MIBNotificationGroup NOTIFICATION-GROUP
+ NOTIFICATIONS { bgpEstablished,
+ bgpBackwardTransition }
+ STATUS current
+ DESCRIPTION
+ "A collection of notifications for signaling
+ changes in BGP peer relationships."
+ ::= { bgpMIBGroups 5 }
+
+ END
diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog
new file mode 100644
index 00000000..4f7a20e9
--- /dev/null
+++ b/bgpd/ChangeLog
@@ -0,0 +1,2368 @@
+2002-10-23 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * bgp_aspath.c (aspath_init): Extend hash size from default to
+ 32767.
+ (aspath_key_make): Use unsigned shoft for making hash. Suggested
+ by: Marc Evans <Marc@SoftwareHackery.Com>
+
+2002-08-19 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * bgp_clist.c (community_entry_free): Fix memory leak of standard
+ extcommunity-list config string.
+
+2002-08-19 Akihiro Mizutani <mizutani@net-chef.net>
+
+ * bgp_route.c (route_vty_out_detail): Fix bug of router-id display
+ when multiple instance is used.
+
+2002-08-18 Akihiro Mizutani <mizutani@net-chef.net>
+
+ * bgpd.c: Make "default-originate" and "maximum-prefix" commands
+ available in peer-group configuration.
+
+2002-08-13 Akihiro Mizutani <mizutani@net-chef.net>
+
+ * bgp_packet.c (bgp_open_send): Put Opt Parm Len 0 when last
+ capability packet cause error or dont-capability-negotiate option
+ is specified.
+
+2002-07-07 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.93 released.
+
+2001-10-28 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (bgp_vty_init): Translate update commands are removed.
+
+2001-10-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_static_set): Add workaround for BGP static
+ route announcement when there is no zebra running.
+
+2001-10-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (neighbor_remote_as_unicast): Remove "remote-as nlri
+ unicast multicast" commands.
+
+2001-09-14 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_open.c: When we receive capability route-refresh, we should
+ check we send the capability not we receive the capability.
+
+ * bgp_route.c (bgp_network_mask_natural_route_map): network
+ statement route-map is added.
+
+2001-08-31 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * bgp_advertise.c (bgp_advertise_intern): attr must be interned
+ before looking up hash table.
+
+2001-08-30 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * bgpd.h (struct peer): BGP filter is moved from peer_conf to
+ peer.
+
+2001-08-28 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * bgp_nexthop.c (bnc_nexthop_free): Fix next pointer bug.
+ Suggested by: "Hong-Sung Kim" <hoskim@lanbird.co.kr>.
+
+2001-08-26 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * bgp_table.c (bgp_node_create): Clearn memory before use it.
+
+2001-08-24 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * Change to use bgp_table.[ch].
+
+2001-08-23 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * bgpd.c (bgp_init): Add "transparent-as" and
+ "transparent-nexthop" for old version compatibility.
+
+2001-08-23 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd.h (struct peer): default-originate route-map is added.
+
+ * bgp_route.c: When self originated route is advertised with
+ attrubute-unchanged, nexthop was not properly set. This bug is
+ fixed.
+
+2001-08-22 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd.c (neighbor_attr_unchanged): transparent-as and
+ transparent-next-hop commands are restructured. Instead of
+ current transparent-* commands, attribute-unchanged command is
+ introduced.
+
+ neighbor A.B.C.D attribute-unchanged [as-path|next-hop|med]
+
+ (neighbor_default_originate): "default-originate" configuration
+ announce default route even 0.0.0.0/0 does not exists in BGP RIB.
+
+2001-08-19 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92a released.
+
+2001-08-19 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd.c: AF specific soft-reconfiguration inbound commands are
+ added.
+
+2001-08-17 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * bgp_route.c (bgp_show_callback): Do not do community NULL check.
+
+ * bgp_community.c (community_cmp): Add check for commnunity NULL
+ check.
+
+ * bgp_routemap.c (route_match_community): Do not check comunity is
+ NULL. It may match to community-list "^$".
+
+ * bgp_community.c (community_match): Add check for community is
+ NULL case.
+
+2001-08-17 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd.c: AF specific route-reflector-client and
+ route-server-client configuration are added.
+
+2001-08-17 Rick Payne <rickp@ayrnetworks.com>
+
+ * bgp_clist.c (community_match_regexp): Check special ^$ case.
+
+2001-08-17 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_clist.c (community_list_match): Fix bug of community list
+ permit and deny check.
+
+2001-08-16 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_mplsvpn.c (bgp_mplsvpn_init): Add AF specific "nexthop-self"
+ command.
+
+2001-08-15 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd.h (PEER_FLAG_SEND_COMMUNITY): Per AF based configuration
+ flag is introduced.
+
+ * bgp_mplsvpn.c (bgp_mplsvpn_init): VPNv4 filtering is added.
+
+2001-08-15 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92 released.
+
+2001-08-13 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * bgpd.c (bgp_delete): "no router bgp" free static, aggregate, rib
+ table properly.
+
+2001-08-12 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * bgp_route.c (bgp_node_safi): Return SAFI of current node.
+ (bgp_config_write_network_vpnv4): VPNv4 static configuration
+ display.
+
+2001-08-11 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * bgpd.c (no_bgp_ipv4_multicast_route_map): Add IPv4 multicast
+ node filter commands.
+
+2001-08-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.h (PEER_FLAG_IGNORE_LINK_LOCAL_NEXTHOP): Add
+ "ignore-link-local-nexthop" flag for ignore link-local nexthop for
+ IPv6.
+
+2001-08-07 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * bgpd.c (address_family_ipv4_multicast): "address-family ipv4
+ multicast" is added.
+ (address_family_ipv6_unicast): "address-family ipv6 unicast" is
+ added.
+
+2001-08-07 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_route.c (bgp_process): Use flag instead of as_selected
+ memeber in struct bgp_info.
+
+ * bgp_route.h (struct bgp_info): Remove as_selected memeber from
+ struct bgp_info.
+
+2001-07-31 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * bgp_route.c (bgp_announce_check): Enclose sending time AS loop
+ check code with #ifdef BGP_SEND_ASPATH_CHECK.
+
+2001-07-29 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * bgp_packet.c (bgp_withdraw_send): Simplify address family check.
+
+ * bgpd.h (BGP_INFO_HOLDDOWN): Introduce new macro to check BGP
+ information is alive or not.
+
+ * bgp_community.c: Use community_val_get() on all OS.
+
+2001-07-24 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * bgp_route.c (bgp_announce_check): Simplify set next-hop self
+ check.
+
+2001-07-24 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_route.c (bgp_announce_check): To route server clients, we
+ announce AS path, MED and nexthop transparently.
+
+2001-06-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_routemap.c (route_set_atomic_aggregate_free): Do not call
+ XFREE. No memory is allocated in
+ route_set_atomic_aggregate_compile().
+
+2001-06-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_routemap.c (bgp_route_map_init): `match nlri` and `set nlri`
+ are replaced by `address-family ipv4` and `address-family vpnvr'.
+
+2001-06-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_withdraw): Add check for BGP_PEER_CONFED.
+ Reported by Rick Payne <rickp@rossfell.co.uk>.
+
+2001-06-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_zebra.c (bgp_zebra_announce): When global IPv6 nexthop is
+ empty, use socket's remote address for the nexthop.
+
+2001-06-04 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * bgpd.c (peer_delete): Fix memory leak. Reported by Yosi Yarchi
+ <Yosi_Yarchi@KereniX.com>
+
+2001-06-01 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * bgpd.c (bgp_delete): Fix memory leak. Reported by Yosi Yarchi
+ <Yosi_Yarchi@KereniX.com>
+
+2001-05-27 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * bgp_route.c (bgp_route_clear_with_afi_vpnv4): Use next instead
+ of ri->next.
+
+ * bgp_packet.c (bgp_withdraw_send): MPLS/VPN withdraw takes effect
+ when HAVE_IPV6 is not defined.
+
+2001-03-07 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgpd.c (peer_timers_set): Adjust keepalive timer to fit less
+ than holdtime / 3.
+ (bgp_confederation_peers_unset): Only set peer->local_as when
+ confederation is enabled.
+ (bgp_timers): Add "timers bgp <0-65535> <0-65535>" command.
+
+ * bgp_route.c (bgp_announce_check): Set med of redistributed route
+ when it is announced to EBGP peer.
+
+2001-03-06 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_nexthop.c (bgp_scan_ipv4): bgp_scan() call bgp_process() for
+ all prefixes.
+
+2001-03-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_attr.c (bgp_attr_origin): When bgpd send NOTIFICATION with
+ erroneous attribute (type, length and value), it does include
+ attribute flags field.
+
+2001-02-21 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_route.c (bgp_announce_check): The route reflector is not
+ allowed to modify the attributes of the reflected IBGP routes.
+
+2001-02-20 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_route.c (bgp_info_cmp): During path seleciton, BGP
+ confederation peer is treated as same as IBGP peer.
+
+2001-02-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_redistribute_add): Initialize attr_new with
+ attr. Call aspath_unintern when return from this function.
+
+2001-02-19 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgpd.c (bgp_router_id_set): Reset BGP peer when router-id is
+ changed.
+
+2001-02-18 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_packet.c (bgp_open_receive): When user configure holdtimer,
+ do not refrect the value to current session.
+
+2001-02-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_aggregate_delete): Set BGP_INFO_ATTR_CHANGE to
+ suppress route withdraw.
+
+ * bgp_damp.c (bgp_damp_init): Fix bug of flap dampening.
+
+2001-02-16 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_aspath.c (aspath_make_str_count): Use ',' for separator for
+ AS_SET and AS_CONFED_SET.
+
+2001-02-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_process): Do not consider suppress route.
+
+ * bgp_aspath.c (aspath_aggregate_as_set_add): Reset asset when
+ aspath->data is realloced.
+
+2001-02-15 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_attr.c (bgp_attr_aggregate_intern): Do not set atomic
+ aggregate when using as-set.
+
+2001-02-14 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgpd.c (bgp_confederation_peers_unset): Set peer's local-as
+ correctly.
+
+ * bgp_route.c (bgp_update): Just ignore AS path loop for
+ confederation peer.
+
+2001-02-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_aggregate_set): Add as_set argument.
+ (bgp_aggregate_unset): Remove summary_only argument.
+ (aggregate_address_as_set): New commands.
+ "aggregate-address A.B.C.D/M as-set"
+ "no aggregate-address A.B.C.D/M as-set"
+
+2001-02-08 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_route.c (bgp_announce_check): Do not modify nexthop when the
+ route is passed by route reflector.
+
+2001-02-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c: "no bgp dampening" with argument.
+ (bgp_announce_check): Do not modify nexthop when the route is
+ passed by route reflector.
+
+2001-02-07 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgpd.c (neighbor_passive): Change "neighbor NEIGHBOR remote-as
+ ASN passive" to "neighbor NEIGHBOR passive".
+ (bgp_announce_check): Check well-known community attribute even
+ when "no neighbor send-community" is set.
+
+2001-02-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_fsm.c (bgp_establish): Do not send keepalive at established
+ time when keepalive timer is configured as zero.
+
+2001-02-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_attr.c (bgp_attr_check): When peer is IBGP peer, local
+ preference is well-known attribute.
+
+2001-01-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.91 is released.
+
+ * bgp_attr.h (struct attr): Comment out DPA value.
+ (struct attr): Change refcnt type from int to unsinged long.
+
+ * bgp_attr.c (attrhash_key_make): Likewise.
+ (attrhash_cmp): Likewise.
+ (bgp_attr_dpa): Likewise.
+
+2001-01-30 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_route.c (bgp_info_cmp): Make route selection completely same
+ as Cisco's.
+
+2001-01-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_attr.h (BGP_ATTR_FLAG_OPTIONAL): Rename old ATTR_FLAG_* to
+ BGP_ATTR_FLAG_* to clarify meenings.
+
+2001-01-30 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_route.c (route_vty_out): Display argument to suppress same
+ prefix information display.
+ (route_vty_out_route): Don't display mask information for
+ classfull network.
+
+2001-01-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_attr.h (SET_BITMAP): Simple bitmapping macros.
+
+ * bgp_attr.c (bgp_attr_parse): Use bitmap for attribute type
+ check.
+
+2001-01-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_attr.c (bgp_mp_reach_parse): Enclose loggin with BGP_DEBUG.
+ (bgp_attr_parse): Comment out well-known attribute check.
+
+2001-01-28 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_static_unset): Link-local IPv6 address can't be
+ used for network advertisement.
+ (nlri_parse): When link-local IPv6 address NLRI comes from
+ remote-peer, log the information then simply ignore it.
+
+ * bgp_zebra.c (zebra_read_ipv6): Link-local IPv6 address is not
+ redistributed.
+
+ * bgp_route.c (bgp_update): Check IPv6 global nexthop
+ reachability.
+
+2001-01-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_update): Check nexthop points local address or
+ not.
+ (bgp_static_update_vpnv4): Set valid flag.
+
+ * bgp_attr.c (bgp_attr_parse): Duplicate attribute check.
+ (bgp_attr_parse): Well-known attribute check.
+
+ * bgp_open.c (bgp_auth_parse): Authentication is not yet supported.
+
+ * bgp_packet.c (bgp_valid_marker): Check marker is synchronized.
+
+ * bgpd.c (clear_bgp): Send NOTIFICATION Cease when SEND_CEASE is
+ defined.
+
+ * bgp_snmp.c (bgp4PathAttrTable): Fix compile error.
+
+2001-01-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (bgp_network_import_check): New command for IGP network
+ check.
+
+2001-01-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_nexthop.c (bgp_scan): Run bgp_process when IGP metric is
+ changed. Call bgp_process once for each node.
+
+2001-01-23 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_route.c (bgp_info_cmp): Add IGP metric comparison.
+
+2001-01-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_info_cmp): Add IGP metric comparison.
+
+ * bgp_nexthop.c (bgp_nexthop_lookup): Set IGP metric for valid
+ IBGP route.
+
+2001-01-23 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_route.c (show_ip_bgp_prefix_longer): Add new commands.
+ "show ip bgp A.B.C.D/M longer-prefixes"
+ "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes"
+ "show ipv6 bgp X:X::X:X/M longer-prefixes"
+ "show ipv6 mbgp X:X::X:X/M longer-prefixes"
+
+2001-01-20 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_route.c (show_ip_bgp_cidr_only): Add new commands.
+ "show ip bgp cidr-only"
+ "show ip bgp ipv4 (unicast|multicast) cidr-only"
+
+2001-01-18 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_route.c (bgp_update): AS path lookup check is done in
+ bgp_update() not in attr_parse().
+
+2001-01-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_update): Call bgp_aggregate_decrement() just
+ before bgp_attr_unintern().
+
+2001-01-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_update): Now intern is performed very last part
+ of the BGP packet update procedure.
+
+2001-01-17 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_route.c (bgp_update): When implicit withdraw occur, reuse
+ existing bgp_info structure.
+
+2001-01-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_aggregate_decrement): Fix bug of aggregate
+ address matching method.
+ (bgp_update):
+
+ * bgp_nexthop.c (bgp_nexthop_onlink): Separate EBGP nexthop onlink
+ check and IBGP nexthop route check.
+
+2001-01-16 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_route.h (BGP_INFO_ATRR_CHANGED): Added for track attribute
+ change.
+
+2001-01-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.h (struct bgp_info): Remove selected flag. Use
+ BGP_INFO_SELECTED for flags instead.
+ (struct bgp_info): Remove valid flag. Use BGP_INFO_VALID for
+ flags instead.
+ (struct bgp_info): Add igpmetric for IBGP route nexthop IGP
+ metric.
+ (struct bgp_info_tab): Struct bgp_info_tag is integrated into
+ struct bgp_info.
+ (BGP_INFO_ATRR_CHANGED): Added for track attribute change.
+
+ * bgp_community.c (community_val_get): gcc-2.95 on
+ sparc-sun-solaris cause crush. This function is for avoid the
+ crush.
+
+2001-01-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_packet.c (bgp_open_receive): Translated peer's packet_size
+ clear bug is fixed.
+
+2001-01-14 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_packet.c (bgp_open_receive): Return notification with
+ supported version number.
+
+2001-01-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (bgp_show_summary): Display AS path and community
+ entries. Suggested by: "Matt Ranney" <mjr@ranney.com>.
+
+ * bgp_packet.c (bgp_read_packet): Fix bug of unblocking BGP socket
+ read. When BGP packet read is partial, we must get size and type
+ from packet again.
+
+2001-01-12 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_route.c (bgp_update): Do not unset BGP_INFO_HISTORY flag.
+ (bgp_update): When there is a history entry increment route count.
+ (bgp_damp_set): Check BGP_CONFIG_DAMPENING flag.
+
+ * bgp_damp.c (bgp_damp_withdraw): Set status to
+ BGP_DAMP_DISCONTINUE.
+
+2001-01-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_attr.c (bgp_mp_reach_parse): Fix warning code when second
+ IPv6 nexthop is not link-local addresss.
+
+2001-01-11 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_damp.c (bgp_config_write_damp): Smart flap dampening
+ configuration display.
+ (bgp_damp_info_print): Display elapsed time from flap started.
+
+ * bgp_damp.h (struct bgp_damp_info): Add flap start time.
+
+ * bgpd.c (peer_create): Set last read time.
+ (bgp_show_peer): Display last read time.
+ (bgp_show_summary): Use BGP_CONFIG_DAMPENING flag to check
+ configuration.
+
+ * bgpd.h (BGP_CONFIG_DAMPENING): Add new configuration option.
+ (struct peer): Add last read time member.
+ (BGP_VERSION_MP_4): Remove obsolete definition.
+
+2001-01-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_nexthop.c: Remove OLD_RIB codes.
+
+ * bgp_route.c (bgp_process): Likewise.
+
+ * zebra-0.90 is released.
+
+ * bgp_route.h (BGP_INFO_HISTORY): Remove damped member from struct
+ bgp_info. Instead of that use BGP_INFO_DAMPED flag.
+ (struct bgp_info): Remove invalid member from struct bgp_info.
+ Instead of that use BGP_INFO_HISTORY flag.
+
+2001-01-10 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgp_damp.c (bgp_damp_info_print): New function to display
+ dampening status.
+ (DEFAULT_HARF_LIFE): Define default value.
+ (DEFAULT_REUSE): Likewise.
+ (DEFAULT_SUPPRESS): Likewise.
+ (bgp_config_write_damp): When config value is same as default
+ value, simply display "bgp dampening" to configuration.
+
+ * bgp_damp.h (struct bgp_damp_info): Add flap member.
+
+ * bgp_route.h (struct bgp_info): Added for BGP flap dampening
+ history status.
+
+2001-01-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_nexthop.c (bgp_connected_add): Point-to-point connected
+ address is properly handled.
+ (bgp_connected_delete): Likewise.
+
+ * bgp_route.c (bgp_route_init): Turn off BGP Flap dampening code
+ until it works fine.
+
+2001-01-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (bgp_show_summary): Add BGP_VERSION_MP_4 case.
+
+ * bgp_route.c (bgp_update): When this is not damped route, clear
+ ri pointer.
+
+2001-01-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_main.c: Add "-n" no_kernel option to not install route to
+ kernel. Suggested by: "Matt Ranney" <mjr@ranney.com>
+
+2001-01-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_nexthop.c (bgp_connected_add): Revert point-to-point
+ connected route patch. Reported by ruud@ruud.org (Ruud de Rooij)
+
+ * bgp_damp.c (bgp_config_write_damp): Add configuration display
+ function.
+
+ * bgp_route.c (bgp_info_free): Set NULL to BGP dampening
+ information when BGP info structure is freed.
+ (bgp_info_cmp): Check damped flag.
+ (bgp_announce_check): Damped route is not announced.
+
+2001-01-09 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * bgpd.c (neighbor_capability_route_refresh): Change "neighbor
+ route-refresh" command to "neighbor capability route-refresh".
+ (clear_bgp_soft_in): Change soft-reconfig method.
+
+ clear ip bgp <neighbor> soft in
+ --------------------------------------
+ Try stored cache first then route-refresh
+
+ clear ip bgp <neighbor> in
+ ---------------------------------
+ Try route-refresh first then try to use stored cache
+
+2001-01-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_nexthop.c (bgp_connected_add): Check point-to-point
+ connected route. Reported by ruud@ruud.org (Ruud de Rooij)
+
+2001-01-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_nexthop.c (bgp_nexthop_lookup): When IBGP nexthop is
+ changed, refresh it.
+
+2001-01-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.h (struct bgp_info_tag): Add as_selected to
+ bgp_info_tag.
+
+2001-01-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.h (struct bgp_info_tag): Add damped and bgp_damp_info
+ member for BGP flap dampening.
+
+ * bgp_damp.c: New file is added.
+
+ * bgp_damp.h: Likewise.
+
+2001-01-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.h (BGP_VTYSH_PATH): Change "/tmp/bgpd" to "/tmp/.bgpd".
+
+2000-12-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_nexthop.c (zlookup_connect): Change to use UNIX domain
+ socket for zebra communication.
+
+2000-12-29 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_route.c (bgp_process): Fix "bgp deterministic-med" process.
+
+2000-12-27 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_route.c (bgp_process): Add "bgp deterministic-med" process.
+
+2000-12-25 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_route.c (bgp_info_cmp): Use ntohl comparing router ID.
+
+2000-12-18 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_route.c (bgp_info_cmp): When over three same prefix exit,
+ withdrawing best prefix perform router ID comparison.
+
+2000-12-15 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_route.c (bgp_info_cmp): Do not compare router ID when the
+ routes comes from EBGP peer. When originator ID is same, take
+ shorter cluster-list route. If cluster-list is same take smaller
+ IP address neighbor's route.
+
+ * bgpd.c (bgp_bestpath_aspath_ignore): Add "bgp bestpath as-path
+ ignore" command. When this option is set, do not concider AS path
+ length when route selection.
+ (bgp_bestpath_compare_router_id): Add "bgp bestpath
+ compare-routerid". When this option is set, compare router ID
+ when the routes comes from EBGP peer.
+
+2000-12-15 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_route.c (bgp_info_cmp): Compare originator ID when it is
+ available.
+
+2000-12-14 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_packet.c (bgp_notify_receive): Disply received Notify data
+ information.
+
+2000-12-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_filter.c (as_filter_free): Use MTYPE_AS_FILTER_STR to make
+ it sure the memory is freed.
+
+ * bgp_route.c (route_vty_out_detail): Do not use AF_INET6 outside
+ HAVE_IPV6.
+
+2000-12-08 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_packet.c (bgp_notify_send_with_data): Store BGP notification
+ data part.
+
+ * bgp_network.c (bgp_accept): When BGP connection comes from
+ unconfigured IP address, close socket immediately.
+
+ * bgpd.c: Fix some display format.
+
+2000-11-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_packet.c (bgp_keepalive_send): Delete duplicate
+ bgp_packet_set_size () call.
+
+2000-11-28 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_packet.c (bgp_read_packet): Remove debug codes.
+
+2000-11-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_snmp.c (write_bgpPeerTable): Add SNMP set method routine.
+
+ * bgp_fsm.c (bgp_stop): Use fsm_change_status to change peer's
+ status.
+ (bgp_establish): Likewise.
+
+2000-11-26 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_open.c: Fix error messages.
+
+2000-11-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_fsm.c (bgp_establish): Call BGP trap when the peer is
+ established.
+ (bgp_stop): Call BGP trap when the peer is dropped.
+
+2000-11-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_snmp.c (bgp4PathAttrTable): Return BGP path attribute table.
+
+ * bgpd.h (struct peer): Add update_time for track last update
+ received time.
+
+ * bgp_packet.c (bgp_notify_receive): Preserv notify code and sub
+ code in any case.
+
+ * bgp_snmp.c (bgpPeerTable): Return remote router ID instead of
+ peering IP address.
+ (bgpPeerTable): Return actual BGP version number.
+
+2000-11-22 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_debug.c (bgp_notify_print): Notify data length display bug
+ is fixed.
+
+2000-11-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_nexthop.c (zlookup_connect): When UNIX domain connection to
+ zebra is enabled, use the method.
+
+2000-11-16 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd.c: Revise debug message output.
+
+2000-11-15 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_clist.c (ip_community_list): Fix bug of string comparison.
+
+2000-11-14 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_community.c (community_match): Fix bug of memcmp return
+ value check.
+
+2000-11-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_clist.c (community_list_match_exact): Add check for
+ entry->style is COMMUNITY_LIST.
+ (community_match_regexp): Apply new com_nthval macro.
+
+2000-11-07 Rick Payne <rickp@rossfell.co.uk>
+
+ * bgp_routemap.c (route_set_community_delete): "set
+ community-delete COMMUNITY-LIST" is added.
+
+ * bgp_community.c (community_del_val): Delete one community.
+ (community_delete): Delete all community included in list.
+ (community_match): Fix bug of matching community value.
+
+ * bgp_clist.c (community_entry_free): Free community regular
+ expression.
+ (community_entry_make): Default style is COMMUNITY_LIST.
+ (community_entry_lookup): Make it sure style is COMMUNITY_LIST.
+ (community_entry_regexp_lookup): New function for community
+ regular expression lookup.
+ (community_match_regexp): New function.
+ (community_delete_regexp): New function.
+ (community_list_delete_entries): New function.
+ (community_list_match): Add COMMUNITY_REGEXP treatment.
+ (community_list_match_exact): Likewise.
+ (config_write_community): Write community list according to
+ entry->style.
+
+2000-11-07 Rick Payne <rickp@rossfell.co.uk>
+
+ * bgp_attr.c (bgp_attr_aspath): AS path first AS check.
+
+ * bgp_clist.c (struct community_entry): Add style, regexp, reg to
+ community_entry.
+
+2000-11-06 Rick Payne <rickp@rossfell.co.uk>
+
+ * bgp_aspath.c (aspath_firstas_check): AS path first AS check.
+
+ * bgpd.c (bgp_enforce_first_as): New command "bgp
+ enforce-first-as".
+
+ * bgpd.h (BGP_CONFIG_ENFORCE_FIRST_AS): Add new flag.
+
+2000-11-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_community.c (community_compare): Copy byte stream data to
+ actual value instead of using type casting hack.
+ (community_add_val): Likewise.
+ (community_uniq_sort): Likewise.
+ (community_print): Likewise.
+ (community_print_vty): Likewise.
+ (community_include): Use memcmp to compare community value.
+
+ * bgp_community.h (com_lastval): com_lastval and com_nthval macro
+ return pointer.
+
+2000-11-06 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd.h (struct peer): Add established and dropped member for
+ count peering up/down statistics.
+
+ * bgpd.c (bgp_show_peer): Display peering up/down statistics.
+
+ * bgp_fsm.c (bgp_establish): Increment established count.
+ (bgp_stop): Increment dropped count.
+
+ * bgp_packet.c (bgp_notify_receive): Increament notify count.
+
+2000-11-1 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_fsm.c: Fix bug of holdtimer is not reset when bgp cleared.
+
+2000-10-31 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.h: Static bit flag is set by (1 << DIGIT).
+
+2000-10-24 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_ecommunity.c (ecommunity_dup): Extended community display
+ format fix.
+
+2000-10-24 Arkadiusz Miskiewicz <misiek@pld.org.pl>
+
+ * bgp_network.c (bgp_serv_sock_addrinfo): Use gai_strerror.
+ (bgp_serv_sock_addrinfo): Check address family.
+
+2000-10-23 Jochen Friedrich <jochen@scram.de>
+
+ * bgp_snmp.c: bgp_oid and bgpd_oid are used in smux_open after it
+ is registered. So those variables must be static.
+
+2000-10-23 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_routemap.c (route_match_ip_next_hop): Change "match ip
+ next-hop" argument from IP address to access-list name.
+ Remove zebra-0.88 compatibility commands.
+ "match ip prefix-list WORD"
+ "match ipv6 prefix-list WORD"
+
+2000-10-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_routemap.c (route_match_ipv6_next_hop_compile): Fix bug of
+ passing the pointer to the pointer of struct in6_addr instead of
+ the pointer of struct in6_addr in "match ipv6 next-hop" command.
+
+ * bgp_route.c (bgp_announce_check): Enclose IPv6 part with
+ HAVE_IPV6.
+
+2000-10-20 Jasper Wallace <jasper@ivision.co.uk>
+
+ * bgp_snmp.c (bgpPeerTable): ntohs missing bug is fixed. Change
+ to use linklist.c. Define COUNTER32 as ASN_COUNTER.
+
+2000-10-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_announce_check): attr->nexthop empty check
+ should be done by attr->nexthop.s_addr instead of strcmp.
+
+2000-10-18 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_zebra.c (zebra_read_ipv4): Pass nexthop value to
+ bgp_redistribute_add().
+
+ * bgp_nexthop.c (bgp_multiaccess_check_v4): New function for
+ checking IPv4 multiaccess nexthop.
+
+ * bgp_route.c (bgp_announce_check): In case of the nexthop is
+ reachable on multiaccess media, do not change nexthop.
+ (bgp_redistribute_add): Set nexthop when the value is passed.
+
+2000-10-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_fsm.c (bgp_timer_set): If peer is passive mode, do not set
+ connect timer.
+ (bgp_start): If the peer is passive mode, force to move to Active
+ mode.
+
+2000-10-17 Horms <horms@vergenet.net>
+
+ * bgp_debug.c (debug_bgp_fsm): Fix typo.
+
+2000-10-17 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_route.c: "show ipv6 bgp" route display improvement.
+
+2000-10-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (neighbor_routes): Allocate sockunion for callback
+ function.
+ (bgp_show_neighbor_route): Remove static declaration for union
+ sockunion.
+
+ * bgpd.c (peer_update_source_set): Clean previously allocated
+ memory before allocate new one.
+
+2000-10-03 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_route.c (neighbor_routes): Add show neighbor's routes
+ command.
+ "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes"
+ "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes"
+ "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes"
+ "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes"
+
+2000-10-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.89 is released.
+
+2000-10-02 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd.c: "bgp deterministic-med" command is added.
+
+2000-10-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_nexthop.c (bgp_connected_add): Apply mask for connected
+ route addition and deletion.
+
+2000-09-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_aspath.c (aspath_cmp_left): Skip confederation AS segment
+ when comparing leftmost AS number.
+
+2000-09-29 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd.c (peer_route_reflector): Route reflector can be set for
+ IBGP peer.
+ (bgp_distribute_set): Fix bug of string check for (in|out).
+ (bgp_show_summary): Display total neighbor count.
+
+2000-09-28 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_attr.c (bgp_packet_attribute): Only add cluster_list and
+ originator for clinet to client routes.
+ (bgp_packet_attribute): Add new cluster_list to the beginning of
+ existing cluster_list.
+ (bgp_packet_attribute): Fix bug of originator is rewritten even
+ when originator is already set.
+
+2000-09-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (bgp_client_to_client_reflection): Add new command.
+ "no bgp client-to-client reflection"
+ "bgp client-to-client reflection"
+
+ * bgpd.h (BGP_CONFIG_NO_CLIENT_TO_CLIENT): Add new definition.
+
+2000-09-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_packet.c (bgp_read): Make BGP packet read to non-blocking
+ read.
+ (bgp_read_packet): Likewise.
+ (bgp_read_packet): When errono is EAGAIN, try to read it again.
+
+ * bgp_fsm.c (bgp_stop): Clear packet size and read buffer.
+
+2000-09-26 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_routemap.c: Configuration of prefix-list match is shown as
+ "match ip address prefix-list <WORD>". Old configuration "match
+ ip prefix-list <WORD>" is left for compatibilitty.
+
+2000-09-25 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd.h (BGP_CONFIG_MED_MISSING_AS_WORST): Changed from
+ BGP_CONFIG_MISSING_AS_WORST.
+
+ * bgpd.c (bgp_bestpath_med): Change missing-as-worst syntax.
+ Old "bgp bestpath missing-as-worst"
+ New "bgp bestpath med missing-as-worst"
+
+2000-09-24 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_route.c: Compare MED properly in case of CONFED-IBGP.
+
+2000-09-21 steve@Watt.COM (Steve Watt)
+
+ * bgp_debug.h: Do not declare debug variables conf_bgp_debug_* and
+ term_bgp_debug_*.
+
+ * bgp_debug.c: Declare variables here.
+
+2000-09-21 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd.c: MBGP soft-reconfiguration command is added.
+ clear ip bgp x.x.x.x ipv4 (unicast|multicast) in
+ clear ip bgp x.x.x.x ipv4 (unicast|multicast) out
+ clear ip bgp x.x.x.x ipv4 (unicast|multicast) soft
+ clear ip bgp <1-65535> ipv4 (unicast|multicast) in
+ clear ip bgp <1-65535> ipv4 (unicast|multicast) out
+ clear ip bgp <1-65535> ipv4 (unicast|multicast) soft
+ clear ip bgp * ipv4 (unicast|multicast) in
+ clear ip bgp * ipv4 (unicast|multicast) out
+ clear ip bgp * ipv4 (unicast|multicast) soft
+
+ Change "clear ip bgp vpnv4 x.x.x.x soft" command to
+ "clear ip bgp x.x.x.x vpnv4 unicast soft".
+
+ "bgp bestpath med confed" command is added.
+
+ * bgpd.h (BGP_CONFIG_MED_CONFED): Add New definition.
+
+2000-09-18 Rick Payne <rickp@rossfell.co.uk>
+
+ * bgpd.c (bgp_show_peer): Fix misplaced #endif.
+
+2000-09-12 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd.c (bgp_default_local_preference): Add "bgp default
+ local-preference" command.
+
+ * bgp_nexthop.c (no_bgp_scan_time): Add "no bgp scan-time"
+ command.
+
+2000-09-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_zebra.c (bgp_zebra_announce): BGP confederation peer's routes
+ are passed to zebra like IBGP route.
+
+2000-09-10 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd.c (bgp_config_write_peer): Make it consistent passive
+ configuration.
+
+ * bgp_route.c: Community match command is added.
+ "show ip bgp community <val>"
+ "show ip bgp community <val> exact-match"
+
+2000-09-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_nexthop.c (bgp_nexthop_lookup): ebgp-multihop routes are
+ treated as IBGP routes.
+
+2000-09-08 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_route.c (bgp_show_route): When local-AS community route is
+ selected, display "not advertised outside local AS" to "show ip
+ route A.B.C.D" output.
+ (show_ip_bgp_ipv4_filter_list): Add below four commands.
+ "show ip bgp ipv4 (unicast|multicast) filter-list WORD"
+ "show ip bgp ipv4 (unicast|multicast) community"
+ "show ip bgp ipv4 (unicast|multicast) community-list WORD"
+ "show ip bgp ipv4 (unicast|multicast) community-list WORD exact-match"
+
+ * bgp_clist.c (community_list_match_exact): Community exact match
+ function.
+
+2000-09-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_update): Add peer's ttl check.
+
+ * bgpd.h (struct peer): Structure member refresh is renamed to
+ refresh_adv.
+
+ * bgpd.c (clear_bgp_soft_in): Check PEER_FLAG_ROUTE_REFRESH flag
+ when soft reconfiguration is performed.
+
+ * bgp_zebra.c (bgp_zebra_announce): When the peer is EBGP and
+ ebgp-multiphop is set, set ZEBRA_FLAG_INTERNAL for nexthop lookup.
+
+ * bgp_route.h (struct bgp_info_tag): Add valid flag.
+
+2000-08-25 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd.c: Add AS base BGP soft reconfiguration.
+
+ * bgp_route.c: When no-advertise or no-export route is selected,
+ "show ip bgp" display "not advertised to EBGP peer" or "not
+ advertised to any peer" message.
+
+2000-08-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.88 is released.
+
+ * bgp_dump.c (dump_bgp_routes): Change "dump bgp routes" to "dump
+ bgp route-mrt" to support MRT specific dump format.
+
+ * bgpd.c (bgp_init): "clear ip bgp vpnv4 soft {in,out}" command is
+ added.
+
+ * bgp_route.c (bgp_update): Currently nexthop check is only works
+ for IPv4.
+
+2000-08-17 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd. (clear_ip_bgp_all_soft): Add "clear ip bgp * soft" for
+ both inbound and outbound soft reconfiguration.
+
+2000-08-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (clear_ip_bgp_peer_soft_out): Add soft-reconfiguration
+ outbound.
+ (peer_new): Set route-refresh flag.
+
+2000-08-16 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd.c: "no bgp router-id A.B.C.D" alias is added. "no bgp
+ cluster-id A.B.C.D" alias is added. " bgp cluster-id
+ <1-4294967295>" alias is added. "clear ip bgp * soft in" command
+ is added. "clear ip bgp A.B.C.D in" alias is added. "clear ip
+ bgp * in" alias is added.
+
+2000-08-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_update): Add soft_reconfig flag. When the flag
+ is set do not install the route into Adj-RIBs-In.
+ (bgp_update): Perform implicit withdraw before filtering of the
+ route.
+
+ * bgp_packet.c (bgp_read): draft-ietf-idr-bgp-route-refresh-01.txt
+ capability code and BGP message can be accepted.
+
+ * bgp_open.c (bgp_capability_parse): Likewise.
+
+ * bgp_route.c (bgp_refresh_table): New function for route refresh.
+ (bgp_refresh_rib): Likewise.
+
+ * bgpd.c (bgp_show_peer): Display route refresh status.
+
+ * bgp_route.c (bgp_aggregate_add): Add check for the route
+ validness.
+ (bgp_aggregate_delete): Likewise.
+
+2000-08-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_nexthop.c (bgp_scan): Care for aggregate route when the
+ route become inaccessible.
+
+2000-08-15 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_route.c (show_ip_bgp_prefix): "show ip bgp A.B.C.D/M"
+ command is added.
+
+2000-08-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_zebra.c (bgp_interface_up): Register connected route.
+ (bgp_interface_down): Unregister connected route.
+
+2000-08-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.h (struct bgp_info): Add distance to the structure.
+
+ * bgp_route.c (bgp_aggregate_increment): Aggregate route only
+ match to smaller prefixlen route not match same prefixlen route.
+ (bgp_aggregate_decrement): Likewise.
+ (bgp_aggregate_add): Likewise.
+ (bgp_aggregate_delete): Likewise.
+ (bgp_network_backdoor): Add backdoor network configuration.
+
+ * bgpd.h (struct bgp ): Add distance_{ebgp,ibgp,local} for store
+ configuration distance value.
+
+ * bgp_route.c (bgp_update): Filter EBGP route which has non
+ connected nexthop.
+
+ * bgp_attr.c (bgp_attr_aggregate_intern): New function for
+ aggregate route. Set origin to IGP. Set atomic aggregate flag.
+ Set aggregator AS and address.
+ (bgp_attr_aggregate_intern): Check BGP_CONFIG_CONFEDERATION when
+ filling aggregator_as.
+
+ * bgp_route.c (bgp_process): Delete suppress check for install
+ suppressed route into local routing table.
+ (bgp_aggregate_increment): Use bgp_attr_aggregate_intern() instead
+ of bgp_attr_default_intern ().
+ (bgp_aggregate_add): Likewise.
+
+ * bgpd.c (bgp_get): Call bgp_if_update_all() after BGP instance is
+ created. This is for avoid 0.0.0.0 router-id.
+
+2000-08-13 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_route.c (route_vty_out_detail): Display "valid" when the
+ route is valied. Display "aggregated" when the route is
+ aggregated. "Advertisements suppressed by an aggregate" is
+ displayed when the route is suppressed.
+ (bgp_info_cmp): Prefer EBGP than Confed-EBGP.
+
+2000-08-10 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_route.c (route_vty_out_detail): Display format change.
+
+2000-08-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_update): Only AFI_IP nexthop check is enabled.
+
+ * bgpd.c (bgp_delete): Delete static route before delete peer
+ configuration.
+
+2000-08-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c: Include bgpd/bgp_nexthop.h.
+
+2000-07-31 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd.c (bgp_show_summary): "show ip bgp summary" shows own BGP
+ identifier. And status is changed like below.
+
+ State/Pref -> State/PfxRcd
+ Shutdown -> Idle (Admin)
+ PrefixOvflw -> Idle (PfxCt)
+
+ * bgp_route.c (route_vty_out): Show internal route as "i".
+
+2000-07-13 Jim Bowen <jimb@zereau.net>
+
+ * bgp_snmp.c: Add BGP peer MIB implementation.
+
+2000-07-12 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd.c (bgp_show_peer): Fix typo.
+
+2000-07-11 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_routemap.c: Add commands for deleting set without argument.
+
+2000-07-03 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_zebra.c: Fix redistribute help strings.
+
+2000-07-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_show): When bgpd works as vtysh server send all
+ output to vty at once.
+
+2000-06-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_mplsvpn.c (no_vpnv4_network): "no network A.B.C.D/M rd WORD
+ tag WORD" command is added.
+
+ * bgp_ecommunity.c (ecommunity_vty_out): New function added.
+
+2000-06-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_show): Fix total number of prefix count bug.
+
+ * bgpd.c (bgp_show_peer): Display VPNv4 unicast configuration and
+ negotiation result in "show ip bgp neighbors".
+
+2000-06-12 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgpd.c: Fix help strings.
+
+ * bgpd.h: Likewise.
+
+2000-06-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_aggregate_unset): Fix bug of checking rn->info
+ instead of rn. Reported by Akihiro Mizutani <mizutani@dml.com>.
+
+ * bgp_mplsvpn.c (vpnv4_network): For testing purpose, "network
+ A.B.C.D rd RD" is added to address-family vpnv4 unicast node.
+
+ * bgp_route.c (bgp_static_set): Set safi to p.safi.
+
+2000-06-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_show_prefix_list): Change to use bgp_show().
+ (bgp_show_regexp): Change to use bgp_show().
+ (show_adj_route): Change to display header.
+
+ * bgpd.c (clear_bgp): Set peer->v_start to default value when peer
+ is cleared manually.
+
+ * bgp_route.c (bgp_show_route): New function which display
+ specific BGP route. Divided from bgp_show().
+ (bgp_static_delete): Delete all static route.
+
+2000-06-09 NOGUCHI Kay <kay@v6.access.co.jp>
+
+ * bgp_route.c (show_ipv6_bgp): "show ipv6 bgp" is broken with
+ invalid privious fix. Now show_ipv6_bgp and show_ipv6_bgp_route
+ take care of "show ipv6 bgp [X:X::X:X]". Same change for "show ip
+ mbgp" and "show ipv6 mbgp".
+
+2000-06-07 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_route.c: Fix help strings and command arguments.
+
+2000-06-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_ecommunity.c: Include prefix.h
+
+2000-06-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.h (struct bgp_info_tag): New structure to hold tag
+ value.
+
+ * bgp_route.c (bgp_adj_set): table NULL check is added.
+ (bgp_adj_unset): Likewise.
+ (bgp_adj_lookup): Likewise.
+ (bgp_adj_clear): Likewise.
+ (route_vty_out): Add SAFI check for nexthop display.
+ (bgp_withdraw): Add SAFI check for withdraw route.
+
+ * Remove all #ifdef MPLS_VPN then include it as default.
+
+ * bgpd.c: Temporary disable peer-group command until the
+ implementation is completed.
+
+ * bgp_routemap.c (bgp_route_map_init): Install
+ route_metric_match_cmd.
+ (route_match_metric_compile): MED value compile using strtoul.
+
+2000-06-05 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_filter.c: Fix help strings. Change REGEXP to LINE. Change
+ NAME to WORD.
+
+ * Change command argument to more comprehensive.
+
+ METRIC -> <0-4294967295>
+ WEIGHT -> <0-4294967295>
+ LOCAL_PREF -> <0-4294967295>
+ IP_ADDR -> A.B.C.D
+ AS -> <1-65535>
+ AS-PATH-NAME -> WORD
+ ACCESS_LIST -> WORD
+ PREFIX_LIST -> WORD
+ COMMUNITY -> AA:NN
+ EXT_COMMUNITY -> ASN:nn_or_IP-address:nn
+ IPv6_ADDR -> X:X::X:X
+
+ * bgp_clist.c: Fix help strings.
+
+2000-06-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (peer_active): Add new function for check the peer is
+ active or not.
+ (neighbor_activate): New command "neighbor PEER activate" and "no
+ neighbor PEER activate" are added.
+
+ * bgp_packet.c: Include bgpd/bgp_mplsvpn.h.
+
+2000-06-02 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_clist.c: Fix commuity-list help strings.
+
+ * bgp_routemap.c: Fix "set community" help strings. Add #define
+ SET_STR. Use (unicast|multicast) argument for "set nlri" command.
+
+2000-06-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_routemap.c (route_set_community_none_cmd): "set community
+ none" command is added to route-map.
+
+2000-06-01 Akihiro Mizutani <mizutani@dml.com>
+
+ * bgp_debug.c: Change "show debug" to "show debugging". Now "show
+ debugging" is not used in VIEW_NODE.
+
+2000-05-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_fsm.c (bgp_timer_set): Add check for shutdown flag. This
+ fix unconditional BGP connection.
+
+ * bgpd.c (peer_shutdown): Replace peer_shutdown() with
+ peer_change_flag_with_reset().
+
+2000-05-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (no_bgp_default_ipv4_unicast): Add "no bgp default
+ ipv4-unicast" command.
+
+ * bgpd.h (BGP_CONFIG_NO_DEFAULT_IPV4): Add new definition.
+
+ * bgp_filter.c (as_list_delete): Free all AS filter.
+
+ * bgp_clist.c (community_list_delete): Free all community entry.
+
+ * bgp_filter.c (no_ip_as_path_all): New DEFUN for "no ip as-path
+ access-list NAME".
+
+ * bgp_clist.c (no_ip_community_list_all): New DEFUN for "no ip
+ community-list NAME".
+
+2000-05-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (ipv6_mbgp_neighbor_routes): Change "show ip bgp PEER
+ routes" to "show ip bgp PEER received-routes"
+
+2000-05-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_ecommunity.c (ecommunity_parse): New file for Extended
+ Communities attribute.
+ * bgp_ecommunity.h: Likewise.
+
+2000-05-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_mplsvpn.h: New file for MPLS-VPN.
+ * bgp_mplsvpn.c: Likewise.
+
+ * bgpd.c (bgp_delete): Fix bug of "no router bgp" crush.
+
+2000-05-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (bgp_bestpath_missing_as_worst): Add "bgp bestpath
+ missing-as-worst".
+
+2000-05-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_routemap.c (match_community): Clarify help of "match
+ community".
+
+2000-05-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_aspath.c (aspath_cmp_left): Remove debug code.
+
+2000-04-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_info_cmp): Compare MED only both routes comes
+ from same neighboring AS.
+
+ * bgp_aspath.c (aspath_cmp_left): Compare leftmost AS value.
+
+ * bgp_route.c (bgp_info_cmp): Fix misused htonl() to ntohl().
+
+2000-04-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_output_filter): When distribute-list's
+ corresponding access-list does not exist, filter all routes.
+ (bgp_input_filter): Likewise.
+
+2000-04-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_attr.c (bgp_packet_attribute): Propagate MED to IBGP peer.
+
+ * bgp_route.c (bgp_info_cmp): Add evaluation of local preference.
+
+2000-04-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (bgp_distribute_update): Add struct access_list *
+ argument.
+
+2000-04-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_clist.c (community_list_dup_check): Add duplicate insertion
+ check.
+
+ * bgp_filter.c (as_list_dup_check): Add duplicate insertion check.
+
+ * bgp_route.c (bgp_show): Fix undeclared write variable.
+
+2000-04-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_routemap.c: Add "match ip address prefix-list".
+
+2000-03-29 Rick Payne <rickp@rossfell.co.uk>
+
+ * bgp_aspath.c (aspath_strip_confed): Fix realloc problem.
+
+2000-03-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_fsm.c (bgp_reconnect): Connect retry timer is expired when
+ the peer status is Connect.
+
+2000-03-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Fix bug of rewritten originator-id.
+
+2000-01-27 Rick Payne <rickp@rossfell.co.uk>
+
+ * bgp_aspath.c (aspath_delimiter_char): New function. Instead of
+ directly referencing array, search proper AS path delimiter.
+ (aspath_strip_confed): Strip the confederation stuff from the
+ front of an AS path.
+ (aspath_add_left_confed): New function for adding specified AS to
+ the leftmost AS_CONFED_SEQUENCE.
+
+ * bgp_aspath.h: Change AS_CONFED_SEQUENCE and AS_CONFED_SET value
+ to Cisco compatible.
+
+ * bgpd.c (bgp_confederation_id_set): Confederation configuration.
+ (bgp_confederation_id_unset): Likewise.
+ (bgp_confederation_peers_check): Likewise.
+ (bgp_confederation_peers_add): Likewise.
+ (bgp_confederation_peers_remove): Likewise.
+ (bgp_confederation_peers_set): Likewise.
+ (bgp_confederation_peers_unset): Likewise.
+ (bgp_confederation_peers_print): Likewise.
+
+2000-01-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c: Introduce peer_change_flag_with_reset() fucntion.
+
+2000-01-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_open.c (bgp_open_option_parse): When there is no common
+ capability send Unsupported Capability error to the peer.
+
+2000-01-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_open.c (bgp_capability_mp): Fix bug of mis-negotiation about
+ IPv6 unicast.
+
+ * bgpd.c (bgp_init): Add "soft-reconfiguration inbound" command.
+
+2000-01-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (neighbor_strict_capability): Add
+ "strict-capability-match" command.
+
+ * bgp_zebra.c (bgp_if_update): Ignore NET127 determining
+ router-id.
+
+ * bgpd.c (peer_override_capability): Add "override-capability"
+ command.
+
+1999-12-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_packet.c (bgp_write): Change status to Idle and set timer
+ after write failed.
+
+1999-12-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_zebra.c (bgp_zebra_announce): Add info->selected check.
+
+1999-12-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (nlri_unfeasible): nlri_unfeasible() is merged with
+ nlri_parse().
+
+1999-12-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_fsm.h (BGP_EVENT_DELETE): Macro added.
+
+ * bgp_fsm.c (bgp_stop): Clear all event threads of the peer when
+ the peer is cleared.
+
+ * bgp_zebra.c (bgp_nexthop_set): Clear interface index of
+ link-local address. This is KAME specific problem.
+
+1999-12-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_attr.c (bgp_mp_reach_parse): Comment out previous code for a
+ while. We don't completely detect the link is shared or not at
+ this moment.
+
+ * bgp_packet.c (bgp_notify_send): Make shortcut call of
+ bgp_write() and bgp_stop().
+
+ * bgp_attr.c (bgp_mp_reach_parse): Fix serious bug when getting
+ global and link-local address.
+
+1999-12-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (no_neighbor_port): New command added.
+ (peer_new): Set send_community.
+
+1999-12-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (show_ip_bgp_summary): Changed to use bgp_show_summary().
+ (show_ip_mbgp_summary): Likewise.
+ (show_ipv6_bgp_summary): Likewise.
+ (show_ipv6_mbgp_summary): Add new command.
+ (peer_free): Free peer->host.
+ (peer_lookup_by_su): Delete function.
+ (ipv6_bgp_neighbor): Changed to use peer_remote_as().
+ (sockunion_vty_out): Function deleted.
+ (vty_clear_bgp): Use afi instead of family.
+ Delete old list bgp_list. Use struct newlist *bgplist.
+ (peer_lookup_by_host): Function deleted.
+
+1999-12-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.h (struct peer_group): New structure added.
+ (struct peer_conf): New structure added.
+ (struct peer): Change all prefix_count to unsigned long.
+
+ * bgpd.c: Reconstruct all of VTY commands reflect internal
+ structure change.
+ Use bgplist instead of bgp_list.
+ Use peerlist intstead of peer_list.
+
+ * bgp_attr.c (bgp_mp_reach_parse): If nlri_parse return -1, stop
+ parsing then return immediately.
+
+ * bgp_route.c (nlri_parse): When NLRI parse error occured, return
+ -1.
+ (nlri_process): Use pcount_v4_{unicast,multicast}.
+ (nlri_delete): Likewise.
+
+1999-11-25 Robert Olsson <Robert.Olsson@data.slu.se>
+
+ * bgp_routemap.c (route_match_nlri): `match nlri
+ unicast|multicast' and `set nlri unicast|multicast' command are
+ added.
+
+1999-11-22 Robert Olsson <Robert.Olsson@data.slu.se>
+
+ * bgpd.c: Add translate-update support.
+
+ * bgpd.h (TRANSLATE_UPDATE_OFF): Add translate-update definition.
+
+1999-11-19 Robert.Olsson@data.slu.se
+
+ * bgp_route.c (bgp_peer_delete): Add MBGP peer clear codes.
+
+1999-11-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_open.c (bgp_capability_mp): Temporary comment out
+ SAFI_UNICAST_MULTICAST handling until we know the meanings.
+
+1999-11-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_btoa.c: New file added.
+
+1999-11-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.h (struct peer): Add dont_capability flag.
+ (struct peer): Add override_capability flag.
+
+ * bgpd.c (neighbor_dont_capability_negotiation): `neighbor PEER
+ dont-capability-negotiation' added.
+
+1999-11-12 Bill Sommerfeld <sommerfeld@orchard.arlington.ma.us>
+
+ * bgp_attr.c (bgp_mp_reach_parse): Ignore link-local addresses
+ attribute from non-shared-network peers.
+
+1999-11-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_snmp.c: New file added.
+
+ * BGP4-MIB.txt: Updated to the latest Internet-Draft
+ draft-ietf-idr-bgp4-mib-04.txt.
+
+1999-11-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_route_init): Add `show ipv6 bgp prefix-list'.
+
+ * bgp_attr.c (bgp_mp_unreach_parse): Enclose safi setup with
+ #ifdef HAVE_MBGPV4.
+
+1999-11-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_dump.c (no_dump_bgp_all): Add [PATH] and [INTERVAL] to no
+ dump bgp commands.
+ (config_write_bgp_dump): Write interval value to the
+ configuration.
+
+1999-11-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_zebra.c: Redistribute route-map support is added.
+
+ * bgp_zebra.h: New file added.
+
+1999-11-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_dump.c: BGP packet dump routine compatible with MRT.
+ * bgp_dump.h: BGP packet dump routine compatible with MRT.
+
+ * bgp_debug.c: Renamed from bgp_dump.c
+ * bgp_debug.h: Renamed from bgp_dump.h
+
+1999-10-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * BGP4-MIB.txt: New file added. Edited version of RFC1657.
+
+1999-10-25 Bill Sommerfeld <sommerfeld@orchard.arlington.ma.us>
+
+ * bgp_route.c (bgp_announce): If we're not on a shared network
+ with the peer and we don't have a link-local next hop, but the
+ inbound next-hop has a link-local address, don't readvertise it to
+ our peer.
+
+1999-10-25 Marc Boucher <marc@mbsi.ca>
+
+ * bgp_zebra.c: Add redistribute kernel command.
+
+1999-10-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_reset): New function added.
+
+ * bgpd.conf.sample2: Add IPv6 configuration sample.
+
+1999-10-24 Bill Sommerfeld <sommerfeld@orchard.arlington.ma.us>
+
+ * bgp_route.c (ipv6_aggregate_address): Function added.
+
+1999-10-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_packet.c (bgp_update): Unintern aspath, community, cluster
+ list after parsing BGP update packet.
+
+ * bgp_attr.c (bgp_attr_aspath): Intern parsed aspath.
+ (bgp_attr_community): Intern parsed community.
+ (bgp_attr_cluster_list): Intern parsed cluster list.
+
+ * bgp_routemap.c: Add `set community-additive' command.
+
+1999-10-21 Alexandr D. Kanevskiy <kad@blackcatlinux.com>
+
+ * bgp_routemap.c (route_set_local_pref): Fix bug of setting
+ attribute flag.
+
+1999-10-21 Bill Sommerfeld <sommerfeld@orchard.arlington.ma.us>
+
+ * bgp_route.c (bgp_announce): Add check of IPv6 default route
+ announcement.
+
+ * bgp_packet.c (bgp_update_send): Add BGP announcement logging.
+
+1999-10-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * `show ip[v6] bgp PREFIX' show uptime of the route.
+
+1999-10-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (bgp_filter_set): Delete PEER_FAMILY_{IPV4,IPV6}. instead
+ of that use AF_INET and AF_INET6 directly.
+ (vty_clear_bgp): Add new function to support various clear ip bgp
+ method.
+
+1999-10-04 Lars Fenneberg <lf@elemental.net>
+
+ * bgpd.c (clear_ip_bgp): Add `clear ip bgp ASN'.
+
+1999-10-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_routemap.c: Add `match ip prefix-list' and `match ipv6
+ prefix-list'.
+
+1999-09-28 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (bgp_collision_detect): Add BGP collision detection
+ function.
+
+1999-09-26 Blake Meike <bmeike@adero.com>
+
+ * bgpd.c (neighbor_port): New command `neighbor PEER port PORT' is
+ added.
+
+1999-08-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (no_neighbor_timers_keepalive): Change MIN to min. Add
+ min() macro.
+
+1999-08-19 Rick Payne <rickp@rossfell.co.uk>
+
+ * bgp_packet.c (bgp_open): BGP holdtimer bug is fixed. Make BGP
+ keepalive timer configurable.
+
+1999-08-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_zebra.c (bgp_redistribute_set): Fix redistribute bug.
+
+1999-08-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (bgp_peer_display): show ip bgp neighbors PEER only list
+ the peer not all of them.
+
+1999-08-11 Rick Payne <rickp@rossfell.co.uk>
+
+ * bgp_route.c (bgp_announce): Remove MED if its an EBGP peer -
+ will get overwritten by route-maps.
+
+1999-08-08 Rick Payne <rickp@rossfell.co.uk>
+
+ * bgp_routemap.c: Multi protocol route-map modification.
+
+1999-08-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c: Set network statement route's origin attribute as
+ igp.
+
+ * bgp_zebra.c: Set redistribute route's origin attribute as
+ incomplete.
+
+ * bgp_route.c (bgp_info_cmp): Add attribute existance check,
+ origin attribute check, BGP peer type check.
+
+1999-07-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_peer_delete): Reselect of IPv6 route.
+
+1999-07-29 Rick Payne <rickp@rossfell.co.uk>
+
+ * Changed route-maps to behave in a more cisco-like fashion
+
+1999-07-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_fsm.c (bgp_stop): Very serious bug of bgp_stop () is fixed.
+ When multiple route to the same destination exist, bgpd try to
+ announce the information to stopped peer. Then add orphan write
+ thread is added. This cause many strange behavior of bgpd.
+ Reported by Georg Hitsch <georg@atnet.at>.
+
+1999-07-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c: Change peer's A.B.C.D to PEER.
+
+1999-07-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_announce): Add hack for link-local nexthop.
+
+ * bgp_zebra.c (bgp_zebra_announce): Fill in nexthop address from
+ local address.
+
+1999-07-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_packet.c (bgp_open): Holdtime fetch bug is fixed. Reported
+ by Yuji SEKIYA <sekiya@sfc.wide.ad.jp>.
+
+1999-07-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_fsm.c (fsm_holdtime): Don't close file descriptor in
+ fsm_holdtime ().
+
+1999-07-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_routemap.c: Add `set atomic-aggregate' command.
+
+1999-07-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_routemap.c (route_set_ip_nexthop_cmd): Change "ip nexthop"
+ to "ip next-hop".
+
+1999-07-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (show_ipv6_bgp_regexp): `show ipv6 bgp regexp'
+ added.
+
+1999-07-01 Rick Payne <rickp@rossfell.co.uk>
+
+ * bgp_zebra.c (zebra_init): Install standard commands to
+ ZEBRA_NODE.
+
+1999-06-28 Rick Payne <rickp@rossfell.co.uk>
+
+ * bgpd.c (bgp_delete): bgp peer deletion bug is fixed.
+
+1999-06-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c: Add neighbor update-source command as ALIAS to
+ neighbor_interface.
+
+1999-06-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_attr.c (bgp_packet_attribute): Send community attribute when
+ send_community flag is set.
+
+ * bgpd.h (struct peer): Add send_community flag.
+
+1999-06-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (router_bgp): router bgp's argument changed from AS_NO to
+ <1-65535>.
+
+1999-06-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.h (struct bgp_info): Add subtype for BGP route type.
+
+1999-06-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_community.c (community_merge): Function added.
+
+1999-06-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_clist.c: New file.
+ * bgp_clist.h: New file.
+
+ * bgp_community.h (COMMUNITY_LOCAL_AS): Added for Cisco
+ compatibility.
+ (COMMUNITY_NO_ADVERTISE): Fix typo.
+
+1999-05-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_routemap.c: Add `set weight WEIGHT' command.
+
+ * bgpd.c: Remove all_digit_check function. Instead of that use
+ all_digit function in lib/prefix.c.
+
+ * bgp_routemap.c (bgp_route_map_init): Install
+ no_set_ipv6_nexthop_global_cmd and no_set_ipv6_nexthop_local_cmd
+ element to the RMAP_NODE.
+
+1999-05-28 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_aspath.c (aspath_make_str): Declare aspath_delimiter_char
+ inside aspath_make_str function.
+ (aspath_prepend): New function is added for AS path prepend.
+ (aspath_make_str_count): Renamed from aspath_make_str. AS path
+ count is set to the structure.
+ (aspath_merge): New function.
+
+1999-05-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_zebra.c (redistribute_bgp): Add new DEFUN.
+ (no_redistribute_bgp): Likewise.
+ (router_zebra): Semantics changed. Now 'router zebra' is default
+ behavior of bgpd.
+
+1999-05-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_routemap.c: Add some commands to bgp route-map.
+ match ip next-hop: New command.
+ match metric: New command.
+ set metric: Doc fix.
+ set local-preference: Add DEFUN.
+
+1999-05-14 Stephen R. van den Berg <srb@cuci.nl>
+
+ * bgp_main.c (signal_init): SIGTERM call sigint.
+ (sigint): Loggging more better message.
+
+1999-05-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_attr.c (bgp_packet_attribute): AS path attribute extended
+ length bit check is added.
+
+1999-05-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_routemap.c (bgp_route_map_init): Call route_map_install_set
+ function with route_set_local_pref_cmd argument.
+ (no_match_aspath): Function added.
+ (route_set_metric): Set attribute flag bit.
+
+ * bgp_attr.c (bgp_packet_attribute): MULTI_EXIT_DISC is now in BGP
+ packet.
+
+1999-05-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (no_neighbor_timers_holdtime): `no neighbor PEER timers
+ holdtime' command is added.
+
+ * bgpd.h (BGP_DEFAULT_HOLDTIME_BIG): Delete define.
+
+ * bgpd.c (bgp_prefix_list_set): New function added.
+ (bgp_prefix_list_unset): Likewise.
+ (bgp_prefix_list_update): Likewise.
+ (show_ip_bgp_neighbors): prefix-list information display.
+
+1999-05-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (bgp_delete): Function added for `no router bgp'.
+
+1999-05-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_dump.c (bgp_dump_attr): Add originator_id display.
+
+ * bgpd.c (bgp_router_id): Even when address is malformed set the
+ value to configuration bug fixed.
+ (no_bgp_router_id): New function.
+ (no_bgp_cluster_id): New function.
+
+1999-05-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.h (BGP_ATTR_ORIGINATOR_ID): Changed from BGP_ATTR_ORIGINATOR.
+
+1999-05-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (bgp_announce): Add route reflector check.
+
+1999-05-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (bgp_cluster_id): Add function for route reflector.
+ (neighbor_route_reflector_client): Likewise.
+ (no_neighbor_route_reflector_client): Likewise.
+
+ * bgpd.h (struct bgp ): Add cluster for route reflector.
+
+ * bgp_route.c (show_ip_bgp_prefix_list): New command is added.
+
+1999-04-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am (noinst_HEADERS): Add bgp_filter.h
+
+ * bgp_aspath.c (aspath_undup): Function deleted. aspath_free ()
+ has same functionality.
+
+ * bgp_filter.h: New file.
+
+ * bgp_aspath.c (aspath_unintern): Rename aspath_free () to
+ aspath_unintern ()
+ (aspath_free): New function.
+
+1999-04-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_aspath.c (aspath_aggregate): Function added.
+
+ * bgp_aspath.h (aspath_aggregate): Prototype added.
+
+ * bgp_aspath.c (aspath_empty_aspath): New argument
+ gated_dont_eat_flag is added.
+
+1999-04-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c: Add bgp_aggregate_ipv4 and bgp_aggregate_ipv6.
+
+1999-04-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c (aggregate_address): Function added.
+
+ * bgp_zebra.c (zebra_read): Change log to zlog.
+
+1999-04-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am (noninst_HEADERS): Added for make dist.
+
+1999-04-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * aspath_regex.c: Removed from distribution.
+
+1999-04-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_attr.c (bgp_packet_attribute): Old draft-00 packet treatment
+ bug fixed.
+
+1999-04-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_aspath.c (aspath_add_left): Fix empty aspath bug. Reported
+ by kad@gibson.skif.net.
+
+ * bgp_regex.[ch]: New file added.
+
+
+1999-04-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_filter.c: New file added.
+
+1999-04-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_aspath.c (aspath_empty_aspath): Change for peering with
+ gated.
+
+1999-03-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_main.c (main): Default loggin method changed from syslog to
+ stdout.
+
+1999-03-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c: Delete obsolete default attribute DEFUN.
+
+1999-03-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_attr.c: Make attribute structure put into attribute hash.
+
+1999-03-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_view.c : Delete file.
+
+1999-02-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_routemap.c (bgp_apply_route_map): Add prefix argument.
+
+ * bgp_route.h (struct bgp_info): Add bgp_info structre. I'll
+ replace bgp_route with this.
+
+ * bgp_routemap.c (route_match_ip_address): Fix bug of passing non
+ prefix value to access_list_apply().
+
+ * bgpd.conf.sample: Add route-map sample.
+ Delete obsolete default-attr statements.
+
+ * bgp_packet.c: Use stream_fifo for packet queueing.
+
+1999-02-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_aspath.c (aspath_add_left): add non empty aspath treatment.
+
+ * bgp_main.c: include unistd.h for daemon().
+
+ * bgp_route.c (nlri_process): add IPv6 table lookup.
+
+ * bgp_attr.c (route_parse_ipv6): call nlri_process().
+ (attr_make): Obsolete function attr_make deleted.
+
+1999-02-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_aspath.c (aspath_add_left): change function name from
+ aspath_add_leftmost_as().
+
+1999-02-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_aspath.c: add aspath_add_leftmost_as ().
+
+1999-02-18 Peter Galbavy <Peter.Galbavy@knowledge.com>
+
+ * syslog support added
+
+1999-01-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c: DEFUN (neighbor_nexthop): deleted.
+ DEFUN (neighbor_distribute_list): added.
+
+1999-01-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.h (struct peer ): header_buf and read_buf is removed.
+
+ * bgp_peer.[ch]: Deleted. Peer related functions are merged to
+ bgpd.c
+
+ * bgp_network.c: New file.
+ * bgp_network.h: New file.
+
+ * bgp_packet.h: New file.
+
+1999-01-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_packet.c (bgp_keepalive_send): Now BGP keepalive packet is
+ buffered.
+
+1999-01-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_packet.c: New file.
+
+1998-12-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_zebra.c (zebra_client): Use zebra_connect() in lib/client.c.
+
+ * `show ip bgp' bug fixed.
+ * aspath_log (): Remove argument logfp.
+
+1998-12-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_fsm.h: New file.
+
+1998-12-15 Magnus Ahltorp <map@stacken.kth.se>
+
+ * bgp_attr.c, bgp_community.h, bgp_dump.c, bgp_fsm.c, bgp_open.c
+ bgp_peer.c, bgp_peer.h, bgp_route.c, bgp_route.h, bgp_view.c
+ bgpd.c, bgpd.h, bgp_attr.c, bgp_community.h, bgp_dump.c,
+ bgp_fsm.c, bgp_open.c, bgp_peer.c, bgp_peer.h: Prototype fixes.
+
+1998-12-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (bgp_config_write): Delete vector v argument.
+
+1998-12-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.h: Delete annoying ld_[124]byte and st_[124]byte macros.
+
+1998-11-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_radix.[ch]: removed.
+
+1998-09-15 HEO SeonMeyong <seirios@matrix.iri.co.jp>
+
+ * bgp_main.c: ifdef HYDRANGEA -> ifdef KAME
+
+1998-08-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_dump.c: delete nroute().
+
+1998-05-19 Yamshita TAKAO <jargon@lares.dti.ne.jp>
+
+ * bgp_aspath.c: HAVE_CONFIG_H typo :-)
+ * bgpd.h: Modify for compile on Solaris.
+ * bgp_aspath.h: likewize
+ * bgp_community.h: likewize
+ * bgp_routemap.c: likewize
+
+1998-05-18 Yamshita TAKAO <jargon@lares.dti.ne.jp>
+
+ * bgpd.h: Modify for compile on Solaris.
+ * bgp_aspath.h: likewize
+
+1998-05-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * routemap.[ch]: move to ../lib directory.
+
+1998-05-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * routemap.c (route_map_apply): add function.
+
+1998-05-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * routemap.h: add file.
+
+ * bgp_peer.h (enum ): change PEER_{IBGP,EBGP} to BGP_PEER_{IBGP,EBGP}
+
+1998-05-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am: sysconfdir_DATA added.
+
+1998-05-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_dump.c: add `debug bgp fsm'
+ add `no debug bgp fsm'
+ add `show debug bgp'
+ * bgp_open.c: File added.
+
+1998-05-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * .cvsignore: File added.
+
+1998-04-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_community.[ch]: File added.
+
+1998-03-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd now use lib/thread.[ch].
+
+1998-01-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.c (show_ip_bgp_neighbors): add 'show ip bgp neighbors' command.
+
+ * bgpd.h (BGP_DEFAULT_START_TIMER): change from 1 to 30.
+
+1997-12-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_vty.c: bgp_vty.c deleted.
+
+ * bgpd.c (config_write_neighbor): add ebgp-multihop command.
+
+1997-12-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_fsm.c: [-p bgp_port] and [-P vty_port] works
+
+1997-12-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_vty.c: new file.
+
+ * bgp_attr.c: add new logging system.
+
+1997-11-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Change all inet_addr call into inet_aton.
+
+1997-11-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_radix.c: change radix_peer_delete
+
+1997-10-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_aspath.c: move AS_TOKEN_??? definition from header to c source.
+
+1997-09-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_dump.c (bgp_log_route): add dump_attr function
+
+1997-09-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_aspath.c (aspath_test): change AS_SET brace from '[' to '{'
+ * bgp_dump.c (bgp_log_route): change logfile format.
+
+1997-08-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_open.c (bgp_open): move bgp_open function from bgpd.c
+ * bgp_attr.c (community_str2com): add community value generation
+ * bgp_attr.h: add SAFI definition for BGP-4+
+
+1997-08-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgpd.h: add BGP_OPEN_OPT_CAP for Capabilities Optional Parameter
+ * Makefile.in: add bgp_open.o, delete bgp_loop.o
+ * bgp_open.c: newfile which manages BGP Open message
+ * bgp_loop.c: this file is merged with bgp_fsm.c
+ * bgp_radix.c (radix_add): radix_add() now return route_t instead
+ of int
+ (bgp_sim): now we can read update & withdraw from file
+ * bgp_route.c: add route_free() call into route_parse etc.
+
+1997-08-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_radix.c: Radix code is completely rewritten. It has better
+ memory treatment than old one.
+
+1997-08-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_route.c: route_alloc for route struct allocation statistics.
+ * bgpd.c (bgp_make_update): now we cann announce MED attribute.
+ * bgp_aspath.c (aspath_print_all): change aspath_print_all output
+ format.
+
+1997-08-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_term.c (term_parse): add command : show asstat, show ashash
+ * bgp_aspath.c: aspath_cmp bug fix
+ (aspath_print_all): add aspath_print_all ();
+ * bgp_peer.h: delete rlist element from struct peer.
+
+1997-08-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_aspath.c: completely rewritten.
+ * bgp_aspath.h: completely rewritten.
+ add AsPath, AsSegment structure
+ add AS_SET treatment
+ change Hash codes
+
+1997-08-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_attr.h: add Attribute flags defines
+ * bgp_route.c: delete rlist related functions
+ * bgp_aspath.c (as_origin): add as_origin function
+ (aspath_print): move from bgp_dump.c and add support of AS_SET
+ change Hash related function names.
+
+1997-08-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_aspath.h: add next entry, delete rlist entry from struct aspath
+
+1997-08-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * bgp_aspath.c (as_sort): add function as_sort
+ * bgp_aspath.h: add IBGP, EBGP
+
diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am
new file mode 100644
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 <zebra.h>
+
+#include "command.h"
+#include "memory.h"
+#include "prefix.h"
+#include "hash.h"
+#include "thread.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_advertise.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_mplsvpn.h"
+
+/* 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 <zebra.h>
+
+#include "hash.h"
+#include "memory.h"
+#include "vector.h"
+#include "vty.h"
+#include "str.h"
+#include "log.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_aspath.h"
+
+/* 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 <zebra.h>
+
+#include "linklist.h"
+#include "prefix.h"
+#include "memory.h"
+#include "vector.h"
+#include "vty.h"
+#include "stream.h"
+#include "log.h"
+#include "hash.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_ecommunity.h"
+
+/* 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 <zebra.h>
+
+#include "zebra.h"
+#include "stream.h"
+#include "log.h"
+#include "prefix.h"
+#include "command.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_dump.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_aspath.h"
+
+enum MRT_MSG_TYPES {
+ MSG_NULL,
+ MSG_START, /* sender is starting up */
+ MSG_DIE, /* receiver should shut down */
+ MSG_I_AM_DEAD, /* sender is shutting down */
+ MSG_PEER_DOWN, /* sender's peer is down */
+ MSG_PROTOCOL_BGP, /* msg is a BGP packet */
+ MSG_PROTOCOL_RIP, /* msg is a RIP packet */
+ MSG_PROTOCOL_IDRP, /* msg is an IDRP packet */
+ MSG_PROTOCOL_RIPNG, /* msg is a RIPNG packet */
+ MSG_PROTOCOL_BGP4PLUS, /* msg is a BGP4+ packet */
+ MSG_PROTOCOL_BGP4PLUS_01, /* msg is a BGP4+ (draft 01) packet */
+ MSG_PROTOCOL_OSPF, /* msg is an OSPF packet */
+ MSG_TABLE_DUMP /* routing table dump */
+};
+
+int
+attr_parse (struct stream *s, u_int16_t len)
+{
+ u_int flag;
+ u_int type;
+ u_int16_t length;
+ u_int16_t lim;
+
+ lim = s->getp + len;
+
+ printf ("attr_parse s->getp %d, len %d, lim %d\n", s->getp, len, lim);
+
+ while (s->getp < lim)
+ {
+ flag = stream_getc (s);
+ type = stream_getc (s);
+
+ if (flag & ATTR_FLAG_EXTLEN)
+ length = stream_getw (s);
+ else
+ length = stream_getc (s);
+
+ printf ("FLAG: %d\n", flag);
+ printf ("TYPE: %d\n", type);
+ printf ("Len: %d\n", length);
+
+ switch (type)
+ {
+ case BGP_ATTR_ORIGIN:
+ {
+ u_char origin;
+ origin = stream_getc (s);
+ printf ("ORIGIN: %d\n", origin);
+ }
+ break;
+ case BGP_ATTR_AS_PATH:
+ {
+ struct aspath aspath;
+
+ aspath.data = (s->data + s->getp);
+ aspath.length = length;
+ aspath.str = aspath_make_str_count (&aspath);
+ printf ("ASPATH: %s\n", aspath.str);
+ free (aspath.str);
+
+ stream_forward (s, length);
+ }
+ break;
+ case BGP_ATTR_NEXT_HOP:
+ {
+ struct in_addr nexthop;
+ nexthop.s_addr = stream_get_ipv4 (s);
+ printf ("NEXTHOP: %s\n", inet_ntoa (nexthop));
+ /* stream_forward (s, length); */
+ }
+ break;
+ default:
+ stream_forward (s, length);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ int ret;
+ FILE *fp;
+ struct stream *s;
+ time_t now;
+ int type;
+ int subtype;
+ int len;
+ int source_as;
+ int dest_as;
+ int ifindex;
+ int family;
+ struct in_addr sip;
+ struct in_addr dip;
+ u_int16_t viewno, seq_num;
+ struct prefix_ipv4 p;
+
+ s = stream_new (10000);
+
+ if (argc != 2)
+ {
+ fprintf (stderr, "Usage: %s FILENAME\n", argv[0]);
+ exit (1);
+ }
+ fp = fopen (argv[1], "r");
+ if (!fp)
+ {
+ perror ("fopen");
+ exit (1);
+ }
+
+ while (1)
+ {
+ stream_reset (s);
+
+ ret = fread (s->data, 12, 1, fp);
+ if (feof (fp))
+ {
+ printf ("END OF FILE\n");
+ break;
+ }
+ if (ferror (fp))
+ {
+ printf ("ERROR OF FREAD\n");
+ break;
+ }
+
+ /* Extract header. */
+ now = stream_getl (s);
+ type = stream_getw (s);
+ subtype = stream_getw (s);
+ len = stream_getl (s);
+
+ printf ("TIME: %s", ctime (&now));
+
+ /* printf ("TYPE: %d/%d\n", type, subtype); */
+
+ if (type == MSG_PROTOCOL_BGP4MP)
+ printf ("TYPE: BGP4MP");
+ else if (type == MSG_TABLE_DUMP)
+ printf ("TYPE: MSG_TABLE_DUMP");
+ else
+ printf ("TYPE: Unknown %d", type);
+
+ if (type == MSG_TABLE_DUMP)
+ switch (subtype)
+ {
+ case AFI_IP:
+ printf ("/AFI_IP\n");
+ break;
+ case AFI_IP6:
+ printf ("/AFI_IP6\n");
+ break;
+ default:
+ printf ("/UNKNOWN %d", subtype);
+ break;
+ }
+ else
+ {
+ switch (subtype)
+ {
+ case BGP4MP_STATE_CHANGE:
+ printf ("/CHANGE\n");
+ break;
+ case BGP4MP_MESSAGE:
+ printf ("/MESSAGE\n");
+ break;
+ case BGP4MP_ENTRY:
+ printf ("/ENTRY\n");
+ break;
+ case BGP4MP_SNAPSHOT:
+ printf ("/SNAPSHOT\n");
+ break;
+ default:
+ printf ("/UNKNOWN %d", subtype);
+ break;
+ }
+ }
+
+ printf ("len: %d\n", len);
+
+ ret = fread (s->data + 12, len, 1, fp);
+ if (feof (fp))
+ {
+ printf ("ENDOF FILE 2\n");
+ break;
+ }
+ if (ferror (fp))
+ {
+ printf ("ERROR OF FREAD 2\n");
+ break;
+ }
+
+ /* printf ("now read %d\n", len); */
+
+ if (type == MSG_TABLE_DUMP)
+ {
+ u_char status;
+ time_t originated;
+ struct in_addr peer;
+ u_int16_t attrlen;
+
+ viewno = stream_getw (s);
+ seq_num = stream_getw (s);
+ printf ("VIEW: %d\n", viewno);
+ printf ("SEQUENCE: %d\n", seq_num);
+
+ /* start */
+ while (s->getp < len - 16)
+ {
+ p.prefix.s_addr = stream_get_ipv4 (s);
+ p.prefixlen = stream_getc (s);
+ printf ("PREFIX: %s/%d\n", inet_ntoa (p.prefix), p.prefixlen);
+
+ status = stream_getc (s);
+ originated = stream_getl (s);
+ peer.s_addr = stream_get_ipv4 (s);
+ source_as = stream_getw(s);
+
+ printf ("FROM: %s AS%d\n", inet_ntoa (peer), source_as);
+ printf ("ORIGINATED: %s", ctime (&originated));
+
+ attrlen = stream_getw (s);
+ printf ("ATTRLEN: %d\n", attrlen);
+
+ attr_parse (s, attrlen);
+
+ printf ("STATUS: 0x%x\n", status);
+ }
+ }
+ else
+ {
+ source_as = stream_getw (s);
+ dest_as = stream_getw (s);
+ printf ("source_as: %d\n", source_as);
+ printf ("dest_as: %d\n", dest_as);
+
+ ifindex = stream_getw (s);
+ family = stream_getw (s);
+
+ printf ("ifindex: %d\n", ifindex);
+ printf ("family: %d\n", family);
+
+ sip.s_addr = stream_get_ipv4 (s);
+ dip.s_addr = stream_get_ipv4 (s);
+
+ printf ("saddr: %s\n", inet_ntoa (sip));
+ printf ("daddr: %s\n", inet_ntoa (dip));
+
+ printf ("\n");
+ }
+ }
+ fclose (fp);
+ return 0;
+}
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
new file mode 100644
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 <zebra.h>
+
+#include "command.h"
+#include "prefix.h"
+#include "memory.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_regex.h"
+#include "bgpd/bgp_clist.h"
+
+/* 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 <zebra.h>
+
+#include "hash.h"
+#include "memory.h"
+
+#include "bgpd/bgp_community.h"
+
+/* Hash of community attribute. */
+struct hash *comhash;
+
+/* Allocate a new communities value. */
+struct community *
+community_new ()
+{
+ return (struct community *) XCALLOC (MTYPE_COMMUNITY,
+ sizeof (struct community));
+}
+
+/* Free communities value. */
+void
+community_free (struct community *com)
+{
+ if (com->val)
+ XFREE (MTYPE_COMMUNITY_VAL, com->val);
+ if (com->str)
+ XFREE (MTYPE_COMMUNITY_STR, com->str);
+ XFREE (MTYPE_COMMUNITY, com);
+}
+
+/* Add one community value to the community. */
+void
+community_add_val (struct community *com, u_int32_t val)
+{
+ com->size++;
+ if (com->val)
+ com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val, com_length (com));
+ else
+ com->val = XMALLOC (MTYPE_COMMUNITY_VAL, com_length (com));
+
+ val = htonl (val);
+ memcpy (com_lastval (com), &val, sizeof (u_int32_t));
+}
+
+/* Delete one community. */
+void
+community_del_val (struct community *com, u_int32_t *val)
+{
+ int i = 0;
+ int c = 0;
+
+ if (! com->val)
+ return;
+
+ while (i < com->size)
+ {
+ if (memcmp (com->val + i, val, sizeof (u_int32_t)) == 0)
+ {
+ c = com->size -i -1;
+
+ if (c > 0)
+ memcpy (com->val + i, com->val + (i + 1), c * sizeof (val));
+
+ com->size--;
+
+ if (com->size > 0)
+ com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val,
+ com_length (com));
+ else
+ {
+ XFREE (MTYPE_COMMUNITY_VAL, com->val);
+ com->val = NULL;
+ }
+ return;
+ }
+ i++;
+ }
+}
+
+/* Delete all communities listed in com2 from com1 */
+struct community *
+community_delete (struct community *com1, struct community *com2)
+{
+ int i = 0;
+
+ while(i < com2->size)
+ {
+ community_del_val (com1, com2->val + i);
+ i++;
+ }
+
+ return com1;
+}
+
+/* Callback function from qsort(). */
+int
+community_compare (const void *a1, const void *a2)
+{
+ u_int32_t v1;
+ u_int32_t v2;
+
+ memcpy (&v1, a1, sizeof (u_int32_t));
+ memcpy (&v2, a2, sizeof (u_int32_t));
+ v1 = ntohl (v1);
+ v2 = ntohl (v2);
+
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return 1;
+ return 0;
+}
+
+int
+community_include (struct community *com, u_int32_t val)
+{
+ int i;
+
+ val = htonl (val);
+
+ for (i = 0; i < com->size; i++)
+ if (memcmp (&val, com_nthval (com, i), sizeof (u_int32_t)) == 0)
+ return 1;
+
+ return 0;
+}
+
+u_int32_t
+community_val_get (struct community *com, int i)
+{
+ u_char *p;
+ u_int32_t val;
+
+ p = (u_char *) com->val;
+ p += (i * 4);
+
+ memcpy (&val, p, sizeof (u_int32_t));
+
+ return ntohl (val);
+}
+
+/* Sort and uniq given community. */
+struct community *
+community_uniq_sort (struct community *com)
+{
+ int i;
+ struct community *new;
+ u_int32_t val;
+
+ if (! com)
+ return NULL;
+
+ new = community_new ();;
+
+ for (i = 0; i < com->size; i++)
+ {
+ val = community_val_get (com, i);
+
+ if (! community_include (new, val))
+ community_add_val (new, val);
+ }
+
+ qsort (new->val, new->size, sizeof (u_int32_t), community_compare);
+
+ return new;
+}
+
+/* Convert communities attribute to string.
+
+ For Well-known communities value, below keyword is used.
+
+ 0x0 "internet"
+ 0xFFFFFF01 "no-export"
+ 0xFFFFFF02 "no-advertise"
+ 0xFFFFFF03 "local-AS"
+
+ For other values, "AS:VAL" format is used. */
+static char *
+community_com2str (struct community *com)
+{
+ int i;
+ char *str;
+ char *pnt;
+ int len;
+ int first;
+ u_int32_t comval;
+ u_int16_t as;
+ u_int16_t val;
+
+ /* When communities attribute is empty. */
+ if (com->size == 0)
+ {
+ str = XMALLOC (MTYPE_COMMUNITY_STR, 1);
+ str[0] = '\0';
+ return str;
+ }
+
+ /* Memory allocation is time consuming work. So we calculate
+ required string length first. */
+ len = 0;
+
+ for (i = 0; i < com->size; i++)
+ {
+ memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
+ comval = ntohl (comval);
+
+ switch (comval)
+ {
+ case COMMUNITY_INTERNET:
+ len += strlen (" internet");
+ break;
+ case COMMUNITY_NO_EXPORT:
+ len += strlen (" no-export");
+ break;
+ case COMMUNITY_NO_ADVERTISE:
+ len += strlen (" no-advertise");
+ break;
+ case COMMUNITY_LOCAL_AS:
+ len += strlen (" local-AS");
+ break;
+ default:
+ len += strlen (" 65536:65535");
+ break;
+ }
+ }
+
+ /* Allocate memory. */
+ str = pnt = XMALLOC (MTYPE_COMMUNITY_STR, len);
+ first = 1;
+
+ /* Fill in string. */
+ for (i = 0; i < com->size; i++)
+ {
+ memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
+ comval = ntohl (comval);
+
+ if (first)
+ first = 0;
+ else
+ *pnt++ = ' ';
+
+ switch (comval)
+ {
+ case COMMUNITY_INTERNET:
+ strcpy (pnt, "internet");
+ pnt += strlen ("internet");
+ break;
+ case COMMUNITY_NO_EXPORT:
+ strcpy (pnt, "no-export");
+ pnt += strlen ("no-export");
+ break;
+ case COMMUNITY_NO_ADVERTISE:
+ strcpy (pnt, "no-advertise");
+ pnt += strlen ("no-advertise");
+ break;
+ case COMMUNITY_LOCAL_AS:
+ strcpy (pnt, "local-AS");
+ pnt += strlen ("local-AS");
+ break;
+ default:
+ as = (comval >> 16) & 0xFFFF;
+ val = comval & 0xFFFF;
+ sprintf (pnt, "%d:%d", as, val);
+ pnt += strlen (pnt);
+ break;
+ }
+ }
+ *pnt = '\0';
+
+ return str;
+}
+
+/* Intern communities attribute. */
+struct community *
+community_intern (struct community *com)
+{
+ struct community *find;
+
+ /* Assert this community structure is not interned. */
+ assert (com->refcnt == 0);
+
+ /* Lookup community hash. */
+ find = (struct community *) hash_get (comhash, com, hash_alloc_intern);
+
+ /* Arguemnt com is allocated temporary. So when it is not used in
+ hash, it should be freed. */
+ if (find != com)
+ community_free (com);
+
+ /* Increment refrence counter. */
+ find->refcnt++;
+
+ /* Make string. */
+ if (! find->str)
+ find->str = community_com2str (find);
+
+ return find;
+}
+
+/* Free community attribute. */
+void
+community_unintern (struct community *com)
+{
+ struct community *ret;
+
+ if (com->refcnt)
+ com->refcnt--;
+
+ /* Pull off from hash. */
+ if (com->refcnt == 0)
+ {
+ /* Community value com must exist in hash. */
+ ret = (struct community *) hash_release (comhash, com);
+ assert (ret != NULL);
+
+ community_free (com);
+ }
+}
+
+/* Create new community attribute. */
+struct community *
+community_parse (char *pnt, u_short length)
+{
+ struct community tmp;
+ struct community *new;
+
+ /* If length is malformed return NULL. */
+ if (length % 4)
+ return NULL;
+
+ /* Make temporary community for hash look up. */
+ tmp.size = length / 4;
+ tmp.val = (u_int32_t *) pnt;
+
+ new = community_uniq_sort (&tmp);
+
+ return community_intern (new);
+}
+
+struct community *
+community_dup (struct community *com)
+{
+ struct community *new;
+
+ new = XCALLOC (MTYPE_COMMUNITY, sizeof (struct community));
+ new->size = com->size;
+ if (new->size)
+ {
+ new->val = XMALLOC (MTYPE_COMMUNITY_VAL, com->size * 4);
+ memcpy (new->val, com->val, com->size * 4);
+ }
+ else
+ new->val = NULL;
+ return new;
+}
+
+/* Retrun string representation of communities attribute. */
+char *
+community_str (struct community *com)
+{
+ if (! com->str)
+ com->str = community_com2str (com);
+ return com->str;
+}
+
+/* Make hash value of community attribute. This function is used by
+ hash package.*/
+unsigned int
+community_hash_make (struct community *com)
+{
+ int c;
+ unsigned int key;
+ unsigned char *pnt;
+
+ key = 0;
+ pnt = (unsigned char *)com->val;
+
+ for(c = 0; c < com->size * 4; c++)
+ key += pnt[c];
+
+ return key;
+}
+
+int
+community_match (struct community *com1, struct community *com2)
+{
+ int i = 0;
+ int j = 0;
+
+ if (com1 == NULL && com2 == NULL)
+ return 1;
+
+ if (com1 == NULL || com2 == NULL)
+ return 0;
+
+ if (com1->size < com2->size)
+ return 0;
+
+ /* Every community on com2 needs to be on com1 for this to match */
+ while (i < com1->size && j < com2->size)
+ {
+ if (memcmp (com1->val + i, com2->val + j, sizeof (u_int32_t)) == 0)
+ j++;
+ i++;
+ }
+
+ if (j == com2->size)
+ return 1;
+ else
+ return 0;
+}
+
+/* If two aspath have same value then return 1 else return 0. This
+ function is used by hash package. */
+int
+community_cmp (struct community *com1, struct community *com2)
+{
+ if (com1 == NULL && com2 == NULL)
+ return 1;
+ if (com1 == NULL || com2 == NULL)
+ return 0;
+
+ if (com1->size == com2->size)
+ if (memcmp (com1->val, com2->val, com1->size * 4) == 0)
+ return 1;
+ return 0;
+}
+
+/* Add com2 to the end of com1. */
+struct community *
+community_merge (struct community *com1, struct community *com2)
+{
+ if (com1->val)
+ com1->val = XREALLOC (MTYPE_COMMUNITY_VAL, com1->val,
+ (com1->size + com2->size) * 4);
+ else
+ com1->val = XMALLOC (MTYPE_COMMUNITY_VAL, (com1->size + com2->size) * 4);
+
+ memcpy (com1->val + com1->size, com2->val, com2->size * 4);
+ com1->size += com2->size;
+
+ return com1;
+}
+
+/* Community token enum. */
+enum community_token
+{
+ community_token_val,
+ community_token_no_export,
+ community_token_no_advertise,
+ community_token_local_as,
+ community_token_unknown
+};
+
+/* Get next community token from string. */
+char *
+community_gettoken (char *buf, enum community_token *token, u_int32_t *val)
+{
+ char *p = buf;
+
+ /* Skip white space. */
+ while (isspace ((int) *p))
+ p++;
+
+ /* Check the end of the line. */
+ if (*p == '\0')
+ return NULL;
+
+ /* Well known community string check. */
+ if (isalpha ((int) *p))
+ {
+ if (strncmp (p, "internet", strlen ("internet")) == 0)
+ {
+ *val = COMMUNITY_INTERNET;
+ *token = community_token_no_export;
+ p += strlen ("internet");
+ return p;
+ }
+ if (strncmp (p, "no-export", strlen ("no-export")) == 0)
+ {
+ *val = COMMUNITY_NO_EXPORT;
+ *token = community_token_no_export;
+ p += strlen ("no-export");
+ return p;
+ }
+ if (strncmp (p, "no-advertise", strlen ("no-advertise")) == 0)
+ {
+ *val = COMMUNITY_NO_ADVERTISE;
+ *token = community_token_no_advertise;
+ p += strlen ("no-advertise");
+ return p;
+ }
+ if (strncmp (p, "local-AS", strlen ("local-AS")) == 0)
+ {
+ *val = COMMUNITY_LOCAL_AS;
+ *token = community_token_local_as;
+ p += strlen ("local-AS");
+ return p;
+ }
+
+ /* Unknown string. */
+ *token = community_token_unknown;
+ return p;
+ }
+
+ /* Community value. */
+ if (isdigit ((int) *p))
+ {
+ int separator = 0;
+ int digit = 0;
+ u_int32_t community_low = 0;
+ u_int32_t community_high = 0;
+
+ while (isdigit ((int) *p) || *p == ':')
+ {
+ if (*p == ':')
+ {
+ if (separator)
+ {
+ *token = community_token_unknown;
+ return p;
+ }
+ else
+ {
+ separator = 1;
+ digit = 0;
+ community_high = community_low << 16;
+ community_low = 0;
+ }
+ }
+ else
+ {
+ digit = 1;
+ community_low *= 10;
+ community_low += (*p - '0');
+ }
+ p++;
+ }
+ if (! digit)
+ {
+ *token = community_token_unknown;
+ return p;
+ }
+ *val = community_high + community_low;
+ *token = community_token_val;
+ return p;
+ }
+ *token = community_token_unknown;
+ return p;
+}
+
+/* convert string to community structure */
+struct community *
+community_str2com (char *str)
+{
+ struct community *com = NULL;
+ struct community *com_sort = NULL;
+ u_int32_t val;
+ enum community_token token;
+
+ while ((str = community_gettoken (str, &token, &val)))
+ {
+ switch (token)
+ {
+ case community_token_val:
+ case community_token_no_export:
+ case community_token_no_advertise:
+ case community_token_local_as:
+ if (com == NULL)
+ com = community_new();
+ community_add_val (com, val);
+ break;
+ case community_token_unknown:
+ default:
+ if (com)
+ community_free (com);
+ return NULL;
+ break;
+ }
+ }
+
+ if (! com)
+ return NULL;
+
+ com_sort = community_uniq_sort (com);
+ community_free (com);
+
+ return com_sort;
+}
+
+/* Return communities hash entry count. */
+unsigned long
+community_count ()
+{
+ return comhash->count;
+}
+
+/* Return communities hash. */
+struct hash *
+community_hash ()
+{
+ return comhash;
+}
+
+/* Initialize comminity related hash. */
+void
+community_init ()
+{
+ comhash = hash_create (community_hash_make, community_cmp);
+}
diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h
new file mode 100644
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 <zebra.h>
+#include <math.h>
+
+#include "prefix.h"
+#include "memory.h"
+#include "command.h"
+#include "log.h"
+#include "thread.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_damp.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_advertise.h"
+
+/* Global variable to access damping configuration */
+struct bgp_damp_config bgp_damp_cfg;
+struct bgp_damp_config *damp = &bgp_damp_cfg;
+
+/* Utility macro to add and delete BGP dampening information to no
+ used list. */
+#define BGP_DAMP_LIST_ADD(N,A) BGP_INFO_ADD(N,A,no_reuse_list)
+#define BGP_DAMP_LIST_DEL(N,A) BGP_INFO_DEL(N,A,no_reuse_list)
+
+/* 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 <zebra.h>
+
+#include "version.h"
+#include "prefix.h"
+#include "linklist.h"
+#include "stream.h"
+#include "command.h"
+#include "str.h"
+#include "log.h"
+#include "sockunion.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_community.h"
+
+unsigned long conf_bgp_debug_fsm;
+unsigned long conf_bgp_debug_events;
+unsigned long conf_bgp_debug_packet;
+unsigned long conf_bgp_debug_filter;
+unsigned long conf_bgp_debug_keepalive;
+unsigned long conf_bgp_debug_update;
+unsigned long conf_bgp_debug_normal;
+
+unsigned long term_bgp_debug_fsm;
+unsigned long term_bgp_debug_events;
+unsigned long term_bgp_debug_packet;
+unsigned long term_bgp_debug_filter;
+unsigned long term_bgp_debug_keepalive;
+unsigned long term_bgp_debug_update;
+unsigned long term_bgp_debug_normal;
+
+/* messages for BGP-4 status */
+struct message bgp_status_msg[] =
+{
+ { 0, "null" },
+ { Idle, "Idle" },
+ { Connect, "Connect" },
+ { Active, "Active" },
+ { OpenSent, "OpenSent" },
+ { OpenConfirm, "OpenConfirm" },
+ { Established, "Established" },
+};
+int bgp_status_msg_max = BGP_STATUS_MAX;
+
+/* BGP message type string. */
+char *bgp_type_str[] =
+{
+ NULL,
+ "OPEN",
+ "UPDATE",
+ "NOTIFICATION",
+ "KEEPALIVE",
+ "ROUTE-REFRESH",
+ "CAPABILITY"
+};
+
+/* message for BGP-4 Notify */
+struct message bgp_notify_msg[] =
+{
+ { 0, "" },
+ { BGP_NOTIFY_HEADER_ERR, "Message Header Error"},
+ { BGP_NOTIFY_OPEN_ERR, "OPEN Message Error"},
+ { BGP_NOTIFY_UPDATE_ERR, "UPDATE Message Error"},
+ { BGP_NOTIFY_HOLD_ERR, "Hold Timer Expired"},
+ { BGP_NOTIFY_FSM_ERR, "Finite State Machine Error"},
+ { BGP_NOTIFY_CEASE, "Cease"},
+ { BGP_NOTIFY_CAPABILITY_ERR, "CAPABILITY Message Error"},
+};
+int bgp_notify_msg_max = BGP_NOTIFY_MAX;
+
+struct message bgp_notify_head_msg[] =
+{
+ { 0, "null"},
+ { BGP_NOTIFY_HEADER_NOT_SYNC, "/Connection Not Synchronized."},
+ { BGP_NOTIFY_HEADER_BAD_MESLEN, "/Bad Message Length."},
+ { BGP_NOTIFY_HEADER_BAD_MESTYPE, "/Bad Message Type."}
+};
+int bgp_notify_head_msg_max = BGP_NOTIFY_HEADER_MAX;
+
+struct message bgp_notify_open_msg[] =
+{
+ { 0, "null" },
+ { BGP_NOTIFY_OPEN_UNSUP_VERSION, "/Unsupported Version Number." },
+ { BGP_NOTIFY_OPEN_BAD_PEER_AS, "/Bad Peer AS."},
+ { BGP_NOTIFY_OPEN_BAD_BGP_IDENT, "/Bad BGP Identifier."},
+ { BGP_NOTIFY_OPEN_UNSUP_PARAM, "/Unsupported Optional Parameter."},
+ { BGP_NOTIFY_OPEN_AUTH_FAILURE, "/Authentication Failure."},
+ { BGP_NOTIFY_OPEN_UNACEP_HOLDTIME, "/Unacceptable Hold Time."},
+ { BGP_NOTIFY_OPEN_UNSUP_CAPBL, "/Unsupported Capability."},
+};
+int bgp_notify_open_msg_max = BGP_NOTIFY_OPEN_MAX;
+
+struct message bgp_notify_update_msg[] =
+{
+ { 0, "null"},
+ { BGP_NOTIFY_UPDATE_MAL_ATTR, "/Malformed Attribute List."},
+ { BGP_NOTIFY_UPDATE_UNREC_ATTR, "/Unrecognized Well-known Attribute."},
+ { BGP_NOTIFY_UPDATE_MISS_ATTR, "/Missing Well-known Attribute."},
+ { BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, "/Attribute Flags Error."},
+ { BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, "/Attribute Length Error."},
+ { BGP_NOTIFY_UPDATE_INVAL_ORIGIN, "/Invalid ORIGIN Attribute."},
+ { BGP_NOTIFY_UPDATE_AS_ROUTE_LOOP, "/AS Routing Loop."},
+ { BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, "/Invalid NEXT_HOP Attribute."},
+ { BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, "/Optional Attribute Error."},
+ { BGP_NOTIFY_UPDATE_INVAL_NETWORK, "/Invalid Network Field."},
+ { BGP_NOTIFY_UPDATE_MAL_AS_PATH, "/Malformed AS_PATH."},
+};
+int bgp_notify_update_msg_max = BGP_NOTIFY_UPDATE_MAX;
+
+struct message bgp_notify_cease_msg[] =
+{
+ { 0, ""},
+ { BGP_NOTIFY_CEASE_MAX_PREFIX, "/Maximum Number of Prefixes Reached."},
+ { BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, "/Administratively Shutdown."},
+ { BGP_NOTIFY_CEASE_PEER_UNCONFIG, "/Peer Unconfigured."},
+ { BGP_NOTIFY_CEASE_ADMIN_RESET, "/Administratively Reset."},
+ { BGP_NOTIFY_CEASE_CONNECT_REJECT, "/Connection Rejected."},
+ { BGP_NOTIFY_CEASE_CONFIG_CHANGE, "/Other Configuration Change."},
+};
+int bgp_notify_cease_msg_max = BGP_NOTIFY_CEASE_MAX;
+
+struct message bgp_notify_capability_msg[] =
+{
+ { 0, "null" },
+ { BGP_NOTIFY_CAPABILITY_INVALID_ACTION, "/Invalid Action Value." },
+ { BGP_NOTIFY_CAPABILITY_INVALID_LENGTH, "/Invalid Capability Length."},
+ { BGP_NOTIFY_CAPABILITY_MALFORMED_CODE, "/Malformed Capability Value."},
+};
+int bgp_notify_capability_msg_max = BGP_NOTIFY_CAPABILITY_MAX;
+
+/* Origin strings. */
+char *bgp_origin_str[] = {"i","e","?"};
+char *bgp_origin_long_str[] = {"IGP","EGP","incomplete"};
+
+/* Dump attribute. */
+void
+bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size)
+{
+
+ if (! attr)
+ return;
+
+ snprintf (buf, size, "nexthop %s", inet_ntoa (attr->nexthop));
+ snprintf (buf + strlen (buf), size - strlen (buf), ", origin %s",
+ bgp_origin_str[attr->origin]);
+
+#ifdef HAVE_IPV6
+ {
+ char addrbuf[BUFSIZ];
+
+ /* Add MP case. */
+ if (attr->mp_nexthop_len == 16 || attr->mp_nexthop_len == 32)
+ snprintf (buf + strlen (buf), size - strlen (buf), ", mp_nexthop %s",
+ inet_ntop (AF_INET6, &attr->mp_nexthop_global,
+ addrbuf, BUFSIZ));
+
+ if (attr->mp_nexthop_len == 32)
+ snprintf (buf + strlen (buf), size - strlen (buf), "(%s)",
+ inet_ntop (AF_INET6, &attr->mp_nexthop_local,
+ addrbuf, BUFSIZ));
+ }
+#endif /* HAVE_IPV6 */
+
+ if (peer_sort (peer) == BGP_PEER_IBGP)
+ snprintf (buf + strlen (buf), size - strlen (buf), ", localpref %d",
+ attr->local_pref);
+
+ if (attr->med)
+ snprintf (buf + strlen (buf), size - strlen (buf), ", metric %d",
+ attr->med);
+
+ if (attr->community)
+ snprintf (buf + strlen (buf), size - strlen (buf), ", community %s",
+ community_str (attr->community));
+
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))
+ snprintf (buf + strlen (buf), size - strlen (buf), ", atomic-aggregate");
+
+ if (attr->aggregator_as)
+ snprintf (buf + strlen (buf), size - strlen (buf), ", aggregated by %d %s",
+ attr->aggregator_as, inet_ntoa (attr->aggregator_addr));
+
+ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID))
+ snprintf (buf + strlen (buf), size - strlen (buf), ", originator %s",
+ inet_ntoa (attr->originator_id));
+
+ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST))
+ {
+ int i;
+
+ snprintf (buf + strlen (buf), size - strlen (buf), ", clusterlist ");
+ for (i = 0; i < attr->cluster->length / 4; i++)
+ snprintf (buf + strlen (buf), size - strlen (buf), "%s",
+ inet_ntoa (attr->cluster->list[i]));
+ }
+
+ if (attr->aspath)
+ snprintf (buf + strlen (buf), size - strlen (buf), ", path %s",
+ aspath_print (attr->aspath));
+}
+
+/* dump notify packet */
+void
+bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify, char *direct)
+{
+ char *subcode_str;
+
+ subcode_str = "";
+
+ switch (bgp_notify->code)
+ {
+ case BGP_NOTIFY_HEADER_ERR:
+ subcode_str = LOOKUP (bgp_notify_head_msg, bgp_notify->subcode);
+ break;
+ case BGP_NOTIFY_OPEN_ERR:
+ subcode_str = LOOKUP (bgp_notify_open_msg, bgp_notify->subcode);
+ break;
+ case BGP_NOTIFY_UPDATE_ERR:
+ subcode_str = LOOKUP (bgp_notify_update_msg, bgp_notify->subcode);
+ break;
+ case BGP_NOTIFY_HOLD_ERR:
+ subcode_str = "";
+ break;
+ case BGP_NOTIFY_FSM_ERR:
+ subcode_str = "";
+ break;
+ case BGP_NOTIFY_CEASE:
+ subcode_str = LOOKUP (bgp_notify_cease_msg, bgp_notify->subcode);
+ break;
+ case BGP_NOTIFY_CAPABILITY_ERR:
+ subcode_str = LOOKUP (bgp_notify_capability_msg, bgp_notify->subcode);
+ break;
+ }
+ if (BGP_DEBUG (normal, NORMAL))
+ plog_info (peer->log, "%s %s NOTIFICATION %d/%d (%s%s) %d bytes %s",
+ peer ? peer->host : "",
+ direct, bgp_notify->code, bgp_notify->subcode,
+ LOOKUP (bgp_notify_msg, bgp_notify->code),
+ subcode_str, bgp_notify->length,
+ bgp_notify->data ? bgp_notify->data : "");
+}
+
+/* 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 <zebra.h>
+
+#include "log.h"
+#include "stream.h"
+#include "sockunion.h"
+#include "command.h"
+#include "prefix.h"
+#include "thread.h"
+#include "bgpd/bgp_table.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_dump.h"
+
+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 <kunihiro@zebra.org>
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING. If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include <zebra.h>
+
+#include "hash.h"
+#include "memory.h"
+#include "prefix.h"
+#include "command.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_ecommunity.h"
+
+/* Hash of community attribute. */
+struct hash *ecomhash;
+
+/* 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 <kunihiro@zebra.org>
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING. If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+/* High-order octet of the Extended Communities type field. */
+#define ECOMMUNITY_ENCODE_AS 0x00
+#define ECOMMUNITY_ENCODE_IP 0x01
+
+/* Low-order octet of the Extended Communityes type field. */
+#define ECOMMUNITY_ROUTE_TARGET 0x02
+#define ECOMMUNITY_SITE_ORIGIN 0x03
+
+/* Extended communities attribute string format. */
+#define ECOMMUNITY_FORMAT_ROUTE_MAP 0
+#define ECOMMUNITY_FORMAT_COMMUNITY_LIST 1
+#define ECOMMUNITY_FORMAT_DISPLAY 2
+
+/* Extended Communities value is eight octet long. */
+#define ECOMMUNITY_SIZE 8
+
+/* Extended Communities attribute. */
+struct ecommunity
+{
+ /* Reference counter. */
+ unsigned long refcnt;
+
+ /* Size of Extended Communities attribute. */
+ int size;
+
+ /* Extended Communities value. */
+ u_char *val;
+
+ /* Human readable format string. */
+ char *str;
+};
+
+/* Extended community value is eight octet. */
+struct ecommunity_val
+{
+ char val[ECOMMUNITY_SIZE];
+};
+
+#define ecom_length(X) ((X)->size * ECOMMUNITY_SIZE)
+
+void ecommunity_init (void);
+void ecommunity_free (struct ecommunity *);
+struct ecommunity *ecommunity_new (void);
+struct ecommunity *ecommunity_parse (char *, u_short);
+struct ecommunity *ecommunity_dup (struct ecommunity *);
+struct ecommunity *ecommunity_merge (struct ecommunity *, struct ecommunity *);
+struct ecommunity *ecommunity_intern (struct ecommunity *);
+int ecommunity_cmp (struct ecommunity *, struct ecommunity *);
+void ecommunity_unintern (struct ecommunity *);
+unsigned int ecommunity_hash_make (struct ecommunity *);
+struct ecommunity *ecommunity_str2com (char *, int, int);
+char *ecommunity_ecom2str (struct ecommunity *, int);
diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c
new file mode 100644
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 <zebra.h>
+
+#include "command.h"
+#include "log.h"
+#include "memory.h"
+#include "buffer.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_regex.h"
+#include "bgpd/bgp_filter.h"
+
+/* List of AS filter list. */
+struct as_list_list
+{
+ struct as_list *head;
+ struct as_list *tail;
+};
+
+/* AS path filter master. */
+struct as_list_master
+{
+ /* List of access_list which name is number. */
+ struct as_list_list num;
+
+ /* List of access_list which name is string. */
+ struct as_list_list str;
+
+ /* Hook function which is executed when new access_list is added. */
+ void (*add_hook) ();
+
+ /* Hook function which is executed when access_list is deleted. */
+ void (*delete_hook) ();
+};
+
+/* Element of AS path filter. */
+struct as_filter
+{
+ struct as_filter *next;
+ struct as_filter *prev;
+
+ enum as_filter_type type;
+
+ regex_t *reg;
+ char *reg_str;
+};
+
+enum as_list_type
+{
+ ACCESS_TYPE_STRING,
+ ACCESS_TYPE_NUMBER
+};
+
+/* AS path filter list. */
+struct as_list
+{
+ char *name;
+
+ enum as_list_type type;
+
+ struct as_list *next;
+ struct as_list *prev;
+
+ struct as_filter *head;
+ struct as_filter *tail;
+};
+
+/* 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 <zebra.h>
+
+#include "linklist.h"
+#include "prefix.h"
+#include "vty.h"
+#include "sockunion.h"
+#include "thread.h"
+#include "log.h"
+#include "stream.h"
+#include "memory.h"
+#include "plist.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_network.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_dump.h"
+#include "bgpd/bgp_open.h"
+#ifdef HAVE_SNMP
+#include "bgpd/bgp_snmp.h"
+#endif /* HAVE_SNMP */
+
+/* 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 <zebra.h>
+
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+#include "getopt.h"
+#include "thread.h"
+#include "version.h"
+#include "memory.h"
+#include "prefix.h"
+#include "log.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_mplsvpn.h"
+
+/* bgpd options, we use GNU getopt library. */
+struct option longopts[] =
+{
+ { "daemon", no_argument, NULL, 'd'},
+ { "config_file", required_argument, NULL, 'f'},
+ { "pid_file", required_argument, NULL, 'i'},
+ { "bgp_port", required_argument, NULL, 'p'},
+ { "vty_addr", required_argument, NULL, 'A'},
+ { "vty_port", required_argument, NULL, 'P'},
+ { "retain", no_argument, NULL, 'r'},
+ { "no_kernel", no_argument, NULL, 'n'},
+ { "version", no_argument, NULL, 'v'},
+ { "help", no_argument, NULL, 'h'},
+ { 0 }
+};
+
+/* Configuration file and directory. */
+char config_current[] = BGP_DEFAULT_CONFIG;
+char config_default[] = SYSCONFDIR BGP_DEFAULT_CONFIG;
+
+/* Route retain mode flag. */
+int retain_mode = 0;
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* Manually specified configuration file name. */
+char *config_file = NULL;
+
+/* Process ID saved for use by init system */
+char *pid_file = PATH_BGPD_PID;
+
+/* VTY port number and address. */
+int vty_port = BGP_VTY_PORT;
+char *vty_addr = NULL;
+
+/* Help information display. */
+static void
+usage (char *progname, int status)
+{
+ if (status != 0)
+ fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+ else
+ {
+ printf ("Usage : %s [OPTION...]\n\n\
+Daemon which manages kernel routing table management and \
+redistribution between different routing protocols.\n\n\
+-d, --daemon Runs in daemon mode\n\
+-f, --config_file Set configuration file name\n\
+-i, --pid_file Set process identifier file name\n\
+-p, --bgp_port Set bgp protocol's port number\n\
+-A, --vty_addr Set vty's bind address\n\
+-P, --vty_port Set vty's port number\n\
+-r, --retain When program terminates, retain added route by bgpd.\n\
+-n, --no_kernel Do not install route to kernel.\n\
+-v, --version Print program version\n\
+-h, --help Display this help and exit\n\
+\n\
+Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
+ }
+
+ exit (status);
+}
+
+/* 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 <kunihiro@zebra.org>
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING. If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "prefix.h"
+#include "log.h"
+#include "memory.h"
+#include "stream.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_mplsvpn.h"
+
+int route_vty_out (struct vty *, struct prefix *, struct bgp_info *, int, safi_t);
+int route_vty_out_tag (struct vty *, struct prefix *, struct bgp_info *, int, safi_t);
+void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, safi_t);
+
+u_int16_t
+decode_rd_type (u_char *pnt)
+{
+ u_int16_t v;
+
+ v = ((u_int16_t) *pnt++ << 8);
+ v |= (u_int16_t) *pnt;
+ return v;
+}
+
+u_int32_t
+decode_label (u_char *pnt)
+{
+ u_int32_t l;
+
+ l = ((u_int32_t) *pnt++ << 12);
+ l |= (u_int32_t) *pnt++ << 4;
+ l |= (u_int32_t) ((*pnt & 0xf0) >> 4);
+ return l;
+}
+
+void
+decode_rd_as (u_char *pnt, struct rd_as *rd_as)
+{
+ rd_as->as = (u_int16_t) *pnt++ << 8;
+ rd_as->as |= (u_int16_t) *pnt++;
+
+ rd_as->val = ((u_int32_t) *pnt++ << 24);
+ rd_as->val |= ((u_int32_t) *pnt++ << 16);
+ rd_as->val |= ((u_int32_t) *pnt++ << 8);
+ rd_as->val |= (u_int32_t) *pnt;
+}
+
+void
+decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip)
+{
+ memcpy (&rd_ip->ip, pnt, 4);
+ pnt += 4;
+
+ rd_ip->val = ((u_int16_t) *pnt++ << 8);
+ rd_ip->val |= (u_int16_t) *pnt;
+}
+
+int bgp_update (struct peer *, struct prefix *, struct attr *,
+ afi_t, safi_t, int, int, struct prefix_rd *, u_char *);
+
+int bgp_withdraw (struct peer *, struct prefix *, struct attr *,
+ int, int, int, int, struct prefix_rd *, u_char *);
+int
+bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr,
+ struct bgp_nlri *packet)
+{
+ u_char *pnt;
+ u_char *lim;
+ struct prefix p;
+ int psize;
+ int prefixlen;
+ u_int32_t label;
+ u_int16_t type;
+ struct rd_as rd_as;
+ struct rd_ip rd_ip;
+ struct prefix_rd prd;
+ u_char *tagpnt;
+
+ /* Check peer status. */
+ if (peer->status != Established)
+ return 0;
+
+ /* Make prefix_rd */
+ prd.family = AF_UNSPEC;
+ prd.prefixlen = 64;
+
+ pnt = packet->nlri;
+ lim = pnt + packet->length;
+
+ for (; pnt < lim; pnt += psize)
+ {
+ /* Clear prefix structure. */
+ memset (&p, 0, sizeof (struct prefix));
+
+ /* Fetch prefix length. */
+ prefixlen = *pnt++;
+ p.family = AF_INET;
+ psize = PSIZE (prefixlen);
+
+ if (prefixlen < 88)
+ {
+ zlog_err ("prefix length is less than 88: %d", prefixlen);
+ return -1;
+ }
+
+ label = decode_label (pnt);
+
+ /* Copyr label to prefix. */
+ tagpnt = pnt;;
+
+ /* Copy routing distinguisher to rd. */
+ memcpy (&prd.val, pnt + 3, 8);
+
+ /* Decode RD type. */
+ type = decode_rd_type (pnt + 3);
+
+ /* Decode RD value. */
+ if (type == RD_TYPE_AS)
+ decode_rd_as (pnt + 5, &rd_as);
+ else if (type == RD_TYPE_IP)
+ decode_rd_ip (pnt + 5, &rd_ip);
+ else
+ {
+ zlog_err ("Invalid RD type %d", type);
+ return -1;
+ }
+
+ p.prefixlen = prefixlen - 88;
+ memcpy (&p.u.prefix, pnt + 11, psize - 11);
+
+#if 0
+ if (type == RD_TYPE_AS)
+ zlog_info ("prefix %ld:%ld:%ld:%s/%d", label, rd_as.as, rd_as.val,
+ inet_ntoa (p.u.prefix4), p.prefixlen);
+ else if (type == RD_TYPE_IP)
+ zlog_info ("prefix %ld:%s:%ld:%s/%d", label, inet_ntoa (rd_ip.ip),
+ rd_ip.val, inet_ntoa (p.u.prefix4), p.prefixlen);
+#endif /* 0 */
+
+ if (pnt + psize > lim)
+ return -1;
+
+ if (attr)
+ bgp_update (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN,
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt);
+ else
+ bgp_withdraw (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN,
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt);
+ }
+
+ /* Packet length consistency check. */
+ if (pnt != lim)
+ return -1;
+
+ return 0;
+}
+
+int
+str2prefix_rd (u_char *str, struct prefix_rd *prd)
+{
+ int ret;
+ u_char *p;
+ u_char *p2;
+ struct stream *s;
+ u_char *half;
+ struct in_addr addr;
+
+ s = stream_new (8);
+
+ prd->family = AF_UNSPEC;
+ prd->prefixlen = 64;
+
+ p = strchr (str, ':');
+ if (! p)
+ return 0;
+
+ if (! all_digit (p + 1))
+ return 0;
+
+ half = XMALLOC (MTYPE_TMP, (p - str) + 1);
+ memcpy (half, str, (p - str));
+ half[p - str] = '\0';
+
+ p2 = strchr (str, '.');
+
+ if (! p2)
+ {
+ if (! all_digit (half))
+ {
+ XFREE (MTYPE_TMP, half);
+ return 0;
+ }
+ stream_putw (s, RD_TYPE_AS);
+ stream_putw (s, atoi (half));
+ stream_putl (s, atol (p + 1));
+ }
+ else
+ {
+ ret = inet_aton (half, &addr);
+ if (! ret)
+ {
+ XFREE (MTYPE_TMP, half);
+ return 0;
+ }
+ stream_putw (s, RD_TYPE_IP);
+ stream_put_in_addr (s, &addr);
+ stream_putw (s, atol (p + 1));
+ }
+ memcpy (prd->val, s->data, 8);
+
+ return 1;
+}
+
+int
+str2tag (u_char *str, u_char *tag)
+{
+ u_int32_t l;
+
+ l = atol (str);
+
+ tag[0] = (u_char)(l >> 12);
+ tag[1] = (u_char)(l >> 4);
+ tag[2] = (u_char)(l << 4);
+
+ return 1;
+}
+
+char *
+prefix_rd2str (struct prefix_rd *prd, char *buf, size_t size)
+{
+ u_char *pnt;
+ u_int16_t type;
+ struct rd_as rd_as;
+ struct rd_ip rd_ip;
+
+ if (size < RD_ADDRSTRLEN)
+ return NULL;
+
+ pnt = prd->val;
+
+ type = decode_rd_type (pnt);
+
+ if (type == RD_TYPE_AS)
+ {
+ decode_rd_as (pnt + 2, &rd_as);
+ snprintf (buf, size, "%d:%d", rd_as.as, rd_as.val);
+ return buf;
+ }
+ else if (type == RD_TYPE_IP)
+ {
+ decode_rd_ip (pnt + 2, &rd_ip);
+ snprintf (buf, size, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
+ return buf;
+ }
+
+ return NULL;
+}
+
+/* For testing purpose, static route of MPLS-VPN. */
+DEFUN (vpnv4_network,
+ vpnv4_network_cmd,
+ "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD",
+ "Specify a network to announce via BGP\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Specify Route Distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "BGP tag\n"
+ "tag value\n")
+{
+ return bgp_static_set_vpnv4 (vty, argv[0], argv[1], argv[2]);
+}
+
+/* For testing purpose, static route of MPLS-VPN. */
+DEFUN (no_vpnv4_network,
+ no_vpnv4_network_cmd,
+ "no network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD",
+ NO_STR
+ "Specify a network to announce via BGP\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Specify Route Distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "BGP tag\n"
+ "tag value\n")
+{
+ return bgp_static_unset_vpnv4 (vty, argv[0], argv[1], argv[2]);
+}
+
+int
+show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd)
+{
+ struct bgp *bgp;
+ struct bgp_table *table;
+ struct bgp_node *rn;
+ struct bgp_node *rm;
+ struct attr *attr;
+ int rd_header;
+ int header = 1;
+ char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s";
+
+ bgp = bgp_get_default ();
+ if (bgp == NULL)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn;
+ rn = bgp_route_next (rn))
+ {
+ if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
+ continue;
+
+ if ((table = rn->info) != NULL)
+ {
+ rd_header = 1;
+
+ for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm))
+ if ((attr = rm->info) != NULL)
+ {
+ if (header)
+ {
+ vty_out (vty, "BGP table version is 0, local router ID is %s%s",
+ inet_ntoa (bgp->router_id), VTY_NEWLINE);
+ vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s",
+ VTY_NEWLINE);
+ vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s",
+ VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, v4_header, VTY_NEWLINE);
+ header = 0;
+ }
+
+ if (rd_header)
+ {
+ u_int16_t type;
+ struct rd_as rd_as;
+ struct rd_ip rd_ip;
+ u_char *pnt;
+
+ pnt = rn->p.u.val;
+
+ /* Decode RD type. */
+ type = decode_rd_type (pnt);
+ /* Decode RD value. */
+ if (type == RD_TYPE_AS)
+ decode_rd_as (pnt + 2, &rd_as);
+ else if (type == RD_TYPE_IP)
+ decode_rd_ip (pnt + 2, &rd_ip);
+
+ vty_out (vty, "Route Distinguisher: ");
+
+ if (type == RD_TYPE_AS)
+ vty_out (vty, "%d:%d", rd_as.as, rd_as.val);
+ else if (type == RD_TYPE_IP)
+ vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+ rd_header = 0;
+ }
+ route_vty_out_tmp (vty, &rm->p, attr, SAFI_MPLS_VPN);
+ }
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+enum bgp_show_type
+{
+ bgp_show_type_normal,
+ bgp_show_type_regexp,
+ bgp_show_type_prefix_list,
+ bgp_show_type_filter_list,
+ bgp_show_type_neighbor,
+ bgp_show_type_cidr_only,
+ bgp_show_type_prefix_longer,
+ bgp_show_type_community_all,
+ bgp_show_type_community,
+ bgp_show_type_community_exact,
+ bgp_show_type_community_list,
+ bgp_show_type_community_list_exact
+};
+
+int
+bgp_show_mpls_vpn (struct vty *vty, struct prefix_rd *prd, enum bgp_show_type type,
+ void *output_arg, int tags)
+{
+ struct bgp *bgp;
+ struct bgp_table *table;
+ struct bgp_node *rn;
+ struct bgp_node *rm;
+ struct bgp_info *ri;
+ int rd_header;
+ int header = 1;
+ char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s";
+ char v4_header_tag[] = " Network Next Hop In tag/Out tag%s";
+
+ bgp = bgp_get_default ();
+ if (bgp == NULL)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn))
+ {
+ if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
+ continue;
+
+ if ((table = rn->info) != NULL)
+ {
+ rd_header = 1;
+
+ for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm))
+ for (ri = rm->info; ri; ri = ri->next)
+ {
+ if (type == bgp_show_type_neighbor)
+ {
+ union sockunion *su = output_arg;
+
+ if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su))
+ continue;
+ }
+ if (header)
+ {
+ if (tags)
+ vty_out (vty, v4_header_tag, VTY_NEWLINE);
+ else
+ {
+ vty_out (vty, "BGP table version is 0, local router ID is %s%s",
+ inet_ntoa (bgp->router_id), VTY_NEWLINE);
+ vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s",
+ VTY_NEWLINE);
+ vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s",
+ VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, v4_header, VTY_NEWLINE);
+ }
+ header = 0;
+ }
+
+ if (rd_header)
+ {
+ u_int16_t type;
+ struct rd_as rd_as;
+ struct rd_ip rd_ip;
+ u_char *pnt;
+
+ pnt = rn->p.u.val;
+
+ /* Decode RD type. */
+ type = decode_rd_type (pnt);
+ /* Decode RD value. */
+ if (type == RD_TYPE_AS)
+ decode_rd_as (pnt + 2, &rd_as);
+ else if (type == RD_TYPE_IP)
+ decode_rd_ip (pnt + 2, &rd_ip);
+
+ vty_out (vty, "Route Distinguisher: ");
+
+ if (type == RD_TYPE_AS)
+ vty_out (vty, "%d:%d", rd_as.as, rd_as.val);
+ else if (type == RD_TYPE_IP)
+ vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+ rd_header = 0;
+ }
+ if (tags)
+ route_vty_out_tag (vty, &rm->p, ri, 0, SAFI_MPLS_VPN);
+ else
+ route_vty_out (vty, &rm->p, ri, 0, SAFI_MPLS_VPN);
+ }
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_bgp_vpnv4_all,
+ show_ip_bgp_vpnv4_all_cmd,
+ "show ip bgp vpnv4 all",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display VPNv4 NLRI specific information\n"
+ "Display information about all VPNv4 NLRIs\n")
+{
+ return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_normal, NULL, 0);
+}
+
+DEFUN (show_ip_bgp_vpnv4_rd,
+ show_ip_bgp_vpnv4_rd_cmd,
+ "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display VPNv4 NLRI specific information\n"
+ "Display information for a route distinguisher\n"
+ "VPN Route Distinguisher\n")
+{
+ int ret;
+ struct prefix_rd prd;
+
+ ret = str2prefix_rd (argv[0], &prd);
+ if (! ret)
+ {
+ vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_normal, NULL, 0);
+}
+
+DEFUN (show_ip_bgp_vpnv4_all_tags,
+ show_ip_bgp_vpnv4_all_tags_cmd,
+ "show ip bgp vpnv4 all tags",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display VPNv4 NLRI specific information\n"
+ "Display information about all VPNv4 NLRIs\n"
+ "Display BGP tags for prefixes\n")
+{
+ return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_normal, NULL, 1);
+}
+
+DEFUN (show_ip_bgp_vpnv4_rd_tags,
+ show_ip_bgp_vpnv4_rd_tags_cmd,
+ "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn tags",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display VPNv4 NLRI specific information\n"
+ "Display information for a route distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "Display BGP tags for prefixes\n")
+{
+ int ret;
+ struct prefix_rd prd;
+
+ ret = str2prefix_rd (argv[0], &prd);
+ if (! ret)
+ {
+ vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_normal, NULL, 1);
+}
+
+DEFUN (show_ip_bgp_vpnv4_all_neighbor_routes,
+ show_ip_bgp_vpnv4_all_neighbor_routes_cmd,
+ "show ip bgp vpnv4 all neighbors A.B.C.D routes",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display VPNv4 NLRI specific information\n"
+ "Display information about all VPNv4 NLRIs\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Display routes learned from neighbor\n")
+{
+ union sockunion *su;
+ struct peer *peer;
+
+ su = sockunion_str2su (argv[0]);
+ if (su == NULL)
+ {
+ vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ peer = peer_lookup (NULL, su);
+ if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN])
+ {
+ vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_neighbor, su, 0);
+}
+
+DEFUN (show_ip_bgp_vpnv4_rd_neighbor_routes,
+ show_ip_bgp_vpnv4_rd_neighbor_routes_cmd,
+ "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display VPNv4 NLRI specific information\n"
+ "Display information for a route distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Display routes learned from neighbor\n")
+{
+ int ret;
+ union sockunion *su;
+ struct peer *peer;
+ struct prefix_rd prd;
+
+ ret = str2prefix_rd (argv[0], &prd);
+ if (! ret)
+ {
+ vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ su = sockunion_str2su (argv[1]);
+ if (su == NULL)
+ {
+ vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ peer = peer_lookup (NULL, su);
+ if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN])
+ {
+ vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_neighbor, su, 0);
+}
+
+DEFUN (show_ip_bgp_vpnv4_all_neighbor_advertised_routes,
+ show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd,
+ "show ip bgp vpnv4 all neighbors A.B.C.D advertised-routes",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display VPNv4 NLRI specific information\n"
+ "Display information about all VPNv4 NLRIs\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Display the routes advertised to a BGP neighbor\n")
+{
+ int ret;
+ struct peer *peer;
+ union sockunion su;
+
+ ret = str2sockunion (argv[0], &su);
+ if (ret < 0)
+ {
+ vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ peer = peer_lookup (NULL, &su);
+ if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN])
+ {
+ vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return show_adj_route_vpn (vty, peer, NULL);
+}
+
+DEFUN (show_ip_bgp_vpnv4_rd_neighbor_advertised_routes,
+ show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd,
+ "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display VPNv4 NLRI specific information\n"
+ "Display information for a route distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Display the routes advertised to a BGP neighbor\n")
+{
+ int ret;
+ struct peer *peer;
+ struct prefix_rd prd;
+ union sockunion su;
+
+ ret = str2sockunion (argv[1], &su);
+ if (ret < 0)
+ {
+ vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ peer = peer_lookup (NULL, &su);
+ if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN])
+ {
+ vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ret = str2prefix_rd (argv[0], &prd);
+ if (! ret)
+ {
+ vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return show_adj_route_vpn (vty, peer, &prd);
+}
+
+void
+bgp_mplsvpn_init ()
+{
+ install_element (BGP_VPNV4_NODE, &vpnv4_network_cmd);
+ install_element (BGP_VPNV4_NODE, &no_vpnv4_network_cmd);
+
+
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_tags_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd);
+
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_tags_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd);
+}
diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h
new file mode 100644
index 00000000..cd861a87
--- /dev/null
+++ b/bgpd/bgp_mplsvpn.h
@@ -0,0 +1,45 @@
+/* MPLS-VPN
+ Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING. If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#define RD_TYPE_AS 0
+#define RD_TYPE_IP 1
+
+#define RD_ADDRSTRLEN 28
+
+struct rd_as
+{
+ u_int16_t type;
+ as_t as;
+ u_int32_t val;
+};
+
+struct rd_ip
+{
+ u_int16_t type;
+ struct in_addr ip;
+ u_int16_t val;
+};
+
+void bgp_mplsvpn_init ();
+int bgp_nlri_parse_vpnv4 (struct peer *, struct attr *, struct bgp_nlri *);
+u_int32_t decode_label (u_char *);
+int str2prefix_rd (u_char *, struct prefix_rd *);
+int str2tag (u_char *, u_char *);
+char *prefix_rd2str (struct prefix_rd *, char *, size_t);
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
new file mode 100644
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 <zebra.h>
+
+#include "thread.h"
+#include "sockunion.h"
+#include "memory.h"
+#include "log.h"
+#include "if.h"
+#include "prefix.h"
+#include "command.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_network.h"
+
+/* 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 <zebra.h>
+
+#include "command.h"
+#include "thread.h"
+#include "prefix.h"
+#include "zclient.h"
+#include "stream.h"
+#include "network.h"
+#include "log.h"
+#include "memory.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_nexthop.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_damp.h"
+#include "zebra/rib.h"
+#include "zebra/zserv.h" /* For ZEBRA_SERV_PATH. */
+
+struct bgp_nexthop_cache *zlookup_query (struct in_addr);
+#ifdef HAVE_IPV6
+struct bgp_nexthop_cache *zlookup_query_ipv6 (struct in6_addr *);
+#endif /* HAVE_IPV6 */
+
+/* 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 <zebra.h>
+
+#include "linklist.h"
+#include "prefix.h"
+#include "stream.h"
+#include "thread.h"
+#include "log.h"
+#include "command.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_open.h"
+
+/* 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 <zebra.h>
+
+#include "thread.h"
+#include "stream.h"
+#include "network.h"
+#include "prefix.h"
+#include "command.h"
+#include "log.h"
+#include "memory.h"
+#include "sockunion.h" /* for inet_ntop () */
+#include "linklist.h"
+#include "plist.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_dump.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_open.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_network.h"
+#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_advertise.h"
+
+int stream_put_prefix (struct stream *, struct prefix *);
+
+/* 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 <zebra.h>
+
+#include "log.h"
+#include "command.h"
+#include "memory.h"
+
+#include "bgpd.h"
+#include "bgp_aspath.h"
+#include "bgp_regex.h"
+
+/* Character `_' has special mean. It represents [,{}() ] and the
+ beginning of the line(^) and the end of the line ($).
+
+ (^|[,{}() ]|$) */
+
+regex_t *
+bgp_regcomp (char *regstr)
+{
+ /* Convert _ character to generic regular expression. */
+ int i, j;
+ int len;
+ int magic = 0;
+ char *magic_str;
+ char magic_regexp[] = "(^|[,{}() ]|$)";
+ int ret;
+ regex_t *regex;
+
+ len = strlen (regstr);
+ for (i = 0; i < len; i++)
+ if (regstr[i] == '_')
+ magic++;
+
+ magic_str = XMALLOC (MTYPE_TMP, len + (14 * magic) + 1);
+
+ for (i = 0, j = 0; i < len; i++)
+ {
+ if (regstr[i] == '_')
+ {
+ memcpy (magic_str + j, magic_regexp, strlen (magic_regexp));
+ j += strlen (magic_regexp);
+ }
+ else
+ magic_str[j++] = regstr[i];
+ }
+ magic_str[j] = '\0';
+
+ regex = XMALLOC (MTYPE_BGP_REGEXP, sizeof (regex_t));
+
+ ret = regcomp (regex, magic_str, REG_EXTENDED);
+
+ XFREE (MTYPE_TMP, magic_str);
+
+ if (ret != 0)
+ {
+ XFREE (MTYPE_BGP_REGEXP, regex);
+ return NULL;
+ }
+
+ return regex;
+}
+
+int
+bgp_regexec (regex_t *regex, struct aspath *aspath)
+{
+ return regexec (regex, aspath->str, 0, NULL, 0);
+}
+
+void
+bgp_regex_free (regex_t *regex)
+{
+ regfree (regex);
+ XFREE (MTYPE_BGP_REGEXP, regex);
+}
diff --git a/bgpd/bgp_regex.h b/bgpd/bgp_regex.h
new file mode 100644
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 <zebra.h>
+
+#ifdef HAVE_GNU_REGEX
+#include <regex.h>
+#else
+#include "regex-gnu.h"
+#endif /* HAVE_GNU_REGEX */
+
+void bgp_regex_free (regex_t *regex);
+regex_t *bgp_regcomp (char *str);
+int bgp_regexec (regex_t *regex, struct aspath *aspath);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
new file mode 100644
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 <zebra.h>
+
+#include "prefix.h"
+#include "linklist.h"
+#include "memory.h"
+#include "command.h"
+#include "stream.h"
+#include "filter.h"
+#include "str.h"
+#include "log.h"
+#include "routemap.h"
+#include "buffer.h"
+#include "sockunion.h"
+#include "plist.h"
+#include "thread.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_regex.h"
+#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_clist.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_filter.h"
+#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_nexthop.h"
+#include "bgpd/bgp_damp.h"
+#include "bgpd/bgp_advertise.h"
+#include "bgpd/bgp_zebra.h"
+
+/* Extern from bgp_dump.c */
+extern char *bgp_origin_str[];
+extern char *bgp_origin_long_str[];
+
+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 <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+ return bgp_static_set (vty, vty->index, argv[0],
+ AFI_IP, bgp_node_safi (vty), NULL, 0);
+}
+
+DEFUN (bgp_network_route_map,
+ bgp_network_route_map_cmd,
+ "network A.B.C.D/M route-map WORD",
+ "Specify a network to announce via BGP\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+{
+ return bgp_static_set (vty, vty->index, argv[0],
+ AFI_IP, bgp_node_safi (vty), argv[1], 0);
+}
+
+DEFUN (bgp_network_backdoor,
+ bgp_network_backdoor_cmd,
+ "network A.B.C.D/M backdoor",
+ "Specify a network to announce via BGP\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Specify a BGP backdoor route\n")
+{
+ return bgp_static_set (vty, vty->index, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1);
+}
+
+DEFUN (bgp_network_mask,
+ bgp_network_mask_cmd,
+ "network A.B.C.D mask A.B.C.D",
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Network mask\n"
+ "Network mask\n")
+{
+ int ret;
+ char prefix_str[BUFSIZ];
+
+ ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+ if (! ret)
+ {
+ vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_static_set (vty, vty->index, prefix_str,
+ AFI_IP, bgp_node_safi (vty), NULL, 0);
+}
+
+DEFUN (bgp_network_mask_route_map,
+ bgp_network_mask_route_map_cmd,
+ "network A.B.C.D mask A.B.C.D route-map WORD",
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Network mask\n"
+ "Network mask\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+{
+ int ret;
+ char prefix_str[BUFSIZ];
+
+ ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+ if (! ret)
+ {
+ vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_static_set (vty, vty->index, prefix_str,
+ AFI_IP, bgp_node_safi (vty), argv[2], 0);
+}
+
+DEFUN (bgp_network_mask_backdoor,
+ bgp_network_mask_backdoor_cmd,
+ "network A.B.C.D mask A.B.C.D backdoor",
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Network mask\n"
+ "Network mask\n"
+ "Specify a BGP backdoor route\n")
+{
+ int ret;
+ char prefix_str[BUFSIZ];
+
+ ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+ if (! ret)
+ {
+ vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1);
+}
+
+DEFUN (bgp_network_mask_natural,
+ bgp_network_mask_natural_cmd,
+ "network A.B.C.D",
+ "Specify a network to announce via BGP\n"
+ "Network number\n")
+{
+ int ret;
+ char prefix_str[BUFSIZ];
+
+ ret = netmask_str2prefix_str (argv[0], NULL, prefix_str);
+ if (! ret)
+ {
+ vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_static_set (vty, vty->index, prefix_str,
+ AFI_IP, bgp_node_safi (vty), NULL, 0);
+}
+
+DEFUN (bgp_network_mask_natural_route_map,
+ bgp_network_mask_natural_route_map_cmd,
+ "network A.B.C.D route-map WORD",
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+{
+ int ret;
+ char prefix_str[BUFSIZ];
+
+ ret = netmask_str2prefix_str (argv[0], NULL, prefix_str);
+ if (! ret)
+ {
+ vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_static_set (vty, vty->index, prefix_str,
+ AFI_IP, bgp_node_safi (vty), argv[1], 0);
+}
+
+DEFUN (bgp_network_mask_natural_backdoor,
+ bgp_network_mask_natural_backdoor_cmd,
+ "network A.B.C.D backdoor",
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Specify a BGP backdoor route\n")
+{
+ int ret;
+ char prefix_str[BUFSIZ];
+
+ ret = netmask_str2prefix_str (argv[0], NULL, prefix_str);
+ if (! ret)
+ {
+ vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1);
+}
+
+DEFUN (no_bgp_network,
+ no_bgp_network_cmd,
+ "no network A.B.C.D/M",
+ NO_STR
+ "Specify a network to announce via BGP\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+ return bgp_static_unset (vty, vty->index, argv[0], AFI_IP,
+ bgp_node_safi (vty));
+}
+
+ALIAS (no_bgp_network,
+ no_bgp_network_route_map_cmd,
+ "no network A.B.C.D/M route-map WORD",
+ NO_STR
+ "Specify a network to announce via BGP\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+
+ALIAS (no_bgp_network,
+ no_bgp_network_backdoor_cmd,
+ "no network A.B.C.D/M backdoor",
+ NO_STR
+ "Specify a network to announce via BGP\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Specify a BGP backdoor route\n")
+
+DEFUN (no_bgp_network_mask,
+ no_bgp_network_mask_cmd,
+ "no network A.B.C.D mask A.B.C.D",
+ NO_STR
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Network mask\n"
+ "Network mask\n")
+{
+ int ret;
+ char prefix_str[BUFSIZ];
+
+ ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+ if (! ret)
+ {
+ vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP,
+ bgp_node_safi (vty));
+}
+
+ALIAS (no_bgp_network_mask,
+ no_bgp_network_mask_route_map_cmd,
+ "no network A.B.C.D mask A.B.C.D route-map WORD",
+ NO_STR
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Network mask\n"
+ "Network mask\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+
+ALIAS (no_bgp_network_mask,
+ no_bgp_network_mask_backdoor_cmd,
+ "no network A.B.C.D mask A.B.C.D backdoor",
+ NO_STR
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Network mask\n"
+ "Network mask\n"
+ "Specify a BGP backdoor route\n")
+
+DEFUN (no_bgp_network_mask_natural,
+ no_bgp_network_mask_natural_cmd,
+ "no network A.B.C.D",
+ NO_STR
+ "Specify a network to announce via BGP\n"
+ "Network number\n")
+{
+ int ret;
+ char prefix_str[BUFSIZ];
+
+ ret = netmask_str2prefix_str (argv[0], NULL, prefix_str);
+ if (! ret)
+ {
+ vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP,
+ bgp_node_safi (vty));
+}
+
+ALIAS (no_bgp_network_mask_natural,
+ no_bgp_network_mask_natural_route_map_cmd,
+ "no network A.B.C.D route-map WORD",
+ NO_STR
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+
+ALIAS (no_bgp_network_mask_natural,
+ no_bgp_network_mask_natural_backdoor_cmd,
+ "no network A.B.C.D backdoor",
+ NO_STR
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Specify a BGP backdoor route\n")
+
+#ifdef HAVE_IPV6
+DEFUN (ipv6_bgp_network,
+ ipv6_bgp_network_cmd,
+ "network X:X::X:X/M",
+ "Specify a network to announce via BGP\n"
+ "IPv6 prefix <network>/<length>\n")
+{
+ return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0);
+}
+
+DEFUN (ipv6_bgp_network_route_map,
+ ipv6_bgp_network_route_map_cmd,
+ "network X:X::X:X/M route-map WORD",
+ "Specify a network to announce via BGP\n"
+ "IPv6 prefix <network>/<length>\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+{
+ return bgp_static_set (vty, vty->index, argv[0], AFI_IP6,
+ bgp_node_safi (vty), argv[1], 0);
+}
+
+DEFUN (no_ipv6_bgp_network,
+ no_ipv6_bgp_network_cmd,
+ "no network X:X::X:X/M",
+ NO_STR
+ "Specify a network to announce via BGP\n"
+ "IPv6 prefix <network>/<length>\n")
+{
+ return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST);
+}
+
+ALIAS (no_ipv6_bgp_network,
+ no_ipv6_bgp_network_route_map_cmd,
+ "no network X:X::X:X/M route-map WORD",
+ NO_STR
+ "Specify a network to announce via BGP\n"
+ "IPv6 prefix <network>/<length>\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+
+ALIAS (ipv6_bgp_network,
+ old_ipv6_bgp_network_cmd,
+ "ipv6 bgp network X:X::X:X/M",
+ IPV6_STR
+ BGP_STR
+ "Specify a network to announce via BGP\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+
+ALIAS (no_ipv6_bgp_network,
+ old_no_ipv6_bgp_network_cmd,
+ "no ipv6 bgp network X:X::X:X/M",
+ NO_STR
+ IPV6_STR
+ BGP_STR
+ "Specify a network to announce via BGP\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+#endif /* HAVE_IPV6 */
+
+/* Aggreagete address:
+
+ advertise-map Set condition to advertise attribute
+ as-set Generate AS set path information
+ attribute-map Set attributes of aggregate
+ route-map Set parameters of aggregate
+ summary-only Filter more specific routes from updates
+ suppress-map Conditionally filter more specific routes from updates
+ <cr>
+ */
+struct bgp_aggregate
+{
+ /* Summary-only flag. */
+ u_char summary_only;
+
+ /* AS set generation. */
+ u_char as_set;
+
+ /* Route-map for aggregated route. */
+ struct route_map *map;
+
+ /* Suppress-count. */
+ unsigned long count;
+
+ /* SAFI configuration. */
+ safi_t safi;
+};
+
+struct bgp_aggregate *
+bgp_aggregate_new ()
+{
+ struct bgp_aggregate *new;
+ new = XMALLOC (MTYPE_BGP_AGGREGATE, sizeof (struct bgp_aggregate));
+ memset (new, 0, sizeof (struct bgp_aggregate));
+ return new;
+}
+
+void
+bgp_aggregate_free (struct bgp_aggregate *aggregate)
+{
+ XFREE (MTYPE_BGP_AGGREGATE, aggregate);
+}
+
+void
+bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew,
+ afi_t afi, safi_t safi, struct bgp_info *del,
+ struct bgp_aggregate *aggregate)
+{
+ struct bgp_table *table;
+ struct bgp_node *top;
+ struct bgp_node *rn;
+ u_char origin;
+ struct aspath *aspath = NULL;
+ struct aspath *asmerge = NULL;
+ struct community *community = NULL;
+ struct community *commerge = NULL;
+ struct in_addr nexthop;
+ u_int32_t med = 0;
+ struct bgp_info *ri;
+ struct bgp_info *new;
+ int first = 1;
+ unsigned long match = 0;
+
+ /* Record adding route's nexthop and med. */
+ if (rinew)
+ {
+ nexthop = rinew->attr->nexthop;
+ med = rinew->attr->med;
+ }
+
+ /* ORIGIN attribute: If at least one route among routes that are
+ aggregated has ORIGIN with the value INCOMPLETE, then the
+ aggregated route must have the ORIGIN attribute with the value
+ INCOMPLETE. Otherwise, if at least one route among routes that
+ are aggregated has ORIGIN with the value EGP, then the aggregated
+ route must have the origin attribute with the value EGP. In all
+ other case the value of the ORIGIN attribute of the aggregated
+ route is INTERNAL. */
+ origin = BGP_ORIGIN_IGP;
+
+ table = bgp->rib[afi][safi];
+
+ top = bgp_node_get (table, p);
+ for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top))
+ if (rn->p.prefixlen > p->prefixlen)
+ {
+ match = 0;
+
+ for (ri = rn->info; ri; ri = ri->next)
+ {
+ if (BGP_INFO_HOLDDOWN (ri))
+ continue;
+
+ if (del && ri == del)
+ continue;
+
+ if (! rinew && first)
+ {
+ nexthop = ri->attr->nexthop;
+ med = ri->attr->med;
+ first = 0;
+ }
+
+#ifdef AGGREGATE_NEXTHOP_CHECK
+ if (! IPV4_ADDR_SAME (&ri->attr->nexthop, &nexthop)
+ || ri->attr->med != med)
+ {
+ if (aspath)
+ aspath_free (aspath);
+ if (community)
+ community_free (community);
+ bgp_unlock_node (rn);
+ bgp_unlock_node (top);
+ return;
+ }
+#endif /* AGGREGATE_NEXTHOP_CHECK */
+
+ if (ri->sub_type != BGP_ROUTE_AGGREGATE)
+ {
+ if (aggregate->summary_only)
+ {
+ ri->suppress++;
+ SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
+ match++;
+ }
+
+ aggregate->count++;
+
+ if (aggregate->as_set)
+ {
+ if (origin < ri->attr->origin)
+ origin = ri->attr->origin;
+
+ if (aspath)
+ {
+ asmerge = aspath_aggregate (aspath, ri->attr->aspath);
+ aspath_free (aspath);
+ aspath = asmerge;
+ }
+ else
+ aspath = aspath_dup (ri->attr->aspath);
+
+ if (ri->attr->community)
+ {
+ if (community)
+ {
+ commerge = community_merge (community,
+ ri->attr->community);
+ community = community_uniq_sort (commerge);
+ community_free (commerge);
+ }
+ else
+ community = community_dup (ri->attr->community);
+ }
+ }
+ }
+ }
+ if (match)
+ bgp_process (bgp, rn, afi, safi);
+ }
+ bgp_unlock_node (top);
+
+ if (rinew)
+ {
+ aggregate->count++;
+
+ if (aggregate->summary_only)
+ rinew->suppress++;
+
+ if (aggregate->as_set)
+ {
+ if (origin < rinew->attr->origin)
+ origin = rinew->attr->origin;
+
+ if (aspath)
+ {
+ asmerge = aspath_aggregate (aspath, rinew->attr->aspath);
+ aspath_free (aspath);
+ aspath = asmerge;
+ }
+ else
+ aspath = aspath_dup (rinew->attr->aspath);
+
+ if (rinew->attr->community)
+ {
+ if (community)
+ {
+ commerge = community_merge (community,
+ rinew->attr->community);
+ community = community_uniq_sort (commerge);
+ community_free (commerge);
+ }
+ else
+ community = community_dup (rinew->attr->community);
+ }
+ }
+ }
+
+ if (aggregate->count > 0)
+ {
+ rn = bgp_node_get (table, p);
+ new = bgp_info_new ();
+ new->type = ZEBRA_ROUTE_BGP;
+ new->sub_type = BGP_ROUTE_AGGREGATE;
+ new->peer = bgp->peer_self;
+ SET_FLAG (new->flags, BGP_INFO_VALID);
+ new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set);
+ new->uptime = time (NULL);
+
+ bgp_info_add (rn, new);
+ bgp_process (bgp, rn, afi, safi);
+ }
+ else
+ {
+ if (aspath)
+ aspath_free (aspath);
+ if (community)
+ community_free (community);
+ }
+}
+
+void bgp_aggregate_delete (struct bgp *, struct prefix *, afi_t, safi_t,
+ struct bgp_aggregate *);
+
+void
+bgp_aggregate_increment (struct bgp *bgp, struct prefix *p,
+ struct bgp_info *ri, afi_t afi, safi_t safi)
+{
+ struct bgp_node *child;
+ struct bgp_node *rn;
+ struct bgp_aggregate *aggregate;
+
+ /* MPLS-VPN aggregation is not yet supported. */
+ if (safi == SAFI_MPLS_VPN)
+ return;
+
+ if (p->prefixlen == 0)
+ return;
+
+ if (BGP_INFO_HOLDDOWN (ri))
+ return;
+
+ child = bgp_node_get (bgp->aggregate[afi][safi], p);
+
+ /* Aggregate address configuration check. */
+ for (rn = child; rn; rn = rn->parent)
+ if ((aggregate = rn->info) != NULL && rn->p.prefixlen < p->prefixlen)
+ {
+ bgp_aggregate_delete (bgp, &rn->p, afi, safi, aggregate);
+ bgp_aggregate_route (bgp, &rn->p, ri, safi, safi, NULL, aggregate);
+ }
+ bgp_unlock_node (child);
+}
+
+void
+bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p,
+ struct bgp_info *del, afi_t afi, safi_t safi)
+{
+ struct bgp_node *child;
+ struct bgp_node *rn;
+ struct bgp_aggregate *aggregate;
+
+ /* MPLS-VPN aggregation is not yet supported. */
+ if (safi == SAFI_MPLS_VPN)
+ return;
+
+ if (p->prefixlen == 0)
+ return;
+
+ child = bgp_node_get (bgp->aggregate[afi][safi], p);
+
+ /* Aggregate address configuration check. */
+ for (rn = child; rn; rn = rn->parent)
+ if ((aggregate = rn->info) != NULL && rn->p.prefixlen < p->prefixlen)
+ {
+ bgp_aggregate_delete (bgp, &rn->p, afi, safi, aggregate);
+ bgp_aggregate_route (bgp, &rn->p, NULL, safi, safi, del, aggregate);
+ }
+ bgp_unlock_node (child);
+}
+
+void
+bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi,
+ struct bgp_aggregate *aggregate)
+{
+ struct bgp_table *table;
+ struct bgp_node *top;
+ struct bgp_node *rn;
+ struct bgp_info *new;
+ struct bgp_info *ri;
+ unsigned long match;
+ u_char origin = BGP_ORIGIN_IGP;
+ struct aspath *aspath = NULL;
+ struct aspath *asmerge = NULL;
+ struct community *community = NULL;
+ struct community *commerge = NULL;
+
+ table = bgp->rib[afi][safi];
+
+ /* Sanity check. */
+ if (afi == AFI_IP && p->prefixlen == IPV4_MAX_BITLEN)
+ return;
+ if (afi == AFI_IP6 && p->prefixlen == IPV6_MAX_BITLEN)
+ return;
+
+ /* If routes exists below this node, generate aggregate routes. */
+ top = bgp_node_get (table, p);
+ for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top))
+ if (rn->p.prefixlen > p->prefixlen)
+ {
+ match = 0;
+
+ for (ri = rn->info; ri; ri = ri->next)
+ {
+ if (BGP_INFO_HOLDDOWN (ri))
+ continue;
+
+ if (ri->sub_type != BGP_ROUTE_AGGREGATE)
+ {
+ /* summary-only aggregate route suppress aggregated
+ route announcement. */
+ if (aggregate->summary_only)
+ {
+ ri->suppress++;
+ SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
+ match++;
+ }
+ /* as-set aggregate route generate origin, as path,
+ community aggregation. */
+ if (aggregate->as_set)
+ {
+ if (origin < ri->attr->origin)
+ origin = ri->attr->origin;
+
+ if (aspath)
+ {
+ asmerge = aspath_aggregate (aspath, ri->attr->aspath);
+ aspath_free (aspath);
+ aspath = asmerge;
+ }
+ else
+ aspath = aspath_dup (ri->attr->aspath);
+
+ if (ri->attr->community)
+ {
+ if (community)
+ {
+ commerge = community_merge (community,
+ ri->attr->community);
+ community = community_uniq_sort (commerge);
+ community_free (commerge);
+ }
+ else
+ community = community_dup (ri->attr->community);
+ }
+ }
+ aggregate->count++;
+ }
+ }
+
+ /* If this node is suppressed, process the change. */
+ if (match)
+ bgp_process (bgp, rn, afi, safi);
+ }
+ bgp_unlock_node (top);
+
+ /* Add aggregate route to BGP table. */
+ if (aggregate->count)
+ {
+ rn = bgp_node_get (table, p);
+
+ new = bgp_info_new ();
+ new->type = ZEBRA_ROUTE_BGP;
+ new->sub_type = BGP_ROUTE_AGGREGATE;
+ new->peer = bgp->peer_self;
+ SET_FLAG (new->flags, BGP_INFO_VALID);
+ new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set);
+ new->uptime = time (NULL);
+
+ bgp_info_add (rn, new);
+
+ /* Process change. */
+ bgp_process (bgp, rn, afi, safi);
+ }
+}
+
+void
+bgp_aggregate_delete (struct bgp *bgp, struct prefix *p, afi_t afi,
+ safi_t safi, struct bgp_aggregate *aggregate)
+{
+ struct bgp_table *table;
+ struct bgp_node *top;
+ struct bgp_node *rn;
+ struct bgp_info *ri;
+ unsigned long match;
+
+ table = bgp->rib[afi][safi];
+
+ if (afi == AFI_IP && p->prefixlen == IPV4_MAX_BITLEN)
+ return;
+ if (afi == AFI_IP6 && p->prefixlen == IPV6_MAX_BITLEN)
+ return;
+
+ /* If routes exists below this node, generate aggregate routes. */
+ top = bgp_node_get (table, p);
+ for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top))
+ if (rn->p.prefixlen > p->prefixlen)
+ {
+ match = 0;
+
+ for (ri = rn->info; ri; ri = ri->next)
+ {
+ if (BGP_INFO_HOLDDOWN (ri))
+ continue;
+
+ if (ri->sub_type != BGP_ROUTE_AGGREGATE)
+ {
+ if (aggregate->summary_only)
+ {
+ ri->suppress--;
+
+ if (ri->suppress == 0)
+ {
+ SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
+ match++;
+ }
+ }
+ aggregate->count--;
+ }
+ }
+
+ /* If this node is suppressed, process the change. */
+ if (match)
+ bgp_process (bgp, rn, afi, safi);
+ }
+ bgp_unlock_node (top);
+
+ /* Delete aggregate route from BGP table. */
+ rn = bgp_node_get (table, p);
+
+ for (ri = rn->info; ri; ri = ri->next)
+ if (ri->peer == bgp->peer_self
+ && ri->type == ZEBRA_ROUTE_BGP
+ && ri->sub_type == BGP_ROUTE_AGGREGATE)
+ break;
+
+ /* Withdraw static BGP route from routing table. */
+ if (ri)
+ {
+ UNSET_FLAG (ri->flags, BGP_INFO_VALID);
+ bgp_process (bgp, rn, afi, safi);
+ bgp_info_delete (rn, ri);
+ bgp_info_free (ri);
+ bgp_unlock_node (rn);
+ }
+
+ /* Unlock bgp_node_lookup. */
+ bgp_unlock_node (rn);
+}
+
+/* Aggregate route attribute. */
+#define AGGREGATE_SUMMARY_ONLY 1
+#define AGGREGATE_AS_SET 1
+
+int
+bgp_aggregate_set (struct vty *vty, char *prefix_str, afi_t afi, safi_t safi,
+ u_char summary_only, u_char as_set)
+{
+ int ret;
+ struct prefix p;
+ struct bgp_node *rn;
+ struct bgp *bgp;
+ struct bgp_aggregate *aggregate;
+
+ /* Convert string to prefix structure. */
+ ret = str2prefix (prefix_str, &p);
+ if (!ret)
+ {
+ vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ apply_mask (&p);
+
+ /* Get BGP structure. */
+ bgp = vty->index;
+
+ /* Old configuration check. */
+ rn = bgp_node_get (bgp->aggregate[afi][safi], &p);
+
+ if (rn->info)
+ {
+ vty_out (vty, "There is already same aggregate network.%s", VTY_NEWLINE);
+ bgp_unlock_node (rn);
+ return CMD_WARNING;
+ }
+
+ /* Make aggregate address structure. */
+ aggregate = bgp_aggregate_new ();
+ aggregate->summary_only = summary_only;
+ aggregate->as_set = as_set;
+ aggregate->safi = safi;
+ rn->info = aggregate;
+
+ /* Aggregate address insert into BGP routing table. */
+ if (safi & SAFI_UNICAST)
+ bgp_aggregate_add (bgp, &p, afi, SAFI_UNICAST, aggregate);
+ if (safi & SAFI_MULTICAST)
+ bgp_aggregate_add (bgp, &p, afi, SAFI_MULTICAST, aggregate);
+
+ return CMD_SUCCESS;
+}
+
+int
+bgp_aggregate_unset (struct vty *vty, char *prefix_str, afi_t afi, safi_t safi)
+{
+ int ret;
+ struct prefix p;
+ struct bgp_node *rn;
+ struct bgp *bgp;
+ struct bgp_aggregate *aggregate;
+
+ /* Convert string to prefix structure. */
+ ret = str2prefix (prefix_str, &p);
+ if (!ret)
+ {
+ vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ apply_mask (&p);
+
+ /* Get BGP structure. */
+ bgp = vty->index;
+
+ /* Old configuration check. */
+ rn = bgp_node_lookup (bgp->aggregate[afi][safi], &p);
+ if (! rn)
+ {
+ vty_out (vty, "%% There is no aggregate-address configuration.%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ aggregate = rn->info;
+ if (aggregate->safi & SAFI_UNICAST)
+ bgp_aggregate_delete (bgp, &p, afi, SAFI_UNICAST, aggregate);
+ if (aggregate->safi & SAFI_MULTICAST)
+ bgp_aggregate_delete (bgp, &p, afi, SAFI_MULTICAST, aggregate);
+
+ /* Unlock aggregate address configuration. */
+ rn->info = NULL;
+ bgp_aggregate_free (aggregate);
+ bgp_unlock_node (rn);
+ bgp_unlock_node (rn);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (aggregate_address,
+ aggregate_address_cmd,
+ "aggregate-address A.B.C.D/M",
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n")
+{
+ return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty), 0, 0);
+}
+
+DEFUN (aggregate_address_mask,
+ aggregate_address_mask_cmd,
+ "aggregate-address A.B.C.D A.B.C.D",
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n")
+{
+ int ret;
+ char prefix_str[BUFSIZ];
+
+ ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+
+ if (! ret)
+ {
+ vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty),
+ 0, 0);
+}
+
+DEFUN (aggregate_address_summary_only,
+ aggregate_address_summary_only_cmd,
+ "aggregate-address A.B.C.D/M summary-only",
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Filter more specific routes from updates\n")
+{
+ return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty),
+ AGGREGATE_SUMMARY_ONLY, 0);
+}
+
+DEFUN (aggregate_address_mask_summary_only,
+ aggregate_address_mask_summary_only_cmd,
+ "aggregate-address A.B.C.D A.B.C.D summary-only",
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n"
+ "Filter more specific routes from updates\n")
+{
+ int ret;
+ char prefix_str[BUFSIZ];
+
+ ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+
+ if (! ret)
+ {
+ vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty),
+ AGGREGATE_SUMMARY_ONLY, 0);
+}
+
+DEFUN (aggregate_address_as_set,
+ aggregate_address_as_set_cmd,
+ "aggregate-address A.B.C.D/M as-set",
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Generate AS set path information\n")
+{
+ return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty),
+ 0, AGGREGATE_AS_SET);
+}
+
+DEFUN (aggregate_address_mask_as_set,
+ aggregate_address_mask_as_set_cmd,
+ "aggregate-address A.B.C.D A.B.C.D as-set",
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n"
+ "Generate AS set path information\n")
+{
+ int ret;
+ char prefix_str[BUFSIZ];
+
+ ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+
+ if (! ret)
+ {
+ vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty),
+ 0, AGGREGATE_AS_SET);
+}
+
+
+DEFUN (aggregate_address_as_set_summary,
+ aggregate_address_as_set_summary_cmd,
+ "aggregate-address A.B.C.D/M as-set summary-only",
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Generate AS set path information\n"
+ "Filter more specific routes from updates\n")
+{
+ return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty),
+ AGGREGATE_SUMMARY_ONLY, AGGREGATE_AS_SET);
+}
+
+ALIAS (aggregate_address_as_set_summary,
+ aggregate_address_summary_as_set_cmd,
+ "aggregate-address A.B.C.D/M summary-only as-set",
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Filter more specific routes from updates\n"
+ "Generate AS set path information\n")
+
+DEFUN (aggregate_address_mask_as_set_summary,
+ aggregate_address_mask_as_set_summary_cmd,
+ "aggregate-address A.B.C.D A.B.C.D as-set summary-only",
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n"
+ "Generate AS set path information\n"
+ "Filter more specific routes from updates\n")
+{
+ int ret;
+ char prefix_str[BUFSIZ];
+
+ ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+
+ if (! ret)
+ {
+ vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty),
+ AGGREGATE_SUMMARY_ONLY, AGGREGATE_AS_SET);
+}
+
+ALIAS (aggregate_address_mask_as_set_summary,
+ aggregate_address_mask_summary_as_set_cmd,
+ "aggregate-address A.B.C.D A.B.C.D summary-only as-set",
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n"
+ "Filter more specific routes from updates\n"
+ "Generate AS set path information\n")
+
+DEFUN (no_aggregate_address,
+ no_aggregate_address_cmd,
+ "no aggregate-address A.B.C.D/M",
+ NO_STR
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n")
+{
+ return bgp_aggregate_unset (vty, argv[0], AFI_IP, bgp_node_safi (vty));
+}
+
+ALIAS (no_aggregate_address,
+ no_aggregate_address_summary_only_cmd,
+ "no aggregate-address A.B.C.D/M summary-only",
+ NO_STR
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Filter more specific routes from updates\n")
+
+ALIAS (no_aggregate_address,
+ no_aggregate_address_as_set_cmd,
+ "no aggregate-address A.B.C.D/M as-set",
+ NO_STR
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Generate AS set path information\n")
+
+ALIAS (no_aggregate_address,
+ no_aggregate_address_as_set_summary_cmd,
+ "no aggregate-address A.B.C.D/M as-set summary-only",
+ NO_STR
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Generate AS set path information\n"
+ "Filter more specific routes from updates\n")
+
+ALIAS (no_aggregate_address,
+ no_aggregate_address_summary_as_set_cmd,
+ "no aggregate-address A.B.C.D/M summary-only as-set",
+ NO_STR
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Filter more specific routes from updates\n"
+ "Generate AS set path information\n")
+
+DEFUN (no_aggregate_address_mask,
+ no_aggregate_address_mask_cmd,
+ "no aggregate-address A.B.C.D A.B.C.D",
+ NO_STR
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n")
+{
+ int ret;
+ char prefix_str[BUFSIZ];
+
+ ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+
+ if (! ret)
+ {
+ vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_aggregate_unset (vty, prefix_str, AFI_IP, bgp_node_safi (vty));
+}
+
+ALIAS (no_aggregate_address_mask,
+ no_aggregate_address_mask_summary_only_cmd,
+ "no aggregate-address A.B.C.D A.B.C.D summary-only",
+ NO_STR
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n"
+ "Filter more specific routes from updates\n")
+
+ALIAS (no_aggregate_address_mask,
+ no_aggregate_address_mask_as_set_cmd,
+ "no aggregate-address A.B.C.D A.B.C.D as-set",
+ NO_STR
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n"
+ "Generate AS set path information\n")
+
+ALIAS (no_aggregate_address_mask,
+ no_aggregate_address_mask_as_set_summary_cmd,
+ "no aggregate-address A.B.C.D A.B.C.D as-set summary-only",
+ NO_STR
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n"
+ "Generate AS set path information\n"
+ "Filter more specific routes from updates\n")
+
+ALIAS (no_aggregate_address_mask,
+ no_aggregate_address_mask_summary_as_set_cmd,
+ "no aggregate-address A.B.C.D A.B.C.D summary-only as-set",
+ NO_STR
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n"
+ "Filter more specific routes from updates\n"
+ "Generate AS set path information\n")
+
+#ifdef HAVE_IPV6
+DEFUN (ipv6_aggregate_address,
+ ipv6_aggregate_address_cmd,
+ "aggregate-address X:X::X:X/M",
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n")
+{
+ return bgp_aggregate_set (vty, argv[0], AFI_IP6, SAFI_UNICAST, 0, 0);
+}
+
+DEFUN (ipv6_aggregate_address_summary_only,
+ ipv6_aggregate_address_summary_only_cmd,
+ "aggregate-address X:X::X:X/M summary-only",
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Filter more specific routes from updates\n")
+{
+ return bgp_aggregate_set (vty, argv[0], AFI_IP6, SAFI_UNICAST,
+ AGGREGATE_SUMMARY_ONLY, 0);
+}
+
+DEFUN (no_ipv6_aggregate_address,
+ no_ipv6_aggregate_address_cmd,
+ "no aggregate-address X:X::X:X/M",
+ NO_STR
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n")
+{
+ return bgp_aggregate_unset (vty, argv[0], AFI_IP6, SAFI_UNICAST);
+}
+
+DEFUN (no_ipv6_aggregate_address_summary_only,
+ no_ipv6_aggregate_address_summary_only_cmd,
+ "no aggregate-address X:X::X:X/M summary-only",
+ NO_STR
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Filter more specific routes from updates\n")
+{
+ return bgp_aggregate_unset (vty, argv[0], AFI_IP6, SAFI_UNICAST);
+}
+
+ALIAS (ipv6_aggregate_address,
+ old_ipv6_aggregate_address_cmd,
+ "ipv6 bgp aggregate-address X:X::X:X/M",
+ IPV6_STR
+ BGP_STR
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n")
+
+ALIAS (ipv6_aggregate_address_summary_only,
+ old_ipv6_aggregate_address_summary_only_cmd,
+ "ipv6 bgp aggregate-address X:X::X:X/M summary-only",
+ IPV6_STR
+ BGP_STR
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Filter more specific routes from updates\n")
+
+ALIAS (no_ipv6_aggregate_address,
+ old_no_ipv6_aggregate_address_cmd,
+ "no ipv6 bgp aggregate-address X:X::X:X/M",
+ NO_STR
+ IPV6_STR
+ BGP_STR
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n")
+
+ALIAS (no_ipv6_aggregate_address_summary_only,
+ old_no_ipv6_aggregate_address_summary_only_cmd,
+ "no ipv6 bgp aggregate-address X:X::X:X/M summary-only",
+ NO_STR
+ IPV6_STR
+ BGP_STR
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Filter more specific routes from updates\n")
+#endif /* HAVE_IPV6 */
+
+/* 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 <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1);
+}
+
+DEFUN (show_ip_bgp_ipv4_prefix,
+ show_ip_bgp_ipv4_prefix_cmd,
+ "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+ if (strncmp (argv[0], "m", 1) == 0)
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1);
+
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1);
+}
+
+DEFUN (show_ip_bgp_vpnv4_all_prefix,
+ show_ip_bgp_vpnv4_all_prefix_cmd,
+ "show ip bgp vpnv4 all A.B.C.D/M",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display VPNv4 NLRI specific information\n"
+ "Display information about all VPNv4 NLRIs\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1);
+}
+
+DEFUN (show_ip_bgp_vpnv4_rd_prefix,
+ show_ip_bgp_vpnv4_rd_prefix_cmd,
+ "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D/M",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display VPNv4 NLRI specific information\n"
+ "Display information for a route distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+ int ret;
+ struct prefix_rd prd;
+
+ ret = str2prefix_rd (argv[0], &prd);
+ if (! ret)
+ {
+ vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 1);
+}
+
+DEFUN (show_ip_bgp_view,
+ show_ip_bgp_view_cmd,
+ "show ip bgp view WORD",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "BGP view\n"
+ "BGP view name\n")
+{
+ return bgp_show (vty, argv[0], AFI_IP, SAFI_UNICAST, bgp_show_type_normal);
+}
+
+DEFUN (show_ip_bgp_view_route,
+ show_ip_bgp_view_route_cmd,
+ "show ip bgp view WORD A.B.C.D",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "BGP view\n"
+ "BGP view name\n"
+ "Network in the BGP routing table to display\n")
+{
+ return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 0);
+}
+
+DEFUN (show_ip_bgp_view_prefix,
+ show_ip_bgp_view_prefix_cmd,
+ "show ip bgp view WORD A.B.C.D/M",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "BGP view\n"
+ "BGP view name\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+ return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 1);
+}
+
+#ifdef HAVE_IPV6
+DEFUN (show_bgp,
+ show_bgp_cmd,
+ "show bgp",
+ SHOW_STR
+ BGP_STR)
+{
+ return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal);
+}
+
+ALIAS (show_bgp,
+ show_bgp_ipv6_cmd,
+ "show bgp ipv6",
+ SHOW_STR
+ BGP_STR
+ "Address family\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp,
+ show_ipv6_bgp_cmd,
+ "show ipv6 bgp",
+ SHOW_STR
+ IP_STR
+ BGP_STR)
+{
+ return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal);
+}
+
+DEFUN (show_bgp_route,
+ show_bgp_route_cmd,
+ "show bgp X:X::X:X",
+ SHOW_STR
+ BGP_STR
+ "Network in the BGP routing table to display\n")
+{
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0);
+}
+
+ALIAS (show_bgp_route,
+ show_bgp_ipv6_route_cmd,
+ "show bgp ipv6 X:X::X:X",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Network in the BGP routing table to display\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_route,
+ show_ipv6_bgp_route_cmd,
+ "show ipv6 bgp X:X::X:X",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Network in the BGP routing table to display\n")
+{
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0);
+}
+
+DEFUN (show_bgp_prefix,
+ show_bgp_prefix_cmd,
+ "show bgp X:X::X:X/M",
+ SHOW_STR
+ BGP_STR
+ "IPv6 prefix <network>/<length>\n")
+{
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1);
+}
+
+ALIAS (show_bgp_prefix,
+ show_bgp_ipv6_prefix_cmd,
+ "show bgp ipv6 X:X::X:X/M",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "IPv6 prefix <network>/<length>\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_prefix,
+ show_ipv6_bgp_prefix_cmd,
+ "show ipv6 bgp X:X::X:X/M",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+{
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp,
+ show_ipv6_mbgp_cmd,
+ "show ipv6 mbgp",
+ SHOW_STR
+ IP_STR
+ MBGP_STR)
+{
+ return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, bgp_show_type_normal);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp_route,
+ show_ipv6_mbgp_route_cmd,
+ "show ipv6 mbgp X:X::X:X",
+ SHOW_STR
+ IP_STR
+ MBGP_STR
+ "Network in the MBGP routing table to display\n")
+{
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 0);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp_prefix,
+ show_ipv6_mbgp_prefix_cmd,
+ "show ipv6 mbgp X:X::X:X/M",
+ SHOW_STR
+ IP_STR
+ MBGP_STR
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+{
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 1);
+}
+#endif
+
+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 <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Display route and more specific routes\n")
+{
+ return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST,
+ bgp_show_type_prefix_longer);
+}
+
+DEFUN (show_ip_bgp_flap_prefix_longer,
+ show_ip_bgp_flap_prefix_longer_cmd,
+ "show ip bgp flap-statistics A.B.C.D/M longer-prefixes",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display flap statistics of routes\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Display route and more specific routes\n")
+{
+ return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST,
+ bgp_show_type_flap_prefix_longer);
+}
+
+DEFUN (show_ip_bgp_ipv4_prefix_longer,
+ show_ip_bgp_ipv4_prefix_longer_cmd,
+ "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Display route and more specific routes\n")
+{
+ if (strncmp (argv[0], "m", 1) == 0)
+ return bgp_show_prefix_longer (vty, argv[1], AFI_IP, SAFI_MULTICAST,
+ bgp_show_type_prefix_longer);
+
+ return bgp_show_prefix_longer (vty, argv[1], AFI_IP, SAFI_UNICAST,
+ bgp_show_type_prefix_longer);
+}
+
+DEFUN (show_ip_bgp_flap_address,
+ show_ip_bgp_flap_address_cmd,
+ "show ip bgp flap-statistics A.B.C.D",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display flap statistics of routes\n"
+ "Network in the BGP routing table to display\n")
+{
+ return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST,
+ bgp_show_type_flap_address);
+}
+
+DEFUN (show_ip_bgp_flap_prefix,
+ show_ip_bgp_flap_prefix_cmd,
+ "show ip bgp flap-statistics A.B.C.D/M",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display flap statistics of routes\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+ return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST,
+ bgp_show_type_flap_prefix);
+}
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_prefix_longer,
+ show_bgp_prefix_longer_cmd,
+ "show bgp X:X::X:X/M longer-prefixes",
+ SHOW_STR
+ BGP_STR
+ "IPv6 prefix <network>/<length>\n"
+ "Display route and more specific routes\n")
+{
+ return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST,
+ bgp_show_type_prefix_longer);
+}
+
+ALIAS (show_bgp_prefix_longer,
+ show_bgp_ipv6_prefix_longer_cmd,
+ "show bgp ipv6 X:X::X:X/M longer-prefixes",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "IPv6 prefix <network>/<length>\n"
+ "Display route and more specific routes\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_prefix_longer,
+ show_ipv6_bgp_prefix_longer_cmd,
+ "show ipv6 bgp X:X::X:X/M longer-prefixes",
+ SHOW_STR
+ IPV6_STR
+ BGP_STR
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Display route and more specific routes\n")
+{
+ return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST,
+ bgp_show_type_prefix_longer);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp_prefix_longer,
+ show_ipv6_mbgp_prefix_longer_cmd,
+ "show ipv6 mbgp X:X::X:X/M longer-prefixes",
+ SHOW_STR
+ IPV6_STR
+ MBGP_STR
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Display route and more specific routes\n")
+{
+ return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_MULTICAST,
+ bgp_show_type_prefix_longer);
+}
+#endif /* HAVE_IPV6 */
+
+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 <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+ return bgp_clear_damp_route (vty, NULL, argv[0], AFI_IP,
+ SAFI_UNICAST, NULL, 1);
+}
+
+DEFUN (clear_ip_bgp_dampening_address,
+ clear_ip_bgp_dampening_address_cmd,
+ "clear ip bgp dampening A.B.C.D",
+ CLEAR_STR
+ IP_STR
+ BGP_STR
+ "Clear route flap dampening information\n"
+ "Network to clear damping information\n")
+{
+ return bgp_clear_damp_route (vty, NULL, argv[0], AFI_IP,
+ SAFI_UNICAST, NULL, 0);
+}
+
+DEFUN (clear_ip_bgp_dampening_address_mask,
+ clear_ip_bgp_dampening_address_mask_cmd,
+ "clear ip bgp dampening A.B.C.D A.B.C.D",
+ CLEAR_STR
+ IP_STR
+ BGP_STR
+ "Clear route flap dampening information\n"
+ "Network to clear damping information\n"
+ "Network mask\n")
+{
+ int ret;
+ char prefix_str[BUFSIZ];
+
+ ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+ if (! ret)
+ {
+ vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_clear_damp_route (vty, NULL, prefix_str, AFI_IP,
+ SAFI_UNICAST, NULL, 0);
+}
+
+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 <zebra.h>
+
+#include "prefix.h"
+#include "filter.h"
+#include "routemap.h"
+#include "command.h"
+#include "linklist.h"
+#include "plist.h"
+#include "memory.h"
+#include "log.h"
+#ifdef HAVE_GNU_REGEX
+#include <regex.h>
+#else
+#include "regex-gnu.h"
+#endif /* HAVE_GNU_REGEX */
+#include "buffer.h"
+#include "sockunion.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_regex.h"
+#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_clist.h"
+#include "bgpd/bgp_filter.h"
+#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_ecommunity.h"
+
+/* Memo of route-map commands.
+
+o Cisco route-map
+
+ match as-path : Done
+ community : Done
+ interface : Not yet
+ ip address : Done
+ ip next-hop : Done
+ ip route-source : (This will not be implemented by bgpd)
+ ip prefix-list : Done
+ ipv6 address : Done
+ ipv6 next-hop : Done
+ ipv6 route-source: (This will not be implemented by bgpd)
+ ipv6 prefix-list : Done
+ length : (This will not be implemented by bgpd)
+ metric : Done
+ route-type : (This will not be implemented by bgpd)
+ tag : (This will not be implemented by bgpd)
+
+ set as-path prepend : Done
+ as-path tag : Not yet
+ automatic-tag : (This will not be implemented by bgpd)
+ community : Done
+ comm-list : Not yet
+ dampning : Not yet
+ default : (This will not be implemented by bgpd)
+ interface : (This will not be implemented by bgpd)
+ ip default : (This will not be implemented by bgpd)
+ ip next-hop : Done
+ ip precedence : (This will not be implemented by bgpd)
+ ip tos : (This will not be implemented by bgpd)
+ level : (This will not be implemented by bgpd)
+ local-preference : Done
+ metric : Done
+ metric-type : Not yet
+ origin : Done
+ tag : (This will not be implemented by bgpd)
+ weight : Done
+
+o Local extention
+
+ set ipv6 next-hop global: Done
+ set ipv6 next-hop local : Done
+
+*/
+
+/* `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 <zebra.h>
+
+#ifdef HAVE_SNMP
+#include <asn1.h>
+#include <snmp.h>
+#include <snmp_impl.h>
+
+#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "command.h"
+#include "thread.h"
+#include "smux.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_fsm.h"
+
+/* 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 <zebra.h>
+
+#include "prefix.h"
+#include "memory.h"
+#include "sockunion.h"
+#include "vty.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+
+void bgp_node_delete (struct bgp_node *);
+void bgp_table_free (struct bgp_table *);
+
+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 <zebra.h>
+
+#include "linklist.h"
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+#include "prefix.h"
+#include "zebra/zebra.h"
+#include "table.h"
+#include "log.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_dump.h"
+#include "bgpd/bgp_aspath.h"
+
+/* Static configuration of BGP annoucement. */
+struct route_table *bgp_static_ipv4;
+#ifdef HAVE_IPV6
+struct route_table *bgp_static_ipv6;
+#endif /* HAVE_IPV6 */
+
+/* Static annoucement peer. */
+struct peer *static_peer;
+
+/* Default value setting flag */
+#define VAL_LOCAL_PREF 0x01
+#define VAL_MED 0x02
+#define VAL_NEXT_HOP 0x04
+
+DEFUN (default_attr_localpref,
+ default_attr_localpref_cmd,
+ "default-attr local-pref NUMBER",
+ "Set default local preference value\n"
+ "Set default local preference value\n"
+ "Value\n")
+{
+ struct bgp *bgp;
+ long lpref;
+
+ bgp = (struct bgp *) vty->index;
+
+ lpref = strtol (argv[0], NULL, 10);
+
+ bgp->def |= VAL_LOCAL_PREF;
+ bgp->localpref = lpref;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_default_attr_localpref,
+ no_default_attr_localpref_cmd,
+ "no default-attr local-pref NUMBER",
+ NO_STR
+ "Unset default local preference value\n"
+ "Unset default local preference value\n"
+ "Value\n")
+{
+ struct bgp *bgp;
+
+ bgp = (struct bgp *) vty->index;
+
+ bgp->def &= ~DEFAULT_LOCAL_PREF;
+ bgp->localpref = 0;
+
+ return CMD_SUCCESS;
+}
+
+#ifdef HAVE_IPV6
+/* Network configuration for IPv6. */
+int
+bgp_network_config_ipv6 (struct vty *vty, char *address_str)
+{
+ int ret;
+ struct prefix p;
+ struct route_node *node;
+ struct bgp_info *bgp_info;
+
+ ret = str2prefix_ipv6 (address_str, (struct prefix_ipv6 *) &p);
+ if (!ret)
+ {
+ vty_out (vty, "Please specify valid address\r\n");
+ return CMD_WARNING;
+ }
+
+ apply_mask_ipv6 ((struct prefix_ipv6 *) &p);
+
+ node = route_node_get (bgp_static_ipv6, &p);
+ if (node->info)
+ {
+ vty_out (vty, "There is already same static announcement.\r\n");
+ route_unlock_node (node);
+ return CMD_WARNING;
+ }
+
+ bgp_info = bgp_info_new ();
+ bgp_info->type = ZEBRA_ROUTE_STATIC;
+ bgp_info->peer = static_peer;
+ bgp_info->attr = bgp_attr_make_default ();
+ node->info = bgp_info;
+
+ nlri_process (&p, bgp_info);
+
+ return CMD_SUCCESS;
+}
+#endif
+
+/* Configure static BGP network. */
+DEFUN (bgp_network,
+ bgp_network_cmd,
+ "network PREFIX",
+ "Announce network setup\n"
+ "Static network for bgp announcement\n")
+{
+ int ret;
+ struct bgp *bgp;
+ struct prefix p;
+ struct route_node *node;
+ struct bgp_info *bgp_info;
+
+ bgp = (struct bgp *) vty->index;
+
+ ret = str2prefix_ipv4 (argv[0], (struct prefix_ipv4 *) &p);
+ if (!ret)
+ {
+#ifdef HAVE_IPV6
+ return bgp_network_config_ipv6 (vty, argv[0]);
+#endif /* HAVE_IPV6 */
+
+ vty_out (vty, "Please specify address by a.b.c.d/mask\r\n");
+ return CMD_WARNING;
+ }
+
+ /* Make sure mask is applied. */
+ apply_mask ((struct prefix_ipv4 *) &p);
+
+ node = route_node_get (bgp_static_ipv4, &p);
+ if (node->info)
+ {
+ vty_out (vty, "There is already same static announcement.\r\n");
+ route_unlock_node (node);
+ return CMD_WARNING;
+ }
+
+ bgp_info = bgp_info_new ();
+ bgp_info->type = ZEBRA_ROUTE_STATIC;
+ bgp_info->peer = static_peer;
+ bgp_info->attr = bgp_attr_make_default ();
+ node->info = bgp_info;
+
+ nlri_process (&p, bgp_info);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_network,
+ no_bgp_network_cmd,
+ "no network PREFIX",
+ NO_STR
+ "Announce network setup\n"
+ "Delete static network for bgp announcement\n")
+{
+ int ret;
+ struct bgp *bgp;
+ struct route_node *np;
+ struct prefix_ipv4 p;
+
+ bgp = (struct bgp *) vty->index;
+
+ ret = str2prefix_ipv4 (argv[0], &p);
+ if (!ret)
+ {
+ vty_out (vty, "Please specify address by a.b.c.d/mask\r\n");
+ return CMD_WARNING;
+ }
+
+ apply_mask (&p);
+
+ np = route_node_get (bgp_static_ipv4, (struct prefix *) &p);
+ if (!np->info)
+ {
+ vty_out (vty, "Can't find specified static route configuration.\r\n");
+ route_unlock_node (np);
+ return CMD_WARNING;
+ }
+ nlri_delete (static_peer, (struct prefix *) &p);
+
+ /* bgp_attr_free (np->info); */
+ np->info = NULL;
+
+ route_unlock_node (np);
+
+ return CMD_SUCCESS;
+}
+
+int
+config_write_network (struct vty *vty, struct bgp *bgp)
+{
+ struct route_node *node;
+ struct bgp_route *route;
+ char buf[BUFSIZ];
+
+ for (node = route_top (bgp_static_ipv4); node; node = route_next (node))
+ for (route = node->info; route; route = route->next)
+ vty_out (vty, " network %s/%d%s",
+ inet_ntoa (node->p.u.prefix4), node->p.prefixlen, VTY_NEWLINE);
+#ifdef HAVE_IPV6
+ for (node = route_top (bgp_static_ipv6); node; node = route_next (node))
+ for (route = node->info; route; route = route->next)
+ vty_out (vty, " network %s/%d%s",
+ inet_ntop (AF_INET6, &node->p.u.prefix6, buf, BUFSIZ),
+ node->p.prefixlen, VTY_NEWLINE);
+#endif /* HAVE_IPV6 */
+
+ return 0;
+}
+
+void
+view_init ()
+{
+ bgp_static_ipv4 = route_table_init ();
+#ifdef HAVE_IPV6
+ bgp_static_ipv6 = route_table_init ();
+#endif /* HAVE_IPV6 */
+
+ static_peer = peer_new ();
+ static_peer->host = "Static annucement";
+
+ install_element (BGP_NODE, &bgp_network_cmd);
+ install_element (BGP_NODE, &no_bgp_network_cmd);
+ install_element (BGP_NODE, &default_attr_localpref_cmd);
+ install_element (BGP_NODE, &no_default_attr_localpref_cmd);
+}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
new file mode 100644
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 <zebra.h>
+
+#include "command.h"
+#include "prefix.h"
+#include "plist.h"
+#include "buffer.h"
+#include "linklist.h"
+#include "stream.h"
+#include "thread.h"
+#include "log.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_open.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_zebra.h"
+
+/* Utility function to get address family from current node. */
+afi_t
+bgp_node_afi (struct vty *vty)
+{
+ if (vty->node == BGP_IPV6_NODE)
+ return AFI_IP6;
+ return AFI_IP;
+}
+
+/* Utility function to get subsequent address family from current
+ node. */
+safi_t
+bgp_node_safi (struct vty *vty)
+{
+ if (vty->node == BGP_VPNV4_NODE)
+ return SAFI_MPLS_VPN;
+ if (vty->node == BGP_IPV4M_NODE)
+ return SAFI_MULTICAST;
+ return SAFI_UNICAST;
+}
+
+int
+peer_address_self_check (union sockunion *su)
+{
+ struct interface *ifp = NULL;
+
+ if (su->sa.sa_family == AF_INET)
+ ifp = if_lookup_by_ipv4_exact (&su->sin.sin_addr);
+#ifdef HAVE_IPV6
+ else if (su->sa.sa_family == AF_INET6)
+ ifp = if_lookup_by_ipv6_exact (&su->sin6.sin6_addr);
+#endif /* HAVE IPV6 */
+
+ if (ifp)
+ return 1;
+
+ return 0;
+}
+
+/* Utility function for looking up peer from VTY. */
+struct peer *
+peer_lookup_vty (struct vty *vty, char *ip_str)
+{
+ int ret;
+ struct bgp *bgp;
+ union sockunion su;
+ struct peer *peer;
+
+ bgp = vty->index;
+
+ ret = str2sockunion (ip_str, &su);
+ if (ret < 0)
+ {
+ vty_out (vty, "%% Malformed address: %s%s", ip_str, VTY_NEWLINE);
+ return NULL;
+ }
+
+ peer = peer_lookup (bgp, &su);
+ if (! peer)
+ {
+ vty_out (vty, "%% Specify remote-as or peer-group commands first%s", VTY_NEWLINE);
+ return NULL;
+ }
+ return peer;
+}
+
+/* Utility function for looking up peer or peer group. */
+struct peer *
+peer_and_group_lookup_vty (struct vty *vty, char *peer_str)
+{
+ int ret;
+ struct bgp *bgp;
+ union sockunion su;
+ struct peer *peer;
+ struct peer_group *group;
+
+ bgp = vty->index;
+
+ ret = str2sockunion (peer_str, &su);
+ if (ret == 0)
+ {
+ peer = peer_lookup (bgp, &su);
+ if (peer)
+ return peer;
+ }
+ else
+ {
+ group = peer_group_lookup (bgp, peer_str);
+ if (group)
+ return group->conf;
+ }
+
+ vty_out (vty, "%% Specify remote-as or peer-group commands first%s",
+ VTY_NEWLINE);
+
+ return NULL;
+}
+
+int
+bgp_vty_return (struct vty *vty, int ret)
+{
+ char *str = NULL;
+
+ switch (ret)
+ {
+ case BGP_ERR_INVALID_VALUE:
+ str = "Invalid value";
+ break;
+ case BGP_ERR_INVALID_FLAG:
+ str = "Invalid flag";
+ break;
+ case BGP_ERR_PEER_INACTIVE:
+ str = "Activate the neighbor for the address family first";
+ break;
+ case BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER:
+ str = "Invalid command for a peer-group member";
+ break;
+ case BGP_ERR_PEER_GROUP_SHUTDOWN:
+ str = "Peer-group has been shutdown. Activate the peer-group first";
+ break;
+ case BGP_ERR_PEER_GROUP_HAS_THE_FLAG:
+ str = "This peer is a peer-group member. Please change peer-group configuration";
+ break;
+ case BGP_ERR_PEER_FLAG_CONFLICT:
+ str = "Can't set override-capability and strict-capability-match at the same time";
+ break;
+ case BGP_ERR_PEER_GROUP_MEMBER_EXISTS:
+ str = "No activate for peergroup can be given only if peer-group has no members";
+ break;
+ case BGP_ERR_PEER_BELONGS_TO_GROUP:
+ str = "No activate for an individual peer-group member is invalid";
+ break;
+ case BGP_ERR_PEER_GROUP_AF_UNCONFIGURED:
+ str = "Activate the peer-group for the address family first";
+ break;
+ case BGP_ERR_PEER_GROUP_NO_REMOTE_AS:
+ str = "Specify remote-as or peer-group remote AS first";
+ break;
+ case BGP_ERR_PEER_GROUP_CANT_CHANGE:
+ str = "Cannot change the peer-group. Deconfigure first";
+ break;
+ case BGP_ERR_PEER_GROUP_MISMATCH:
+ str = "Cannot have different peer-group for the neighbor";
+ break;
+ case BGP_ERR_PEER_FILTER_CONFLICT:
+ str = "Prefix/distribute list can not co-exist";
+ break;
+ case BGP_ERR_NOT_INTERNAL_PEER:
+ str = "Invalid command. Not an internal neighbor";
+ break;
+ case BGP_ERR_REMOVE_PRIVATE_AS:
+ str = "Private AS cannot be removed for IBGP peers";
+ break;
+ case BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP:
+ str = "Local-AS allowed only for EBGP peers";
+ break;
+ case BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS:
+ str = "Cannot have local-as same as BGP AS number";
+ break;
+ }
+ if (str)
+ {
+ vty_out (vty, "%% %s%s", str, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
+/* BGP global configuration. */
+
+DEFUN (bgp_multiple_instance_func,
+ bgp_multiple_instance_cmd,
+ "bgp multiple-instance",
+ BGP_STR
+ "Enable bgp multiple instance\n")
+{
+ bgp_option_set (BGP_OPT_MULTIPLE_INSTANCE);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_multiple_instance,
+ no_bgp_multiple_instance_cmd,
+ "no bgp multiple-instance",
+ NO_STR
+ BGP_STR
+ "BGP multiple instance\n")
+{
+ int ret;
+
+ ret = bgp_option_unset (BGP_OPT_MULTIPLE_INSTANCE);
+ if (ret < 0)
+ {
+ vty_out (vty, "%% There are more than two BGP instances%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (bgp_config_type,
+ bgp_config_type_cmd,
+ "bgp config-type (cisco|zebra)",
+ BGP_STR
+ "Configuration type\n"
+ "cisco\n"
+ "zebra\n")
+{
+ if (strncmp (argv[0], "c", 1) == 0)
+ bgp_option_set (BGP_OPT_CONFIG_CISCO);
+ else
+ bgp_option_unset (BGP_OPT_CONFIG_CISCO);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_config_type,
+ no_bgp_config_type_cmd,
+ "no bgp config-type",
+ NO_STR
+ BGP_STR
+ "Display configuration type\n")
+{
+ bgp_option_unset (BGP_OPT_CONFIG_CISCO);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_synchronization,
+ no_synchronization_cmd,
+ "no synchronization",
+ NO_STR
+ "Perform IGP synchronization\n")
+{
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_auto_summary,
+ no_auto_summary_cmd,
+ "no auto-summary",
+ NO_STR
+ "Enable automatic network number summarization\n")
+{
+ return CMD_SUCCESS;
+}
+
+/* "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 <zebra.h>
+
+#include "command.h"
+#include "stream.h"
+#include "network.h"
+#include "prefix.h"
+#include "log.h"
+#include "sockunion.h"
+#include "zclient.h"
+#include "routemap.h"
+#include "thread.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_nexthop.h"
+#include "bgpd/bgp_zebra.h"
+#include "bgpd/bgp_fsm.h"
+
+/* 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 <zebra.h>
+
+#include "prefix.h"
+#include "thread.h"
+#include "buffer.h"
+#include "stream.h"
+#include "command.h"
+#include "sockunion.h"
+#include "network.h"
+#include "memory.h"
+#include "filter.h"
+#include "routemap.h"
+#include "str.h"
+#include "log.h"
+#include "plist.h"
+#include "linklist.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_dump.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_regex.h"
+#include "bgpd/bgp_clist.h"
+#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_zebra.h"
+#include "bgpd/bgp_open.h"
+#include "bgpd/bgp_filter.h"
+#include "bgpd/bgp_nexthop.h"
+#include "bgpd/bgp_damp.h"
+#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_advertise.h"
+#include "bgpd/bgp_network.h"
+#include "bgpd/bgp_vty.h"
+#ifdef HAVE_SNMP
+#include "bgpd/bgp_snmp.h"
+#endif /* HAVE_SNMP */
+
+/* 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 <bothner@cygnus.com>.
+# Please send patches to <config-patches@gnu.org>.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of this system.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit"
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case "$1" in
+ --version | --vers* | -V )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ exec >&2
+ echo "$me: invalid option $1"
+ echo "$help"
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+
+dummy=dummy-$$
+trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15
+
+# Use $HOST_CC if defined. $CC may point to a cross-compiler
+if test x"$CC_FOR_BUILD" = x; then
+ if test x"$HOST_CC" != x; then
+ CC_FOR_BUILD="$HOST_CC"
+ else
+ if test x"$CC" != x; then
+ CC_FOR_BUILD="$CC"
+ else
+ echo 'int dummy(){}' >$dummy.c
+ for c in cc c89 gcc; do
+ ($c $dummy.c -c) >/dev/null 2>&1
+ if test $? = 0; then
+ CC_FOR_BUILD="$c"; break
+ fi
+ done
+ rm -f $dummy.c $dummy.o
+ if test x"$CC_FOR_BUILD" = x; then
+ CC_FOR_BUILD=no_compiler_found
+ fi
+ fi
+ fi
+fi
+
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # Netbsd (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ # Determine the machine/vendor (is the vendor relevant).
+ case "${UNAME_MACHINE}" in
+ amiga) machine=m68k-unknown ;;
+ arm32) machine=arm-unknown ;;
+ atari*) machine=m68k-atari ;;
+ sun3*) machine=m68k-sun ;;
+ mac68k) machine=m68k-apple ;;
+ macppc) machine=powerpc-apple ;;
+ hp3[0-9][05]) machine=m68k-hp ;;
+ ibmrt|romp-ibm) machine=romp-ibm ;;
+ *) machine=${UNAME_MACHINE}-unknown ;;
+ esac
+ # The Operating System including object format.
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ # The OS release
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit 0 ;;
+ alpha:OSF1:*:*)
+ if test $UNAME_RELEASE = "V4.0"; then
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ fi
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ cat <<EOF >$dummy.s
+ .data
+\$Lformat:
+ .byte 37,100,45,37,120,10,0 # "%d-%x\n"
+
+ .text
+ .globl main
+ .align 4
+ .ent main
+main:
+ .frame \$30,16,\$26,0
+ ldgp \$29,0(\$27)
+ .prologue 1
+ .long 0x47e03d80 # implver \$0
+ lda \$2,-1
+ .long 0x47e20c21 # amask \$2,\$1
+ lda \$16,\$Lformat
+ mov \$0,\$17
+ not \$1,\$18
+ jsr \$26,printf
+ ldgp \$29,0(\$26)
+ mov 0,\$16
+ jsr \$26,exit
+ .end main
+EOF
+ $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ case `./$dummy` in
+ 0-0)
+ UNAME_MACHINE="alpha"
+ ;;
+ 1-0)
+ UNAME_MACHINE="alphaev5"
+ ;;
+ 1-1)
+ UNAME_MACHINE="alphaev56"
+ ;;
+ 1-101)
+ UNAME_MACHINE="alphapca56"
+ ;;
+ 2-303)
+ UNAME_MACHINE="alphaev6"
+ ;;
+ 2-307)
+ UNAME_MACHINE="alphaev67"
+ ;;
+ esac
+ fi
+ rm -f $dummy.s $dummy
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit 0 ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit 0 ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit 0 ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit 0;;
+ amiga:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit 0 ;;
+ arc64:OpenBSD:*:*)
+ echo mips64el-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hkmips:OpenBSD:*:*)
+ echo mips-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ pmax:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sgi:OpenBSD:*:*)
+ echo mips-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ wgrisc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ SR2?01:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit 0;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit 0 ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit 0 ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit 0 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit 0 ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit 0 ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit 0 ;;
+ sun3*:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit 0 ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy \
+ && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+ && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit 0 ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit 0 ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit 0 ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit 0 ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit 0 ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit 0 ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit 0 ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit 0 ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i?86:AIX:*:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo rs6000-ibm-aix3.2.5
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit 0 ;;
+ *:AIX:*:4)
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=4.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit 0 ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit 0 ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit 0 ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit 0 ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit 0 ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit 0 ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit 0 ;;
+ 9000/[34678]??:HP-UX:*:*)
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
+ if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi
+ rm -f $dummy.c $dummy
+ esac
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo unknown-hitachi-hiuxwe2
+ exit 0 ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit 0 ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit 0 ;;
+ *9??*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit 0 ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit 0 ;;
+ i?86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit 0 ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit 0 ;;
+ hppa*:OpenBSD:*:*)
+ echo hppa-unknown-openbsd
+ exit 0 ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ CRAY*X-MP:*:*:*)
+ echo xmp-cray-unicos
+ exit 0 ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+ exit 0 ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*T3E:*:*:*)
+ echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY-2:*:*:*)
+ echo cray2-cray-unicos
+ exit 0 ;;
+ F300:UNIX_System_V:*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit 0 ;;
+ F301:UNIX_System_V:*:*)
+ echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
+ exit 0 ;;
+ hp300:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ i?86:BSD/386:*:* | i?86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:FreeBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit 0 ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit 0 ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit 0 ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i386-pc-interix
+ exit 0 ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit 0 ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit 0 ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ *:GNU:*:*)
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit 0 ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit 0 ;;
+ *:Linux:*:*)
+
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ ld_supported_emulations=`cd /; ld --help 2>&1 \
+ | sed -ne '/supported emulations:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported emulations: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_emulations" in
+ *ia64)
+ echo "${UNAME_MACHINE}-unknown-linux"
+ exit 0
+ ;;
+ i?86linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit 0
+ ;;
+ elf_i?86)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ i?86coff)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit 0
+ ;;
+ sparclinux)
+ echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
+ exit 0
+ ;;
+ elf32_sparc)
+ echo "${UNAME_MACHINE}-unknown-linux-gnu"
+ exit 0
+ ;;
+ armlinux)
+ echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
+ exit 0
+ ;;
+ elf32arm*)
+ echo "${UNAME_MACHINE}-unknown-linux-gnuoldld"
+ exit 0
+ ;;
+ armelf_linux*)
+ echo "${UNAME_MACHINE}-unknown-linux-gnu"
+ exit 0
+ ;;
+ m68klinux)
+ echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
+ exit 0
+ ;;
+ elf32ppc | elf32ppclinux)
+ # Determine Lib Version
+ cat >$dummy.c <<EOF
+#include <features.h>
+#if defined(__GLIBC__)
+extern char __libc_version[];
+extern char __libc_release[];
+#endif
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+#if defined(__GLIBC__)
+ printf("%s %s\n", __libc_version, __libc_release);
+#else
+ printf("unkown\n");
+#endif
+ return 0;
+}
+EOF
+ LIBC=""
+ $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ ./$dummy | grep 1\.99 > /dev/null
+ if test "$?" = 0 ; then
+ LIBC="libc1"
+ fi
+ fi
+ rm -f $dummy.c $dummy
+ echo powerpc-unknown-linux-gnu${LIBC}
+ exit 0
+ ;;
+ shelf_linux)
+ echo "${UNAME_MACHINE}-unknown-linux-gnu"
+ exit 0
+ ;;
+ esac
+
+ if test "${UNAME_MACHINE}" = "alpha" ; then
+ cat <<EOF >$dummy.s
+ .data
+ \$Lformat:
+ .byte 37,100,45,37,120,10,0 # "%d-%x\n"
+
+ .text
+ .globl main
+ .align 4
+ .ent main
+ main:
+ .frame \$30,16,\$26,0
+ ldgp \$29,0(\$27)
+ .prologue 1
+ .long 0x47e03d80 # implver \$0
+ lda \$2,-1
+ .long 0x47e20c21 # amask \$2,\$1
+ lda \$16,\$Lformat
+ mov \$0,\$17
+ not \$1,\$18
+ jsr \$26,printf
+ ldgp \$29,0(\$26)
+ mov 0,\$16
+ jsr \$26,exit
+ .end main
+EOF
+ LIBC=""
+ $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ case `./$dummy` in
+ 0-0)
+ UNAME_MACHINE="alpha"
+ ;;
+ 1-0)
+ UNAME_MACHINE="alphaev5"
+ ;;
+ 1-1)
+ UNAME_MACHINE="alphaev56"
+ ;;
+ 1-101)
+ UNAME_MACHINE="alphapca56"
+ ;;
+ 2-303)
+ UNAME_MACHINE="alphaev6"
+ ;;
+ 2-307)
+ UNAME_MACHINE="alphaev67"
+ ;;
+ esac
+
+ objdump --private-headers $dummy | \
+ grep ld.so.1 > /dev/null
+ if test "$?" = 0 ; then
+ LIBC="libc1"
+ fi
+ fi
+ rm -f $dummy.s $dummy
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0
+ elif test "${UNAME_MACHINE}" = "mips" ; then
+ cat >$dummy.c <<EOF
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __MIPSEB__
+ printf ("%s-unknown-linux-gnu\n", argv[1]);
+#endif
+#ifdef __MIPSEL__
+ printf ("%sel-unknown-linux-gnu\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ elif test "${UNAME_MACHINE}" = "s390"; then
+ echo s390-ibm-linux && exit 0
+ elif test "${UNAME_MACHINE}" = "x86_64"; then
+ echo x86_64-unknown-linux-gnu && exit 0
+ elif test "${UNAME_MACHINE}" = "parisc" -o "${UNAME_MACHINE}" = "hppa"; then
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*)
+ echo hppa1.1-unknown-linux-gnu
+ ;;
+ PA8*)
+ echo hppa2.0-unknown-linux-gnu
+ ;;
+ *)
+ echo hppa-unknown-linux-gnu
+ ;;
+ esac
+ exit 0
+ else
+ # Either a pre-BFD a.out linker (linux-gnuoldld)
+ # or one that does not give us useful --help.
+ # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
+ # If ld does not provide *any* "supported emulations:"
+ # that means it is gnuoldld.
+ test -z "$ld_supported_emulations" \
+ && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
+
+ case "${UNAME_MACHINE}" in
+ i?86)
+ VENDOR=pc;
+ ;;
+ *)
+ VENDOR=unknown;
+ ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ cat >$dummy.c <<EOF
+#include <features.h>
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __ELF__
+# ifdef __GLIBC__
+# if __GLIBC__ >= 2
+ printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
+# else
+ printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+# else
+ printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+#else
+ printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+ fi ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+ i?86:DYNIX/ptx:4*:*)
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i?86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit 0 ;;
+ i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit 0 ;;
+ i?86:*:5:7*)
+ # Fixed at (any) Pentium or better
+ UNAME_MACHINE=i586
+ if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then
+ echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ i?86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit 0 ;;
+ i?86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit 0 ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit 0 ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit 0 ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit 0 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit 0 ;;
+ M68*:*:R3V[567]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ m68*:LynxOS:2.*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit 0 ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit 0 ;;
+ PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit 0 ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit 0 ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit 0 ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit 0 ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit 0 ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit 0 ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit 0 ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit 0 ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Darwin:*:*)
+ echo `uname -p`-apple-darwin${UNAME_RELEASE}
+ exit 0 ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ if test "${UNAME_MACHINE}" = "x86pc"; then
+ UNAME_MACHINE=pc
+ fi
+ echo `uname -p`-${UNAME_MACHINE}-nto-qnx
+ exit 0 ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit 0 ;;
+ NSR-[KW]:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit 0 ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit 0 ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit 0 ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit 0 ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+ printf ("vax-dec-bsd\n"); exit (0);
+#else
+ printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0
+rm -f $dummy.c $dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ c34*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ c38*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ c4*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+The $version version of this script cannot recognize your system type.
+Please download the most up to date version of the config scripts:
+
+ ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess version = $version
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "version='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config.h.in b/config.h.in
new file mode 100644
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 <kunihiro@zebra.org> */
+
+/* Version of GNU Zebra */
+#undef VERSION
+
+/* Solaris on x86. */
+#undef SOLARIS_X86
+
+/* Package name of GNU Zebra */
+#undef PACKAGE
+
+/* Define if host is GNU/Linux */
+#undef GNU_LINUX
+
+/* Define if you have the AF_ROUTE socket. */
+#undef HAVE_AF_ROUTE
+
+/* Define if you have the inet_aton function. */
+#undef HAVE_INET_ATON
+
+/* Define if you have the inet_ntop function. */
+#undef HAVE_INET_NTOP
+
+/* Define if you have the inet_pton function. */
+#undef HAVE_INET_PTON
+
+/* Define if you have the setproctitle function. */
+#undef HAVE_SETPROCTITLE
+
+/* Define if you have ipv6 stack. */
+#undef HAVE_IPV6
+
+/* Define if you wish to support ipv6 router advertisment. */
+/* #undef HAVE_RTADV */
+
+/* whether system has GNU regex */
+#undef HAVE_GNU_REGEX
+
+/* whether system has SNMP library */
+#undef HAVE_SNMP
+
+/* whether sockaddr has a sa_len field */
+#undef HAVE_SA_LEN
+
+/* whether sockaddr_in has a sin_len field */
+#undef HAVE_SIN_LEN
+
+/* whether sockaddr_un has a sun_len field */
+#undef HAVE_SUN_LEN
+
+/* whether sockaddr_in6 has a sin6_scope_id field */
+#undef HAVE_SIN6_SCOPE_ID
+
+/* Define if there is socklen_t. */
+#undef HAVE_SOCKLEN_T
+
+/* Define if there is sockaddr_dl structure. */
+#undef HAVE_SOCKADDR_DL
+
+/* Define if there is ifaliasreq structure. */
+#undef HAVE_IFALIASREQ
+
+/* Define if there is in6_aliasreq structure. */
+#undef HAVE_IN6_ALIASREQ
+
+/* Define if there is rt_addrinfo structure. */
+#undef HAVE_RT_ADDRINFO
+
+/* Define if there is in_pktinfo structure. */
+#undef HAVE_INPKTINFO
+
+/* Define if you have the getrusage function. */
+#undef HAVE_RUSAGE
+
+/* Define if /proc/net/dev exists. */
+#undef HAVE_PROC_NET_DEV
+
+/* Define if /proc/net/if_inet6 exists. */
+#undef HAVE_PROC_NET_IF_INET6
+
+/* Define if NET_RT_IFLIST exists in sys/socket.h. */
+#undef HAVE_NET_RT_IFLIST
+
+/* Define if you have INRIA ipv6 stack. */
+#undef INRIA_IPV6
+
+/* Define if you have KAME project ipv6 stack. */
+#undef KAME
+
+/* Define if you have Linux ipv6 stack. */
+#undef LINUX_IPV6
+
+/* Define if you have NRL ipv6 stack. */
+#undef NRL
+
+/* Define if you have BSDI NRL IPv6 stack. */
+#undef BSDI_NRL
+
+/* Define if one-vty option is specified. */
+#undef VTYSH
+
+/* Define if interface aliases don't have distinct indeces */
+#undef HAVE_BROKEN_ALIASES
+
+/* Define if disable-bgp-announce option is specified. */
+#undef DISABLE_BGP_ANNOUNCE
+
+/* PAM support */
+#undef USE_PAM
+
+/* TCP/IP communication between zebra and protocol daemon. */
+#undef HAVE_TCP_ZEBRA
+
+/* The OSPF NSSA option (RFC1587). */
+#undef HAVE_NSSA
+
+/* The OSPF Opaque LSA option (RFC2370). */
+#undef HAVE_OPAQUE_LSA
+
+/* Traffic Engineering Extension to OSPF
+ (draft-katz-yeung-ospf-traffic-06.txt). */
+#undef HAVE_OSPF_TE
+
+/* Linux netlink. */
+#undef HAVE_NETLINK
+
+/* PATHS */
+#undef PATH_ZEBRA_PID
+#undef PATH_RIPD_PID
+#undef PATH_RIPNGD_PID
+#undef PATH_BGPD_PID
+#undef PATH_OSPFD_PID
+#undef PATH_OSPF6D_PID
+
+/* Define if Solaris */
+#undef SUNOS_5
+
+/* Define if FreeBSD 3.2 */
+#undef FREEBSD_32
+
+/* Define if OpenBSD */
+#undef OPEN_BSD
+
+#ifdef HAVE_IPV6
+#ifdef KAME
+#ifndef INET6
+#define INET6
+#endif /* INET6 */
+#endif /* KAME */
+#endif /* HAVE_IPV6 */
+
+#ifdef SUNOS_5
+typedef unsigned int u_int32_t;
+typedef unsigned short u_int16_t;
+typedef unsigned short u_int8_t;
+#endif /* SUNOS_5 */
+
+#ifndef HAVE_SOCKLEN_T
+typedef int socklen_t;
+#endif /* HAVE_SOCKLEN_T */
+
+/* Define to 1 if you have the <asm/types.h> header file. */
+#undef HAVE_ASM_TYPES_H
+
+/* Define to 1 if you have the `bcopy' function. */
+#undef HAVE_BCOPY
+
+/* Define to 1 if you have the `bzero' function. */
+#undef HAVE_BZERO
+
+/* Define to 1 if you have the `daemon' function. */
+#undef HAVE_DAEMON
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the `getifaddrs' function. */
+#undef HAVE_GETIFADDRS
+
+/* Define to 1 if you have the `if_indextoname' function. */
+#undef HAVE_IF_INDEXTONAME
+
+/* Define to 1 if you have the `if_nametoindex' function. */
+#undef HAVE_IF_NAMETOINDEX
+
+/* Define to 1 if you have the `inet_aton' function. */
+#undef HAVE_INET_ATON
+
+/* Define to 1 if you have the <inet/nd.h> header file. */
+#undef HAVE_INET_ND_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <kvm.h> header file. */
+#undef HAVE_KVM_H
+
+/* Define to 1 if you have the `crypt' library (-lcrypt). */
+#undef HAVE_LIBCRYPT
+
+/* Define to 1 if you have the `kvm' library (-lkvm). */
+#undef HAVE_LIBKVM
+
+/* Define to 1 if you have the `m' library (-lm). */
+#undef HAVE_LIBM
+
+/* Define to 1 if you have the `ncurses' library (-lncurses). */
+#undef HAVE_LIBNCURSES
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define to 1 if you have the `readline' library (-lreadline). */
+#undef HAVE_LIBREADLINE
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#undef HAVE_LIBRESOLV
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to 1 if you have the `tinfo' library (-ltinfo). */
+#undef HAVE_LIBTINFO
+
+/* Define to 1 if you have the <libutil.h> header file. */
+#undef HAVE_LIBUTIL_H
+
+/* Define to 1 if you have the `xnet' library (-lxnet). */
+#undef HAVE_LIBXNET
+
+/* Define to 1 if you have the <linux/version.h> header file. */
+#undef HAVE_LINUX_VERSION_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet6/nd6.h> header file. */
+#undef HAVE_NETINET6_ND6_H
+
+/* Define to 1 if you have the <netinet/icmp6.h> header file. */
+#undef HAVE_NETINET_ICMP6_H
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+#undef HAVE_NETINET_IN6_H
+
+/* Define to 1 if you have the <netinet/in6_var.h> header file. */
+#undef HAVE_NETINET_IN6_VAR_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/in_var.h> header file. */
+#undef HAVE_NETINET_IN_VAR_H
+
+/* Define to 1 if you have the <net/if_dl.h> header file. */
+#undef HAVE_NET_IF_DL_H
+
+/* Define to 1 if you have the <net/if_var.h> header file. */
+#undef HAVE_NET_IF_VAR_H
+
+/* Define to 1 if you have the <net/netopt.h> header file. */
+#undef HAVE_NET_NETOPT_H
+
+/* Define to 1 if you have the `setproctitle' function. */
+#undef HAVE_SETPROCTITLE
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcat' function. */
+#undef HAVE_STRLCAT
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the <stropts.h> header file. */
+#undef HAVE_STROPTS_H
+
+/* Define to 1 if you have the <sys/conf.h> header file. */
+#undef HAVE_SYS_CONF_H
+
+/* Define to 1 if you have the <sys/ksym.h> header file. */
+#undef HAVE_SYS_KSYM_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/sysctl.h> header file. */
+#undef HAVE_SYS_SYSCTL_H
+
+/* Define to 1 if you have the <sys/times.h> header file. */
+#undef HAVE_SYS_TIMES_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#undef HAVE_VSNPRINTF
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
diff --git a/config.sub b/config.sub
new file mode 100755
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 <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit"
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case "$1" in
+ --version | --vers* | -V )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ exec >&2
+ echo "$me: invalid option $1"
+ echo "$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit 0;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | storm-chaos*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
+ | arme[lb] | armv[2345] | armv[345][lb] | pyramid | mn10200 | mn10300 | tron | a29k \
+ | 580 | i960 | h8300 \
+ | x86 | ppcbe | mipsbe | mipsle | shbe | shle | armbe | armle \
+ | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
+ | hppa64 \
+ | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \
+ | alphaev6[78] \
+ | we32k | ns16k | clipper | i370 | sh | sh[34] \
+ | powerpc | powerpcle \
+ | 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \
+ | mips64orion | mips64orionel | mipstx39 | mipstx39el \
+ | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
+ | mips64vr5000 | miprs64vr5000el | mcore \
+ | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \
+ | thumb | d10v | d30v | fr30 | avr)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65 | pj | pjl)
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i[234567]86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ # FIXME: clean up the formatting here.
+ vax-* | tahoe-* | i[234567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \
+ | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
+ | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+ | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
+ | xmp-* | ymp-* \
+ | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* | armbe-* | armle-* \
+ | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \
+ | hppa2.0n-* | hppa64-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \
+ | alphaev6[78]-* \
+ | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
+ | clipper-* | orion-* \
+ | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
+ | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \
+ | mips64el-* | mips64orion-* | mips64orionel-* \
+ | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
+ | mipstx39-* | mipstx39el-* | mcore-* \
+ | f301-* | armv*-* | s390-* | sv1-* | t3e-* \
+ | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
+ | thumb-* | v850-* | d30v-* | tic30-* | c30-* | fr30-* \
+ | bs2000-* | tic54x-* | c54x-* | x86_64-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ cray2)
+ basic_machine=cray2-cray
+ os=-unicos
+ ;;
+ [ctj]90-cray)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i[34567]86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i[34567]86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i[34567]86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i[34567]86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ i386-go32 | go32)
+ basic_machine=i386-unknown
+ os=-go32
+ ;;
+ i386-mingw32 | mingw32)
+ basic_machine=i386-unknown
+ os=-mingw32
+ ;;
+ i[34567]86-pw32 | pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mipsel*-linux*)
+ basic_machine=mipsel-unknown
+ os=-linux-gnu
+ ;;
+ mips*-linux*)
+ basic_machine=mips-unknown
+ os=-linux-gnu
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ mmix*)
+ basic_machine=mmix-knuth
+ os=-mmixware
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ msdos)
+ basic_machine=i386-unknown
+ os=-msdos
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium | p5 | k5 | k6 | nexgen)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2)
+ basic_machine=i686-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=rs6000-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sparclite-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=t3e-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xmp)
+ basic_machine=xmp-cray
+ os=-unicos
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ mips)
+ if [ x$os = x-linux-gnu ]; then
+ basic_machine=mips-unknown
+ else
+ basic_machine=mips-mips
+ fi
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh3 | sh4)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv9)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ c4x*)
+ basic_machine=c4x-none
+ os=-coff
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* | -storm-chaos*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i[34567]86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto*)
+ os=-nto-qnx
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -*MiNT)
+ os=-mint
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f301-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -vxsim* | -vxworks*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -*MiNT)
+ vendor=atari
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "version='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/configure b/configure
new file mode 100755
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 <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO AMTAR install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM AWK SET_MAKE build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CPP AR ac_ct_AR RANLIB ac_ct_RANLIB EGREP MULTIPATH_NUM LIBPAM RT_METHOD KERNEL_METHOD OTHER_METHOD RTREAD_METHOD IF_METHOD IF_PROC IPFORWARD LIB_IPV6 ZEBRA BGPD RIPD RIPNGD OSPFD OSPF6D VTYSH INCLUDES CURSES LIB_REGEX LIBOBJS LTLIBOBJS'
+ac_subst_files=''
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+ac_prev=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_option in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ eval "enable_$ac_feature=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_$ac_feature='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_$ac_package='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ eval "with_$ac_package=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+ localstatedir libdir includedir oldincludedir infodir mandir
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$0" : 'X\(//\)[^/]' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
+ else
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+ fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+ { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+ { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+ cat <<_ACEOF
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
+_ACEOF
+
+ cat <<\_ACEOF
+
+Program names:
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --disable-dependency-tracking Speeds up one-time builds
+ --enable-dependency-tracking Do not reject slow dependency extractors
+ --enable-vtysh, Make integrated VTY version of zebra
+ --disable-ipv6 turn off IPv6 related features and daemons
+ --disable-zebra do not build zebra daemon
+ --disable-bgpd do not build bgpd
+ --disable-ripd do not build ripd
+ --disable-ripngd do not build ripngd
+ --disable-ospfd do not build ospfd
+ --disable-ospf6d do not build ospf6d
+ --disable-bgp-announce, turn off BGP route announcement
+ --enable-netlink force to use Linux netlink interface
+ --enable-broken-aliases enable aliases as distinct interfaces for Linux 2.2.X
+ --enable-snmp enable SNMP support
+ --enable-tcp-zebra enable TCP/IP socket connection between zebra and protocol daemon
+ --enable-nssa enable OSPF NSSA option
+ --enable-opaque-lsa enable OSPF Opaque-LSA support (RFC2370)
+ --enable-ospf-te enable Traffic Engineering Extension to OSPF
+ --enable-multipath=ARG enable multipath function, ARG must be digit
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-cflags Set CFLAGS for use in compilation.
+ --with-libpam use libpam for PAM support in vtysh
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d $ac_dir || continue
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
+# absolute.
+ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
+ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd`
+ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
+ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
+
+ cd $ac_dir
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f $ac_srcdir/configure.gnu; then
+ echo
+ $SHELL $ac_srcdir/configure.gnu --help=recursive
+ elif test -f $ac_srcdir/configure; then
+ echo
+ $SHELL $ac_srcdir/configure --help=recursive
+ elif test -f $ac_srcdir/configure.ac ||
+ test -f $ac_srcdir/configure.in; then
+ echo
+ $ac_configure --help
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi
+ cd $ac_popdir
+ done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+ cat <<\_ACEOF
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
+Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.54. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo = `(hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ echo "PATH: $as_dir"
+done
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell meta-characters.
+ac_configure_args=
+ac_sep=
+for ac_arg
+do
+ case $ac_arg in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n ) continue ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ continue ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ # Get rid of the leading space.
+ ac_sep=" "
+done
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+{
+ (set) 2>&1 |
+ case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ sed -n \
+ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+ ;;
+ *)
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+}
+ echo
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ sed "/^$/d" confdefs.h | sort
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal"
+ echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core core.* *.core &&
+ rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+ ' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . $cache_file;;
+ *) . ./$cache_file;;
+ esac
+ fi
+else
+ { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+ sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+ eval ac_new_val="\$ac_env_${ac_var}_value"
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+am__api_version="1.7"
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f $ac_dir/shtool; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo "$as_me:$LINENO: checking whether build environment is sane" >&5
+echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" >&5
+echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ { { echo "$as_me:$LINENO: error: newly created file is older than distributed files!
+Check your system clock" >&5
+echo "$as_me: error: newly created file is older than distributed files!
+Check your system clock" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+test "$program_prefix" != NONE &&
+ program_transform_name="s,^,$program_prefix,;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s,\$,$program_suffix,;$program_transform_name"
+# Double any \ or $. echo might interpret backslashes.
+# By default was `s,x,x', remove it if useless.
+cat <<\_ACEOF >conftest.sed
+s/[\\$]/&&/g;s/;s,x,x,$//
+_ACEOF
+program_transform_name=`echo $program_transform_name | sed -f conftest.sed`
+rm conftest.sed
+
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5
+echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+fi
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AWK+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AWK="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ echo "$as_me:$LINENO: result: $AWK" >&5
+echo "${ECHO_T}$AWK" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$AWK" && break
+done
+
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \${MAKE}" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \${MAKE}... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,./+-,__p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.make <<\_ACEOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ SET_MAKE=
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+ # test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" &&
+ test -f $srcdir/config.status; then
+ { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5
+echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE=zebra
+ VERSION=0.93
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+
+AMTAR=${AMTAR-"${am_missing_run}tar"}
+
+install_sh=${install_sh-"$am_aux_dir/install-sh"}
+
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ echo "$as_me:$LINENO: result: $STRIP" >&5
+echo "${ECHO_T}$STRIP" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":"
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
+echo "${ECHO_T}$ac_ct_STRIP" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ STRIP=$ac_ct_STRIP
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
+
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+
+
+
+ ac_config_headers="$ac_config_headers config.h"
+
+
+# Make sure we can run config.sub.
+$ac_config_sub sun4 >/dev/null 2>&1 ||
+ { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5
+echo "$as_me: error: cannot run $ac_config_sub" >&2;}
+ { (exit 1); exit 1; }; }
+
+echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6
+if test "${ac_cv_build+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_build_alias=$build_alias
+test -z "$ac_cv_build_alias" &&
+ ac_cv_build_alias=`$ac_config_guess`
+test -z "$ac_cv_build_alias" &&
+ { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+ { (exit 1); exit 1; }; }
+ac_cv_build=`$ac_config_sub $ac_cv_build_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6
+build=$ac_cv_build
+build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6
+if test "${ac_cv_host+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_host_alias=$host_alias
+test -z "$ac_cv_host_alias" &&
+ ac_cv_host_alias=$ac_cv_build_alias
+ac_cv_host=`$ac_config_sub $ac_cv_host_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6
+host=$ac_cv_host
+host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+
+
+# Check whether --with-cflags or --without-cflags was given.
+if test "${with_cflags+set}" = set; then
+ withval="$with_cflags"
+
+fi;
+if test "x$with_cflags" != "x" ; then
+ CFLAGS="$with_cflags" ; cflags_specified=yes ;
+elif test -n "$CFLAGS" ; then
+ cflags_specified=yes ;
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH" >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH" >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:$LINENO: checking for C compiler default output" >&5
+echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+ (eval $ac_link_default) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Find the output, starting from the most likely. This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+ a.out ) # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ # FIXME: I believe we export ac_cv_exeext for Libtool --akim.
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+check \`config.log' for details." >&5
+echo "$as_me: error: C compiler cannot create executables
+check \`config.log' for details." >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link" >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile" >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_compiler_gnu=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+ x|xno)
+ echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+ *)
+ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+ CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ ''\
+ '#include <stdlib.h>' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+continue
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+rm -f .deps 2>/dev/null
+mkdir .deps 2>/dev/null
+if test -d .deps; then
+ DEPDIR=.deps
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ DEPDIR=_deps
+fi
+rmdir .deps 2>/dev/null
+
+
+ ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+doit:
+ @echo done
+END
+# If we don't find an include directive, just comment out the code.
+echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5
+echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+ am__include=include
+ am__quote=
+ _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ fi
+fi
+
+
+echo "$as_me:$LINENO: result: $_am_result" >&5
+echo "${ECHO_T}$_am_result" >&6
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then
+ enableval="$enable_dependency_tracking"
+
+fi;
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+
+
+if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
+
+
+depcc="$CC" am_compiler_list=
+
+echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ for depmode in $am_compiler_list; do
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ echo '#include "conftest.h"' > conftest.c
+ echo 'int i;' > conftest.h
+ echo "${am__include} ${am__quote}conftest.Po${am__quote}" > confmf
+
+ case $depmode in
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ none) break ;;
+ esac
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+ source=conftest.c object=conftest.o \
+ depfile=conftest.Po tmpdepfile=conftest.TPo \
+ $SHELL ./depcomp $depcc -c conftest.c -o conftest.o >/dev/null 2>&1 &&
+ grep conftest.h conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5
+echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+
+
+if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+
+if test "x$cflags_specified" = "x" ; then
+ CFLAGS="$CFLAGS -Wall"
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <assert.h>
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <assert.h>
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check" >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \${MAKE}" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \${MAKE}... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,./+-,__p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.make <<\_ACEOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ SET_MAKE=
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AR="${ac_tool_prefix}ar"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ echo "$as_me:$LINENO: result: $AR" >&5
+echo "${ECHO_T}$AR" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+ ac_ct_AR=$AR
+ # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_AR="ar"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ echo "$as_me:$LINENO: result: $ac_ct_AR" >&5
+echo "${ECHO_T}$ac_ct_AR" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ AR=$ac_ct_AR
+else
+ AR="$ac_cv_prog_AR"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ RANLIB=$ac_ct_RANLIB
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+
+
+
+echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+ then ac_cv_prog_egrep='grep -E'
+ else ac_cv_prog_egrep='egrep'
+ fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+
+echo "$as_me:$LINENO: checking for AIX" >&5
+echo $ECHO_N "checking for AIX... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#ifdef _AIX
+ yes
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+cat >>confdefs.h <<\_ACEOF
+#define _ALL_SOURCE 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest*
+
+
+
+# Check whether --enable-vtysh or --disable-vtysh was given.
+if test "${enable_vtysh+set}" = set; then
+ enableval="$enable_vtysh"
+
+fi;
+# Check whether --enable-ipv6 or --disable-ipv6 was given.
+if test "${enable_ipv6+set}" = set; then
+ enableval="$enable_ipv6"
+
+fi;
+# Check whether --enable-zebra or --disable-zebra was given.
+if test "${enable_zebra+set}" = set; then
+ enableval="$enable_zebra"
+
+fi;
+# Check whether --enable-bgpd or --disable-bgpd was given.
+if test "${enable_bgpd+set}" = set; then
+ enableval="$enable_bgpd"
+
+fi;
+# Check whether --enable-ripd or --disable-ripd was given.
+if test "${enable_ripd+set}" = set; then
+ enableval="$enable_ripd"
+
+fi;
+# Check whether --enable-ripngd or --disable-ripngd was given.
+if test "${enable_ripngd+set}" = set; then
+ enableval="$enable_ripngd"
+
+fi;
+# Check whether --enable-ospfd or --disable-ospfd was given.
+if test "${enable_ospfd+set}" = set; then
+ enableval="$enable_ospfd"
+
+fi;
+# Check whether --enable-ospf6d or --disable-ospf6d was given.
+if test "${enable_ospf6d+set}" = set; then
+ enableval="$enable_ospf6d"
+
+fi;
+# Check whether --enable-bgp-announce or --disable-bgp-announce was given.
+if test "${enable_bgp_announce+set}" = set; then
+ enableval="$enable_bgp_announce"
+
+fi;
+# Check whether --enable-netlink or --disable-netlink was given.
+if test "${enable_netlink+set}" = set; then
+ enableval="$enable_netlink"
+
+fi;
+# Check whether --enable-broken-aliases or --disable-broken-aliases was given.
+if test "${enable_broken_aliases+set}" = set; then
+ enableval="$enable_broken_aliases"
+
+fi;
+# Check whether --enable-snmp or --disable-snmp was given.
+if test "${enable_snmp+set}" = set; then
+ enableval="$enable_snmp"
+
+fi;
+
+# Check whether --with-libpam or --without-libpam was given.
+if test "${with_libpam+set}" = set; then
+ withval="$with_libpam"
+
+fi;
+# Check whether --enable-tcpsock or --disable-tcpsock was given.
+if test "${enable_tcpsock+set}" = set; then
+ enableval="$enable_tcpsock"
+
+fi;
+# Check whether --enable-nssa or --disable-nssa was given.
+if test "${enable_nssa+set}" = set; then
+ enableval="$enable_nssa"
+
+fi;
+# Check whether --enable-opaque-lsa or --disable-opaque-lsa was given.
+if test "${enable_opaque_lsa+set}" = set; then
+ enableval="$enable_opaque_lsa"
+
+fi;
+# Check whether --enable-ospf-te or --disable-ospf-te was given.
+if test "${enable_ospf_te+set}" = set; then
+ enableval="$enable_ospf_te"
+
+fi;
+# Check whether --enable-multipath or --disable-multipath was given.
+if test "${enable_multipath+set}" = set; then
+ enableval="$enable_multipath"
+
+fi;
+
+
+if test "${enable_broken_aliases}" = "yes"; then
+ if test "${enable_netlink}" = "yes"
+ then
+ echo "Sorry, you can't use netlink with broken aliases"
+ exit 1
+ fi
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_BROKEN_ALIASES 1
+_ACEOF
+
+ enable_netlink=no
+fi
+
+if test "${enable_tcp_zebra}" = "yes"; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_TCP_ZEBRA 1
+_ACEOF
+
+fi
+
+if test "${enable_nssa}" = "yes"; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_NSSA 1
+_ACEOF
+
+fi
+
+if test "${enable_opaque_lsa}" = "yes"; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_OPAQUE_LSA 1
+_ACEOF
+
+fi
+
+if test "${enable_ospf_te}" = "yes"; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_OPAQUE_LSA 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_OSPF_TE 1
+_ACEOF
+
+fi
+
+
+
+MULTIPATH_NUM=1
+
+case "${enable_multipath}" in
+ [0-9]|[1-9][0-9])
+ MULTIPATH_NUM="${enable_multipath}"
+ ;;
+ "")
+ ;;
+ *)
+ echo "Please specify digit to --enable-multipath ARG."
+ exit 1
+ ;;
+esac
+
+
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_header in string.h stropts.h sys/conf.h sys/ksym.h sys/time.h sys/times.h sys/select.h sys/sysctl.h sys/sockio.h sys/types.h net/if_dl.h net/if_var.h linux/version.h kvm.h netdb.h netinet/in.h net/netopt.h netinet/in_var.h netinet/in6_var.h netinet/in6.h inet/nd.h asm/types.h netinet/icmp6.h netinet6/nd6.h libutil.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
+echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6
+if test "${ac_cv_c_const+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this. */
+ typedef int charset[2];
+ const charset x;
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *ccp;
+ char **p;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ ccp = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++ccp;
+ p = (char**) ccp;
+ ccp = (char const *const *) p;
+ { /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ }
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_const=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_c_const=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
+echo "${ECHO_T}$ac_cv_c_const" >&6
+if test $ac_cv_c_const = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define const
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking return type of signal handlers" >&5
+echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6
+if test "${ac_cv_type_signal+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+# undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int
+main ()
+{
+int i;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_signal=void
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_type_signal=int
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5
+echo "${ECHO_T}$ac_cv_type_signal" >&6
+
+cat >>confdefs.h <<_ACEOF
+#define RETSIGTYPE $ac_cv_type_signal
+_ACEOF
+
+
+
+case "$host" in
+ *-sunos5.6* | *-solaris2.6*)
+ opsys=sol2-6
+ cat >>confdefs.h <<\_ACEOF
+#define SUNOS_5 1
+_ACEOF
+
+
+echo "$as_me:$LINENO: checking for main in -lxnet" >&5
+echo $ECHO_N "checking for main in -lxnet... $ECHO_C" >&6
+if test "${ac_cv_lib_xnet_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lxnet $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_xnet_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_xnet_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_xnet_main" >&5
+echo "${ECHO_T}$ac_cv_lib_xnet_main" >&6
+if test $ac_cv_lib_xnet_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBXNET 1
+_ACEOF
+
+ LIBS="-lxnet $LIBS"
+
+fi
+
+ CURSES=-lcurses
+ ;;
+ *-sunos5* | *-solaris2*)
+ cat >>confdefs.h <<\_ACEOF
+#define SUNOS_5 1
+_ACEOF
+
+
+echo "$as_me:$LINENO: checking for main in -lsocket" >&5
+echo $ECHO_N "checking for main in -lsocket... $ECHO_C" >&6
+if test "${ac_cv_lib_socket_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_socket_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_socket_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_socket_main" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_main" >&6
+if test $ac_cv_lib_socket_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSOCKET 1
+_ACEOF
+
+ LIBS="-lsocket $LIBS"
+
+fi
+
+
+echo "$as_me:$LINENO: checking for main in -lnsl" >&5
+echo $ECHO_N "checking for main in -lnsl... $ECHO_C" >&6
+if test "${ac_cv_lib_nsl_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_nsl_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_nsl_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_main" >&5
+echo "${ECHO_T}$ac_cv_lib_nsl_main" >&6
+if test $ac_cv_lib_nsl_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNSL 1
+_ACEOF
+
+ LIBS="-lnsl $LIBS"
+
+fi
+
+ CURSES=-lcurses
+ ;;
+ *-linux-*)
+ opsys=gnu-linux
+ cat >>confdefs.h <<\_ACEOF
+#define GNU_LINUX 1
+_ACEOF
+
+ ;;
+ *-nec-sysv4*)
+
+echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5
+echo $ECHO_N "checking for gethostbyname in -lnsl... $ECHO_C" >&6
+if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname ();
+int
+main ()
+{
+gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_nsl_gethostbyname=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_nsl_gethostbyname=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_lib_nsl_gethostbyname" >&6
+if test $ac_cv_lib_nsl_gethostbyname = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNSL 1
+_ACEOF
+
+ LIBS="-lnsl $LIBS"
+
+fi
+
+
+echo "$as_me:$LINENO: checking for socket in -lsocket" >&5
+echo $ECHO_N "checking for socket in -lsocket... $ECHO_C" >&6
+if test "${ac_cv_lib_socket_socket+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socket ();
+int
+main ()
+{
+socket ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_socket_socket=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_socket_socket=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socket" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_socket" >&6
+if test $ac_cv_lib_socket_socket = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSOCKET 1
+_ACEOF
+
+ LIBS="-lsocket $LIBS"
+
+fi
+
+ ;;
+ *-freebsd3.2)
+ cat >>confdefs.h <<\_ACEOF
+#define FREEBSD_32 1
+_ACEOF
+
+ ;;
+ *-openbsd*)
+ opsys=openbsd
+ cat >>confdefs.h <<\_ACEOF
+#define OPEN_BSD 1
+_ACEOF
+
+ ;;
+ *-bsdi*)
+ opsys=bsdi
+ OTHER_METHOD="mtu_kvm.o"
+
+echo "$as_me:$LINENO: checking for main in -lkvm" >&5
+echo $ECHO_N "checking for main in -lkvm... $ECHO_C" >&6
+if test "${ac_cv_lib_kvm_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lkvm $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_kvm_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_kvm_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_kvm_main" >&5
+echo "${ECHO_T}$ac_cv_lib_kvm_main" >&6
+if test $ac_cv_lib_kvm_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBKVM 1
+_ACEOF
+
+ LIBS="-lkvm $LIBS"
+
+fi
+
+ ;;
+esac
+
+case "${host_cpu}-${host_os}" in
+ i?86-solaris*)
+ cat >>confdefs.h <<\_ACEOF
+#define SOLARIS_X86 1
+_ACEOF
+
+ ;;
+esac
+
+case "${enable_vtysh}" in
+ "yes") VTYSH="vtysh";
+ cat >>confdefs.h <<\_ACEOF
+#define VTYSH 1
+_ACEOF
+
+
+echo "$as_me:$LINENO: checking for tputs in -ltinfo" >&5
+echo $ECHO_N "checking for tputs in -ltinfo... $ECHO_C" >&6
+if test "${ac_cv_lib_tinfo_tputs+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ltinfo $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char tputs ();
+int
+main ()
+{
+tputs ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_tinfo_tputs=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_tinfo_tputs=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_tinfo_tputs" >&5
+echo "${ECHO_T}$ac_cv_lib_tinfo_tputs" >&6
+if test $ac_cv_lib_tinfo_tputs = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBTINFO 1
+_ACEOF
+
+ LIBS="-ltinfo $LIBS"
+
+else
+
+echo "$as_me:$LINENO: checking for tputs in -lncurses" >&5
+echo $ECHO_N "checking for tputs in -lncurses... $ECHO_C" >&6
+if test "${ac_cv_lib_ncurses_tputs+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lncurses $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char tputs ();
+int
+main ()
+{
+tputs ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_ncurses_tputs=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_ncurses_tputs=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_ncurses_tputs" >&5
+echo "${ECHO_T}$ac_cv_lib_ncurses_tputs" >&6
+if test $ac_cv_lib_ncurses_tputs = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNCURSES 1
+_ACEOF
+
+ LIBS="-lncurses $LIBS"
+
+fi
+
+fi
+
+
+echo "$as_me:$LINENO: checking for main in -lreadline" >&5
+echo $ECHO_N "checking for main in -lreadline... $ECHO_C" >&6
+if test "${ac_cv_lib_readline_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lreadline $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_readline_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_readline_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_readline_main" >&5
+echo "${ECHO_T}$ac_cv_lib_readline_main" >&6
+if test $ac_cv_lib_readline_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBREADLINE 1
+_ACEOF
+
+ LIBS="-lreadline $LIBS"
+
+fi
+
+ if test $ac_cv_lib_readline_main = no; then
+ { { echo "$as_me:$LINENO: error: vtysh needs libreadline but was not found on your system." >&5
+echo "$as_me: error: vtysh needs libreadline but was not found on your system." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ if test "${ac_cv_header_readline_history_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for readline/history.h" >&5
+echo $ECHO_N "checking for readline/history.h... $ECHO_C" >&6
+if test "${ac_cv_header_readline_history_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_readline_history_h" >&5
+echo "${ECHO_T}$ac_cv_header_readline_history_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking readline/history.h usability" >&5
+echo $ECHO_N "checking readline/history.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+$ac_includes_default
+#include <readline/history.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking readline/history.h presence" >&5
+echo $ECHO_N "checking readline/history.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <readline/history.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: readline/history.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: readline/history.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: readline/history.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: readline/history.h: proceeding with the preprocessor's result" >&2;};;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: readline/history.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: readline/history.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: readline/history.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: readline/history.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: readline/history.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: readline/history.h: proceeding with the preprocessor's result" >&2;};;
+esac
+echo "$as_me:$LINENO: checking for readline/history.h" >&5
+echo $ECHO_N "checking for readline/history.h... $ECHO_C" >&6
+if test "${ac_cv_header_readline_history_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_readline_history_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_readline_history_h" >&5
+echo "${ECHO_T}$ac_cv_header_readline_history_h" >&6
+
+fi
+
+
+ if test $ac_cv_header_readline_history_h = no;then
+ { { echo "$as_me:$LINENO: error: readline is too old to have readline/history.h, please update to the latest readline library." >&5
+echo "$as_me: error: readline is too old to have readline/history.h, please update to the latest readline library." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ ;;
+ "no" ) VTYSH="";;
+ * ) ;;
+esac
+
+if test "$with_libpam" = "yes"; then
+echo "$as_me:$LINENO: checking for pam_start in -lpam" >&5
+echo $ECHO_N "checking for pam_start in -lpam... $ECHO_C" >&6
+if test "${ac_cv_lib_pam_pam_start+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpam $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pam_start ();
+int
+main ()
+{
+pam_start ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pam_pam_start=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_pam_pam_start=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pam_pam_start" >&5
+echo "${ECHO_T}$ac_cv_lib_pam_pam_start" >&6
+if test $ac_cv_lib_pam_pam_start = yes; then
+ echo "$as_me:$LINENO: checking for misc_conv in -lpam" >&5
+echo $ECHO_N "checking for misc_conv in -lpam... $ECHO_C" >&6
+if test "${ac_cv_lib_pam_misc_conv+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpam $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char misc_conv ();
+int
+main ()
+{
+misc_conv ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pam_misc_conv=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_pam_misc_conv=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pam_misc_conv" >&5
+echo "${ECHO_T}$ac_cv_lib_pam_misc_conv" >&6
+if test $ac_cv_lib_pam_misc_conv = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define USE_PAM 1
+_ACEOF
+
+ LIBPAM="-lpam"
+else
+ cat >>confdefs.h <<\_ACEOF
+#define USE_PAM 1
+_ACEOF
+
+ LIBPAM="-lpam -lpam_misc"
+
+fi
+
+
+else
+ echo "$as_me:$LINENO: checking for pam_end in -lpam" >&5
+echo $ECHO_N "checking for pam_end in -lpam... $ECHO_C" >&6
+if test "${ac_cv_lib_pam_pam_end+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpam -ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pam_end ();
+int
+main ()
+{
+pam_end ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pam_pam_end=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_pam_pam_end=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pam_pam_end" >&5
+echo "${ECHO_T}$ac_cv_lib_pam_pam_end" >&6
+if test $ac_cv_lib_pam_pam_end = yes; then
+ echo "$as_me:$LINENO: checking for misc_conv in -lpam" >&5
+echo $ECHO_N "checking for misc_conv in -lpam... $ECHO_C" >&6
+if test "${ac_cv_lib_pam_misc_conv+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpam $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char misc_conv ();
+int
+main ()
+{
+misc_conv ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pam_misc_conv=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_pam_misc_conv=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pam_misc_conv" >&5
+echo "${ECHO_T}$ac_cv_lib_pam_misc_conv" >&6
+if test $ac_cv_lib_pam_misc_conv = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define USE_PAM 1
+_ACEOF
+
+ LIBPAM="-lpam -ldl"
+else
+ cat >>confdefs.h <<\_ACEOF
+#define USE_PAM 1
+_ACEOF
+
+ LIBPAM="-lpam -ldl -lpam_misc"
+
+fi
+
+
+else
+ { echo "$as_me:$LINENO: WARNING: *** pam support will not be built ***" >&5
+echo "$as_me: WARNING: *** pam support will not be built ***" >&2;}
+fi
+
+
+
+fi
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_func in bcopy bzero strerror inet_aton daemon snprintf vsnprintf strlcat strlcpy if_nametoindex if_indextoname getifaddrs
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+char (*f) ();
+
+int
+main ()
+{
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in setproctitle
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+char (*f) ();
+
+int
+main ()
+{
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: checking for setproctitle in -lutil" >&5
+echo $ECHO_N "checking for setproctitle in -lutil... $ECHO_C" >&6
+if test "${ac_cv_lib_util_setproctitle+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lutil $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char setproctitle ();
+int
+main ()
+{
+setproctitle ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_util_setproctitle=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_util_setproctitle=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_util_setproctitle" >&5
+echo "${ECHO_T}$ac_cv_lib_util_setproctitle" >&6
+if test $ac_cv_lib_util_setproctitle = yes; then
+ LIBS="$LIBS -lutil"; cat >>confdefs.h <<\_ACEOF
+#define HAVE_SETPROCTITLE 1
+_ACEOF
+
+fi
+
+fi
+done
+
+
+echo "$as_me:$LINENO: checking zebra between kernel interface method" >&5
+echo $ECHO_N "checking zebra between kernel interface method... $ECHO_C" >&6
+if test x"$opsys" = x"gnu-linux"; then
+ if test "${enable_netlink}" = "yes";then
+ echo "$as_me:$LINENO: result: netlink" >&5
+echo "${ECHO_T}netlink" >&6
+ RT_METHOD=rt_netlink.o
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_NETLINK 1
+_ACEOF
+
+ netlink=yes
+ elif test "${enable_netlink}" = "no"; then
+ echo "$as_me:$LINENO: result: ioctl" >&5
+echo "${ECHO_T}ioctl" >&6
+ RT_METHOD=rt_ioctl.o
+ netlink=no
+ else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <linux/autoconf.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > 131328 /* 2.1.0 or later */
+#ifdef CONFIG_RTNETLINK
+ yes
+#endif
+#endif
+#if LINUX_VERSION_CODE > 132112 /* 2.4.17 or later */
+ yes
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1; then
+ echo "$as_me:$LINENO: result: netlink" >&5
+echo "${ECHO_T}netlink" >&6
+ RT_METHOD=rt_netlink.o
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_NETLINK 1
+_ACEOF
+
+ netlink=yes
+else
+ echo "$as_me:$LINENO: result: ioctl" >&5
+echo "${ECHO_T}ioctl" >&6
+ RT_METHOD=rt_ioctl.o
+fi
+rm -f conftest*
+
+ fi
+else
+ if test "$opsys" = "sol2-6";then
+ echo "$as_me:$LINENO: result: solaris" >&5
+echo "${ECHO_T}solaris" >&6
+ KERNEL_METHOD="kernel_socket.o"
+ RT_METHOD="rt_socket.o"
+ else
+ if test "$cross_compiling" = yes; then
+ KERNEL_METHOD=kernel_socket.o
+ RT_METHOD=rt_socket.o
+ echo "$as_me:$LINENO: result: socket" >&5
+echo "${ECHO_T}socket" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+main ()
+{
+ int ac_sock;
+
+ ac_sock = socket (AF_ROUTE, SOCK_RAW, 0);
+ if (ac_sock < 0 && errno == EINVAL)
+ exit (1);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_AF_ROUTE 1
+_ACEOF
+
+ KERNEL_METHOD=kernel_socket.o
+ RT_METHOD=rt_socket.o
+ echo "$as_me:$LINENO: result: socket" >&5
+echo "${ECHO_T}socket" >&6
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+( exit $ac_status )
+RT_METHOD=rt_ioctl.o
+ echo "$as_me:$LINENO: result: ioctl" >&5
+echo "${ECHO_T}ioctl" >&6
+fi
+rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+ fi
+fi
+
+
+
+
+echo "$as_me:$LINENO: checking route read method check" >&5
+echo $ECHO_N "checking route read method check... $ECHO_C" >&6
+if test "${zebra_rtread+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$netlink" = yes; then
+ RTREAD_METHOD="rtread_netlink.o"
+ zebra_rtread="netlink"
+else
+for zebra_rtread in /proc/net/route /dev/ip /dev/null;
+do
+ test x`ls $zebra_rtread 2>/dev/null` = x"$zebra_rtread" && break
+done
+case $zebra_rtread in
+ "/proc/net/route") RTREAD_METHOD="rtread_proc.o"
+ zebra_rtread="proc";;
+ "/dev/ip") RTREAD_METHOD="rtread_getmsg.o"
+ zebra_rtread="getmsg";;
+ *) RTREAD_METHOD="rtread_sysctl.o"
+ zebra_rtread="sysctl";;
+esac
+fi
+fi
+echo "$as_me:$LINENO: result: $zebra_rtread" >&5
+echo "${ECHO_T}$zebra_rtread" >&6
+
+
+echo "$as_me:$LINENO: checking interface looking up method" >&5
+echo $ECHO_N "checking interface looking up method... $ECHO_C" >&6
+if test "$netlink" = yes; then
+ echo "$as_me:$LINENO: result: netlink" >&5
+echo "${ECHO_T}netlink" >&6
+ IF_METHOD=if_netlink.o
+else
+ if test "$opsys" = "sol2-6";then
+ echo "$as_me:$LINENO: result: solaris" >&5
+echo "${ECHO_T}solaris" >&6
+ IF_METHOD=if_ioctl.o
+ elif test "$opsys" = "openbsd";then
+ echo "$as_me:$LINENO: result: openbsd" >&5
+echo "${ECHO_T}openbsd" >&6
+ IF_METHOD=if_ioctl.o
+ elif grep NET_RT_IFLIST /usr/include/sys/socket.h >/dev/null 2>&1; then
+ echo "$as_me:$LINENO: result: sysctl" >&5
+echo "${ECHO_T}sysctl" >&6
+ IF_METHOD=if_sysctl.o
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_NET_RT_IFLIST 1
+_ACEOF
+
+ else
+ echo "$as_me:$LINENO: result: ioctl" >&5
+echo "${ECHO_T}ioctl" >&6
+ IF_METHOD=if_ioctl.o
+ fi
+fi
+
+
+if test -r /proc/net/dev; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_PROC_NET_DEV 1
+_ACEOF
+
+ IF_PROC=if_proc.o
+fi
+
+if test -r /proc/net/if_inet6; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_PROC_NET_IF_INET6 1
+_ACEOF
+
+ IF_PROC=if_proc.o
+fi
+
+
+echo "$as_me:$LINENO: checking ipforward method check" >&5
+echo $ECHO_N "checking ipforward method check... $ECHO_C" >&6
+if test "${zebra_ipforward_path+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ for zebra_ipforward_path in /proc/net/snmp /dev/ip /dev/null;
+do
+ test x`ls $zebra_ipforward_path 2>/dev/null` = x"$zebra_ipforward_path" && break
+done
+case $zebra_ipforward_path in
+ "/proc/net/snmp") IPFORWARD=ipforward_proc.o
+ zebra_ipforward_path="proc";;
+ "/dev/ip")
+ case "$host" in
+ *-nec-sysv4*) IPFORWARD=ipforward_ews.o
+ zebra_ipforward_path="ews";;
+ *) IPFORWARD=ipforward_solaris.o
+ zebra_ipforward_path="solaris";;
+ esac;;
+ *) IPFORWARD=ipforward_sysctl.o
+ zebra_ipforward_path="sysctl";;
+esac
+fi
+echo "$as_me:$LINENO: result: $zebra_ipforward_path" >&5
+echo "${ECHO_T}$zebra_ipforward_path" >&6
+
+
+
+for ac_func in getaddrinfo
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+char (*f) ();
+
+int
+main ()
+{
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+ have_getaddrinfo=yes
+else
+ have_getaddrinfo=no
+fi
+done
+
+
+echo "$as_me:$LINENO: checking whether does this OS have IPv6 stack" >&5
+echo $ECHO_N "checking whether does this OS have IPv6 stack... $ECHO_C" >&6
+if test "${enable_ipv6}" = "no"; then
+ echo "$as_me:$LINENO: result: disabled" >&5
+echo "${ECHO_T}disabled" >&6
+else
+if grep IPV6_INRIA_VERSION /usr/include/netinet/in.h >/dev/null 2>&1; then
+ zebra_cv_ipv6=yes
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_IPV6 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define INRIA_IPV6 1
+_ACEOF
+
+ RIPNGD="ripngd"
+ OSPF6D="ospf6d"
+ LIB_IPV6=""
+ echo "$as_me:$LINENO: result: INRIA IPv6" >&5
+echo "${ECHO_T}INRIA IPv6" >&6
+fi
+if grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then
+ zebra_cv_ipv6=yes
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_IPV6 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define KAME 1
+_ACEOF
+
+ RIPNGD="ripngd"
+ OSPF6D="ospf6d"
+ if test -d /usr/local/v6/lib -a -f /usr/local/v6/lib/libinet6.a; then
+ LIB_IPV6="-L/usr/local/v6/lib -linet6"
+ fi
+ echo "$as_me:$LINENO: result: KAME" >&5
+echo "${ECHO_T}KAME" >&6
+fi
+if grep NRL /usr/include/netinet6/in6.h >/dev/null 2>&1; then
+ zebra_cv_ipv6=yes
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_IPV6 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define NRL 1
+_ACEOF
+
+ RIPNGD="ripngd"
+ OSPF6D="ospf6d"
+ if test x"$opsys" = x"bsdi";then
+ cat >>confdefs.h <<\_ACEOF
+#define BSDI_NRL 1
+_ACEOF
+
+ echo "$as_me:$LINENO: result: BSDI_NRL" >&5
+echo "${ECHO_T}BSDI_NRL" >&6
+ else
+ echo "$as_me:$LINENO: result: NRL" >&5
+echo "${ECHO_T}NRL" >&6
+ fi
+fi
+
+if test "${enable_ipv6}" = "yes"; then
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+ #include <linux/version.h>
+ /* 2.1.128 or later */
+ #if LINUX_VERSION_CODE >= 0x020180
+ yes
+ #endif
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1; then
+ zebra_cv_ipv6=yes; zebra_cv_linux_ipv6=yes;echo "$as_me:$LINENO: result: Linux IPv6" >&5
+echo "${ECHO_T}Linux IPv6" >&6
+fi
+rm -f conftest*
+
+else
+ if test x`ls /proc/net/ipv6_route 2>/dev/null` = x"/proc/net/ipv6_route"
+ then
+ zebra_cv_ipv6=yes
+ zebra_cv_linux_ipv6=yes
+ echo "$as_me:$LINENO: result: Linux IPv6" >&5
+echo "${ECHO_T}Linux IPv6" >&6
+ fi
+fi
+
+if test "$zebra_cv_linux_ipv6" = "yes";then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_IPV6 1
+_ACEOF
+
+ echo "$as_me:$LINENO: checking for GNU libc 2.1" >&5
+echo $ECHO_N "checking for GNU libc 2.1... $ECHO_C" >&6
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#include <features.h>
+#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
+ yes
+#endif
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1; then
+ glibc=yes; echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest*
+
+ cat >>confdefs.h <<\_ACEOF
+#define LINUX_IPV6 1
+_ACEOF
+
+ RIPNGD="ripngd"
+ OSPF6D="ospf6d"
+ if test "$glibc" != "yes"; then
+ INCLUDES="-I/usr/inet6/include"
+ if test x`ls /usr/inet6/lib/libinet6.a 2>/dev/null` != x;then
+ LIB_IPV6="-L/usr/inet6/lib -linet6"
+ fi
+ fi
+fi
+
+LIBS="$LIB_IPV6 $LIBS"
+
+
+if test x"$RIPNGD" = x""; then
+ echo "$as_me:$LINENO: result: IPv4 only" >&5
+echo "${ECHO_T}IPv4 only" >&6
+fi
+fi
+
+if test "${enable_zebra}" = "no";then
+ ZEBRA=""
+else
+ ZEBRA="zebra"
+fi
+
+if test "${enable_bgpd}" = "no";then
+ BGPD=""
+else
+ BGPD="bgpd"
+fi
+
+if test "${enable_ripd}" = "no";then
+ RIPD=""
+else
+ RIPD="ripd"
+fi
+
+if test "${enable_ospfd}" = "no";then
+ OSPFD=""
+else
+ OSPFD="ospfd"
+fi
+
+case "${enable_ripngd}" in
+ "yes") RIPNGD="ripngd";;
+ "no" ) RIPNGD="";;
+ * ) ;;
+esac
+
+case "${enable_ospf6d}" in
+ "yes") OSPF6D="ospf6d";;
+ "no" ) OSPF6D="";;
+ * ) ;;
+esac
+
+if test "${enable_bgp_announce}" = "no";then
+ cat >>confdefs.h <<\_ACEOF
+#define DISABLE_BGP_ANNOUNCE 1
+_ACEOF
+
+fi
+
+
+
+
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking for inet_ntop in -lc" >&5
+echo $ECHO_N "checking for inet_ntop in -lc... $ECHO_C" >&6
+if test "${ac_cv_lib_c_inet_ntop+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char inet_ntop ();
+int
+main ()
+{
+inet_ntop ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_c_inet_ntop=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_c_inet_ntop=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_c_inet_ntop" >&5
+echo "${ECHO_T}$ac_cv_lib_c_inet_ntop" >&6
+if test $ac_cv_lib_c_inet_ntop = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_INET_NTOP 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for inet_pton in -lc" >&5
+echo $ECHO_N "checking for inet_pton in -lc... $ECHO_C" >&6
+if test "${ac_cv_lib_c_inet_pton+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char inet_pton ();
+int
+main ()
+{
+inet_pton ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_c_inet_pton=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_c_inet_pton=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_c_inet_pton" >&5
+echo "${ECHO_T}$ac_cv_lib_c_inet_pton" >&6
+if test $ac_cv_lib_c_inet_pton = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_INET_PTON 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for crypt in -lcrypt" >&5
+echo $ECHO_N "checking for crypt in -lcrypt... $ECHO_C" >&6
+if test "${ac_cv_lib_crypt_crypt+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypt $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char crypt ();
+int
+main ()
+{
+crypt ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_crypt_crypt=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_crypt_crypt=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_crypt_crypt" >&5
+echo "${ECHO_T}$ac_cv_lib_crypt_crypt" >&6
+if test $ac_cv_lib_crypt_crypt = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBCRYPT 1
+_ACEOF
+
+ LIBS="-lcrypt $LIBS"
+
+fi
+
+
+echo "$as_me:$LINENO: checking for res_init in -lresolv" >&5
+echo $ECHO_N "checking for res_init in -lresolv... $ECHO_C" >&6
+if test "${ac_cv_lib_resolv_res_init+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lresolv $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char res_init ();
+int
+main ()
+{
+res_init ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_resolv_res_init=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_resolv_res_init=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_resolv_res_init" >&5
+echo "${ECHO_T}$ac_cv_lib_resolv_res_init" >&6
+if test $ac_cv_lib_resolv_res_init = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBRESOLV 1
+_ACEOF
+
+ LIBS="-lresolv $LIBS"
+
+fi
+
+
+echo "$as_me:$LINENO: checking for main in -lm" >&5
+echo $ECHO_N "checking for main in -lm... $ECHO_C" >&6
+if test "${ac_cv_lib_m_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_m_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_m_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_m_main" >&5
+echo "${ECHO_T}$ac_cv_lib_m_main" >&6
+if test $ac_cv_lib_m_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+ LIBS="-lm $LIBS"
+
+fi
+
+
+echo "$as_me:$LINENO: checking for __inet_ntop" >&5
+echo $ECHO_N "checking for __inet_ntop... $ECHO_C" >&6
+if test "${ac_cv_func___inet_ntop+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char __inet_ntop (); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char __inet_ntop ();
+char (*f) ();
+
+int
+main ()
+{
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub___inet_ntop) || defined (__stub_____inet_ntop)
+choke me
+#else
+f = __inet_ntop;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func___inet_ntop=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_func___inet_ntop=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func___inet_ntop" >&5
+echo "${ECHO_T}$ac_cv_func___inet_ntop" >&6
+if test $ac_cv_func___inet_ntop = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_INET_NTOP 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for __inet_pton" >&5
+echo $ECHO_N "checking for __inet_pton... $ECHO_C" >&6
+if test "${ac_cv_func___inet_pton+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char __inet_pton (); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char __inet_pton ();
+char (*f) ();
+
+int
+main ()
+{
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub___inet_pton) || defined (__stub_____inet_pton)
+choke me
+#else
+f = __inet_pton;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func___inet_pton=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_func___inet_pton=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func___inet_pton" >&5
+echo "${ECHO_T}$ac_cv_func___inet_pton" >&6
+if test $ac_cv_func___inet_pton = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_INET_PTON 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for __inet_aton" >&5
+echo $ECHO_N "checking for __inet_aton... $ECHO_C" >&6
+if test "${ac_cv_func___inet_aton+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char __inet_aton (); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char __inet_aton ();
+char (*f) ();
+
+int
+main ()
+{
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub___inet_aton) || defined (__stub_____inet_aton)
+choke me
+#else
+f = __inet_aton;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func___inet_aton=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_func___inet_aton=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func___inet_aton" >&5
+echo "${ECHO_T}$ac_cv_func___inet_aton" >&6
+if test $ac_cv_func___inet_aton = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_INET_ATON 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for regexec in -lc" >&5
+echo $ECHO_N "checking for regexec in -lc... $ECHO_C" >&6
+if test "${ac_cv_lib_c_regexec+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char regexec ();
+int
+main ()
+{
+regexec ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_c_regexec=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_c_regexec=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_c_regexec" >&5
+echo "${ECHO_T}$ac_cv_lib_c_regexec" >&6
+if test $ac_cv_lib_c_regexec = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_GNU_REGEX 1
+_ACEOF
+
+ LIB_REGEX=""
+else
+ LIB_REGEX="regex.o"
+fi
+
+
+
+
+if test "${enable_snmp}" = "yes";then
+ old_libs="${LIBS}"
+ LIBS="-L/usr/local/lib"
+ unset ac_cv_lib_snmp_asn_parse_int
+ echo "$as_me:$LINENO: checking for asn_parse_int in -lsnmp" >&5
+echo $ECHO_N "checking for asn_parse_int in -lsnmp... $ECHO_C" >&6
+if test "${ac_cv_lib_snmp_asn_parse_int+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsnmp $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char asn_parse_int ();
+int
+main ()
+{
+asn_parse_int ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_snmp_asn_parse_int=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_snmp_asn_parse_int=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_snmp_asn_parse_int" >&5
+echo "${ECHO_T}$ac_cv_lib_snmp_asn_parse_int" >&6
+if test $ac_cv_lib_snmp_asn_parse_int = yes; then
+ HAVE_SNMP=yes
+fi
+
+ if test "${HAVE_SNMP}" = ""; then
+ unset ac_cv_lib_snmp_asn_parse_int
+ echo "$as_me:$LINENO: checking for main in -lcrypto" >&5
+echo $ECHO_N "checking for main in -lcrypto... $ECHO_C" >&6
+if test "${ac_cv_lib_crypto_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_crypto_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_crypto_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_crypto_main" >&5
+echo "${ECHO_T}$ac_cv_lib_crypto_main" >&6
+if test $ac_cv_lib_crypto_main = yes; then
+ NEED_CRYPTO=yes
+fi
+
+ if test "${NEED_CRYPTO}" = ""; then
+ echo "$as_me:$LINENO: checking for asn_parse_int in -lsnmp" >&5
+echo $ECHO_N "checking for asn_parse_int in -lsnmp... $ECHO_C" >&6
+if test "${ac_cv_lib_snmp_asn_parse_int+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsnmp $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char asn_parse_int ();
+int
+main ()
+{
+asn_parse_int ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_snmp_asn_parse_int=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_snmp_asn_parse_int=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_snmp_asn_parse_int" >&5
+echo "${ECHO_T}$ac_cv_lib_snmp_asn_parse_int" >&6
+if test $ac_cv_lib_snmp_asn_parse_int = yes; then
+ HAVE_SNMP=yes; NEED_CRYPTO=yes
+fi
+
+ else
+ echo "$as_me:$LINENO: checking for asn_parse_int in -lsnmp" >&5
+echo $ECHO_N "checking for asn_parse_int in -lsnmp... $ECHO_C" >&6
+if test "${ac_cv_lib_snmp_asn_parse_int+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsnmp "-lcrypto" $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char asn_parse_int ();
+int
+main ()
+{
+asn_parse_int ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_snmp_asn_parse_int=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_snmp_asn_parse_int=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_snmp_asn_parse_int" >&5
+echo "${ECHO_T}$ac_cv_lib_snmp_asn_parse_int" >&6
+if test $ac_cv_lib_snmp_asn_parse_int = yes; then
+ HAVE_SNMP=yes; NEED_CRYPTO=yes;LIBS="$LIBS -lcrypto"
+fi
+
+ fi
+ fi
+ LIBS="${old_libs}"
+
+ if test "${HAVE_SNMP}" = ""; then
+ old_libs="${LIBS}"
+ LIBS="-L/usr/local/lib"
+ echo "$as_me:$LINENO: checking for asn_parse_int in -lsnmp" >&5
+echo $ECHO_N "checking for asn_parse_int in -lsnmp... $ECHO_C" >&6
+if test "${ac_cv_lib_snmp_asn_parse_int+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsnmp $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char asn_parse_int ();
+int
+main ()
+{
+asn_parse_int ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_snmp_asn_parse_int=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_snmp_asn_parse_int=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_snmp_asn_parse_int" >&5
+echo "${ECHO_T}$ac_cv_lib_snmp_asn_parse_int" >&6
+if test $ac_cv_lib_snmp_asn_parse_int = yes; then
+ HAVE_SNMP=yes
+fi
+
+ LIBS="${old_libs}"
+ fi
+ if test "${HAVE_SNMP}" = "yes"; then
+ for ac_snmp in /usr/include/ucd-snmp/asn1.h /usr/local/include/ucd-snmp/asn1.h /dev/null
+ do
+ test -f "${ac_snmp}" && break
+ done
+ case ${ac_snmp} in
+ /usr/include/ucd-snmp/*)
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SNMP 1
+_ACEOF
+
+ CFLAGS="${CFLAGS} -I/usr/include/ucd-snmp"
+ LIBS="${LIBS} -lsnmp"
+ ;;
+ /usr/local/include/ucd-snmp/*)
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SNMP 1
+_ACEOF
+
+ CFLAGS="${CFLAGS} -I/usr/local/include/ucd-snmp"
+ LIBS="${LIBS} -L/usr/local/lib -lsnmp"
+ ;;
+ esac
+ if test "${NEED_CRYPTO}" = "yes"; then
+ LIBS="${LIBS} -lcrypto"
+ fi
+ fi
+fi
+
+echo "$as_me:$LINENO: checking whether struct sockaddr has a sa_len field" >&5
+echo $ECHO_N "checking whether struct sockaddr has a sa_len field... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int
+main ()
+{
+static struct sockaddr ac_i;int ac_j = sizeof (ac_i.sa_len);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SA_LEN 1
+_ACEOF
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+echo "$as_me:$LINENO: checking whether struct sockaddr_in has a sin_len field" >&5
+echo $ECHO_N "checking whether struct sockaddr_in has a sin_len field... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <netinet/in.h>
+
+int
+main ()
+{
+static struct sockaddr_in ac_i;int ac_j = sizeof (ac_i.sin_len);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIN_LEN 1
+_ACEOF
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+echo "$as_me:$LINENO: checking whether struct sockaddr_un has a sun_len field" >&5
+echo $ECHO_N "checking whether struct sockaddr_un has a sun_len field... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/un.h>
+
+int
+main ()
+{
+static struct sockaddr_un ac_i;int ac_j = sizeof (ac_i.sun_len);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SUN_LEN 1
+_ACEOF
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+if test "$zebra_cv_ipv6" = yes; then
+ echo "$as_me:$LINENO: checking whether struct sockaddr_in6 has a sin6_scope_id field" >&5
+echo $ECHO_N "checking whether struct sockaddr_in6 has a sin6_scope_id field... $ECHO_C" >&6
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <netinet/in.h>
+
+int
+main ()
+{
+static struct sockaddr_in6 ac_i;int ac_j = sizeof (ac_i.sin6_scope_id);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIN6_SCOPE_ID 1
+_ACEOF
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+
+echo "$as_me:$LINENO: checking whther socklen_t is defined" >&5
+echo $ECHO_N "checking whther socklen_t is defined... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+int
+main ()
+{
+socklen_t ac_x;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SOCKLEN_T 1
+_ACEOF
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+echo "$as_me:$LINENO: checking whether struct sockaddr_dl exist" >&5
+echo $ECHO_N "checking whether struct sockaddr_dl exist... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <net/if_dl.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "sockaddr_dl" >/dev/null 2>&1; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SOCKADDR_DL 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest*
+
+
+echo "$as_me:$LINENO: checking whether struct ifaliasreq exist" >&5
+echo $ECHO_N "checking whether struct ifaliasreq exist... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <net/if.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "ifaliasreq" >/dev/null 2>&1; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_IFALIASREQ 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest*
+
+
+echo "$as_me:$LINENO: checking whether struct if6_aliasreq exist" >&5
+echo $ECHO_N "checking whether struct if6_aliasreq exist... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <netinet6/in6_var.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "in6_aliasreq" >/dev/null 2>&1; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_IN6_ALIASREQ 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest*
+
+
+echo "$as_me:$LINENO: checking whether struct rt_addrinfo exist" >&5
+echo $ECHO_N "checking whether struct rt_addrinfo exist... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <net/route.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "rt_addrinfo" >/dev/null 2>&1; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_RT_ADDRINFO 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest*
+
+
+echo "$as_me:$LINENO: checking whether struct in_pktinfo exist" >&5
+echo $ECHO_N "checking whether struct in_pktinfo exist... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <netinet/in.h>
+
+int
+main ()
+{
+struct in_pktinfo ac_x;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_INPKTINFO 1
+_ACEOF
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+echo "$as_me:$LINENO: checking whether getrusage is available" >&5
+echo $ECHO_N "checking whether getrusage is available... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <sys/resource.h>
+
+int
+main ()
+{
+struct rusage ac_x; getrusage (RUSAGE_SELF, &ac_x);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_RUSAGE 1
+_ACEOF
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+file="${srcdir}/lib/version.h"
+VERSION=`sed -ne 's/^#.*ZEBRA_VERSION.*\"\([^\"]*\)\"$/\1/p' $file`
+
+
+echo "$as_me:$LINENO: checking pid file directory" >&5
+echo $ECHO_N "checking pid file directory... $ECHO_C" >&6
+if test "${ac_piddir+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ for ZEBRA_PID_DIR in /var/run /var/adm /etc /dev/null;
+do
+ test -d $ZEBRA_PID_DIR && break
+done
+ac_piddir=$ZEBRA_PID_DIR
+if test $ZEBRA_PID_DIR = "/dev/null"; then
+ echo "PID DIRECTORY NOT FOUND!"
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_piddir" >&5
+echo "${ECHO_T}$ac_piddir" >&6
+cat >>confdefs.h <<_ACEOF
+#define PATH_ZEBRA_PID "$ac_piddir/zebra.pid"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PATH_RIPD_PID "$ac_piddir/ripd.pid"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PATH_RIPNGD_PID "$ac_piddir/ripngd.pid"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PATH_BGPD_PID "$ac_piddir/bgpd.pid"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PATH_OSPFD_PID "$ac_piddir/ospfd.pid"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PATH_OSPF6D_PID "$ac_piddir/ospf6d.pid"
+_ACEOF
+
+
+
+echo "$as_me:$LINENO: checking for working htonl" >&5
+echo $ECHO_N "checking for working htonl... $ECHO_C" >&6
+if test "${ac_cv_htonl_works+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+int
+main ()
+{
+htonl (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_htonl_works=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_htonl_works=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+
+echo "$as_me:$LINENO: result: $ac_cv_htonl_works" >&5
+echo "${ECHO_T}$ac_cv_htonl_works" >&6
+
+ ac_config_files="$ac_config_files Makefile lib/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile ospf6d/Makefile vtysh/Makefile doc/Makefile"
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+ (set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} |
+ sed '
+ t clear
+ : clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ : end' >>confcache
+if cmp -s $cache_file confcache; then :; else
+ if test -w $cache_file; then
+ test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+ cat confcache >$cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[ ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[ ]*$//;
+}'
+fi
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_i=`echo "$ac_i" |
+ sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+ # 2. Add them.
+ ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+ ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in LANG LANGUAGE LC_ALL LC_COLLATE LC_CTYPE LC_NUMERIC LC_MESSAGES LC_TIME
+do
+ if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conftest.sh
+ echo "exit 0" >>conftest.sh
+ chmod +x conftest.sh
+ if (PATH="/nonexistent;."; conftest.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conftest.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling. Logging --version etc. is OK.
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.54. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+ echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+ echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+ echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+ echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <bug-autoconf@gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.54,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+INSTALL="$INSTALL"
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "x$1" : 'x\([^=]*\)='`
+ ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ -*)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_option=$1
+ ac_need_defaults=false;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running $SHELL $0 " $ac_configure_args " --no-create --no-recursion"
+ exec $SHELL $0 $ac_configure_args --no-create --no-recursion ;;
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+ --version | --vers* | -V )
+ echo "$ac_cs_version"; exit 0 ;;
+ --he | --h)
+ # Conflict between --help and --header
+ { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+ ac_need_defaults=false;;
+
+ # This is an error.
+ -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1" ;;
+
+ esac
+ shift
+done
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+#
+# INIT-COMMANDS section.
+#
+
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+_ACEOF
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+do
+ case "$ac_config_target" in
+ # Handling of arguments.
+ "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "lib/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;;
+ "zebra/Makefile" ) CONFIG_FILES="$CONFIG_FILES zebra/Makefile" ;;
+ "ripd/Makefile" ) CONFIG_FILES="$CONFIG_FILES ripd/Makefile" ;;
+ "ripngd/Makefile" ) CONFIG_FILES="$CONFIG_FILES ripngd/Makefile" ;;
+ "bgpd/Makefile" ) CONFIG_FILES="$CONFIG_FILES bgpd/Makefile" ;;
+ "ospfd/Makefile" ) CONFIG_FILES="$CONFIG_FILES ospfd/Makefile" ;;
+ "ospf6d/Makefile" ) CONFIG_FILES="$CONFIG_FILES ospf6d/Makefile" ;;
+ "vtysh/Makefile" ) CONFIG_FILES="$CONFIG_FILES vtysh/Makefile" ;;
+ "doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+ "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+ trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+: ${TMPDIR=/tmp}
+{
+ tmp=`(umask 077 && mktemp -d -q "$TMPDIR/csXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=$TMPDIR/cs$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
+{
+ echo "$me: cannot create a temporary directory in $TMPDIR" >&2
+ { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+ s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@DEFS@,$DEFS,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@LIBS@,$LIBS,;t t
+s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s,@INSTALL_DATA@,$INSTALL_DATA,;t t
+s,@CYGPATH_W@,$CYGPATH_W,;t t
+s,@PACKAGE@,$PACKAGE,;t t
+s,@VERSION@,$VERSION,;t t
+s,@ACLOCAL@,$ACLOCAL,;t t
+s,@AUTOCONF@,$AUTOCONF,;t t
+s,@AUTOMAKE@,$AUTOMAKE,;t t
+s,@AUTOHEADER@,$AUTOHEADER,;t t
+s,@MAKEINFO@,$MAKEINFO,;t t
+s,@AMTAR@,$AMTAR,;t t
+s,@install_sh@,$install_sh,;t t
+s,@STRIP@,$STRIP,;t t
+s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t
+s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t
+s,@AWK@,$AWK,;t t
+s,@SET_MAKE@,$SET_MAKE,;t t
+s,@build@,$build,;t t
+s,@build_cpu@,$build_cpu,;t t
+s,@build_vendor@,$build_vendor,;t t
+s,@build_os@,$build_os,;t t
+s,@host@,$host,;t t
+s,@host_cpu@,$host_cpu,;t t
+s,@host_vendor@,$host_vendor,;t t
+s,@host_os@,$host_os,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@DEPDIR@,$DEPDIR,;t t
+s,@am__include@,$am__include,;t t
+s,@am__quote@,$am__quote,;t t
+s,@AMDEP_TRUE@,$AMDEP_TRUE,;t t
+s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t
+s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t
+s,@CCDEPMODE@,$CCDEPMODE,;t t
+s,@am__fastdepCC_TRUE@,$am__fastdepCC_TRUE,;t t
+s,@am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t
+s,@CPP@,$CPP,;t t
+s,@AR@,$AR,;t t
+s,@ac_ct_AR@,$ac_ct_AR,;t t
+s,@RANLIB@,$RANLIB,;t t
+s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
+s,@EGREP@,$EGREP,;t t
+s,@MULTIPATH_NUM@,$MULTIPATH_NUM,;t t
+s,@LIBPAM@,$LIBPAM,;t t
+s,@RT_METHOD@,$RT_METHOD,;t t
+s,@KERNEL_METHOD@,$KERNEL_METHOD,;t t
+s,@OTHER_METHOD@,$OTHER_METHOD,;t t
+s,@RTREAD_METHOD@,$RTREAD_METHOD,;t t
+s,@IF_METHOD@,$IF_METHOD,;t t
+s,@IF_PROC@,$IF_PROC,;t t
+s,@IPFORWARD@,$IPFORWARD,;t t
+s,@LIB_IPV6@,$LIB_IPV6,;t t
+s,@ZEBRA@,$ZEBRA,;t t
+s,@BGPD@,$BGPD,;t t
+s,@RIPD@,$RIPD,;t t
+s,@RIPNGD@,$RIPNGD,;t t
+s,@OSPFD@,$OSPFD,;t t
+s,@OSPF6D@,$OSPF6D,;t t
+s,@VTYSH@,$VTYSH,;t t
+s,@INCLUDES@,$INCLUDES,;t t
+s,@CURSES@,$CURSES,;t t
+s,@LIB_REGEX@,$LIB_REGEX,;t t
+s,@LIBOBJS@,$LIBOBJS,;t t
+s,@LTLIBOBJS@,$LTLIBOBJS,;t t
+CEOF
+
+_ACEOF
+
+ cat >>$CONFIG_STATUS <<\_ACEOF
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_lines=48
+ ac_sed_frag=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_lines # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=
+ while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ else
+ sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ fi
+ if test ! -s $tmp/subs.frag; then
+ ac_more_lines=false
+ else
+ # The purpose of the label and of the branching condition is to
+ # speed up the sed processing (if there are no `@' at all, there
+ # is no need to browse any of the substitutions).
+ # These are the two extra sed commands mentioned above.
+ (echo ':t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+ fi
+ ac_sed_frag=`expr $ac_sed_frag + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_lines`
+ fi
+ done
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+ fi
+fi # test -n "$CONFIG_FILES"
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
+# absolute.
+ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
+ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd`
+ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
+ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
+
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
+ esac
+
+ if test x"$ac_file" != x-; then
+ { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ rm -f "$ac_file"
+ fi
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ configure_input=
+ else
+ configure_input="$ac_file. "
+ fi
+ configure_input=$configure_input"Generated from `echo $ac_file_in |
+ sed 's,.*/,,'` by configure."
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo $f;;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo $f
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo $srcdir/$f
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@abs_srcdir@,$ac_abs_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;t t
+s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t
+s,@builddir@,$ac_builddir,;t t
+s,@abs_builddir@,$ac_abs_builddir,;t t
+s,@top_builddir@,$ac_top_builddir,;t t
+s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
+s,@INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+ rm -f $tmp/stdin
+ if test x"$ac_file" != x-; then
+ mv $tmp/out $ac_file
+ else
+ cat $tmp/out
+ rm -f $tmp/out
+ fi
+
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_HEADER section.
+#
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='[ ].*$,\1#\2'
+ac_dC=' '
+ac_dD=',;t'
+# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='$,\1#\2define\3'
+ac_uC=' '
+ac_uD=',;t'
+
+for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo $f;;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo $f
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo $srcdir/$f
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+ # Remove the trailing spaces.
+ sed 's/[ ]*$//' $ac_file_inputs >$tmp/in
+
+_ACEOF
+
+# Transform confdefs.h into two sed scripts, `conftest.defines' and
+# `conftest.undefs', that substitutes the proper values into
+# config.h.in to produce config.h. The first handles `#define'
+# templates, and the second `#undef' templates.
+# And first: Protect against being on the right side of a sed subst in
+# config.status. Protect against being in an unquoted here document
+# in config.status.
+rm -f conftest.defines conftest.undefs
+# Using a here document instead of a string reduces the quoting nightmare.
+# Putting comments in sed scripts is not portable.
+#
+# `end' is used to avoid that the second main sed command (meant for
+# 0-ary CPP macros) applies to n-ary macro definitions.
+# See the Autoconf documentation for `clear'.
+cat >confdef2sed.sed <<\_ACEOF
+s/[\\&,]/\\&/g
+s,[\\$`],\\&,g
+t clear
+: clear
+s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp
+t end
+s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp
+: end
+_ACEOF
+# If some macros were called several times there might be several times
+# the same #defines, which is useless. Nevertheless, we may not want to
+# sort them, since we want the *last* AC-DEFINE to be honored.
+uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines
+sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs
+rm -f confdef2sed.sed
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >>conftest.undefs <<\_ACEOF
+s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */,
+_ACEOF
+
+# Break up conftest.defines because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS
+echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS
+echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS
+echo ' :' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.defines >/dev/null
+do
+ # Write a limited-size here document to $tmp/defines.sed.
+ echo ' cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS
+ # Speed up: don't consider the non `#define' lines.
+ echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS
+ # Work around the forget-to-reset-the-flag bug.
+ echo 't clr' >>$CONFIG_STATUS
+ echo ': clr' >>$CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f $tmp/defines.sed $tmp/in >$tmp/out
+ rm -f $tmp/in
+ mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail
+ rm -f conftest.defines
+ mv conftest.tail conftest.defines
+done
+rm -f conftest.defines
+echo ' fi # grep' >>$CONFIG_STATUS
+echo >>$CONFIG_STATUS
+
+# Break up conftest.undefs because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo ' # Handle all the #undef templates' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.undefs >/dev/null
+do
+ # Write a limited-size here document to $tmp/undefs.sed.
+ echo ' cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS
+ # Speed up: don't consider the non `#undef'
+ echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS
+ # Work around the forget-to-reset-the-flag bug.
+ echo 't clr' >>$CONFIG_STATUS
+ echo ': clr' >>$CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f $tmp/undefs.sed $tmp/in >$tmp/out
+ rm -f $tmp/in
+ mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail
+ rm -f conftest.undefs
+ mv conftest.tail conftest.undefs
+done
+rm -f conftest.undefs
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ echo "/* Generated by configure. */" >$tmp/config.h
+ else
+ echo "/* $ac_file. Generated by configure. */" >$tmp/config.h
+ fi
+ cat $tmp/in >>$tmp/config.h
+ rm -f $tmp/in
+ if test x"$ac_file" != x-; then
+ if cmp -s $ac_file $tmp/config.h 2>/dev/null; then
+ { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ rm -f $ac_file
+ mv $tmp/config.h $ac_file
+ fi
+ else
+ cat $tmp/config.h
+ rm -f $tmp/config.h
+ fi
+_am_stamp_count=`expr ${_am_stamp_count-0} + 1`
+echo "timestamp for $ac_file" >`(dirname $ac_file) 2>/dev/null ||
+$as_expr X$ac_file : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X$ac_file : 'X\(//\)[^/]' \| \
+ X$ac_file : 'X\(//\)$' \| \
+ X$ac_file : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X$ac_file |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_COMMANDS section.
+#
+for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue
+ ac_dest=`echo "$ac_file" | sed 's,:.*,,'`
+ ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_dir=`(dirname "$ac_dest") 2>/dev/null ||
+$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_dest" : 'X\(//\)[^/]' \| \
+ X"$ac_dest" : 'X\(//\)$' \| \
+ X"$ac_dest" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_dest" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
+# absolute.
+ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
+ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd`
+ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
+ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
+
+
+ { echo "$as_me:$LINENO: executing $ac_dest commands" >&5
+echo "$as_me: executing $ac_dest commands" >&6;}
+ case $ac_dest in
+ depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # So let's grep whole file.
+ if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
+ dirpart=`(dirname "$mf") 2>/dev/null ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$mf" : 'X\(//\)[^/]' \| \
+ X"$mf" : 'X\(//\)$' \| \
+ X"$mf" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ else
+ continue
+ fi
+ grep '^DEP_FILES *= *[^ #]' < "$mf" > /dev/null || continue
+ # Extract the definition of DEP_FILES from the Makefile without
+ # running `make'.
+ DEPDIR=`sed -n -e '/^DEPDIR = / s///p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n -e '/^U = / s///p' < "$mf"`
+ test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR"
+ # We invoke sed twice because it is the simplest approach to
+ # changing $(DEPDIR) to its actual value in the expansion.
+ for file in `sed -n -e '
+ /^DEP_FILES = .*\\\\$/ {
+ s/^DEP_FILES = //
+ :loop
+ s/\\\\$//
+ p
+ n
+ /\\\\$/ b loop
+ p
+ }
+ /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`(dirname "$file") 2>/dev/null ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$file" : 'X\(//\)[^/]' \| \
+ X"$file" : 'X\(//\)$' \| \
+ X"$file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p $dirpart/$fdir
+ else
+ as_dir=$dirpart/$fdir
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory $dirpart/$fdir" >&5
+echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+done
+ ;;
+ esac
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
+
+
+echo "
+zebra configuration
+-------------------
+zebra version : ${VERSION}
+host operationg system : ${host_os}
+source code location : ${srcdir}
+compiler : ${CC}
+compiler flags : ${CFLAGS}
+directory for pid files : ${ac_piddir}
+"
diff --git a/configure.in b/configure.in
new file mode 100755
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 <kunihiro@zebra.org>
+##
+AC_PREREQ(2.13)
+
+AC_INIT(lib/zebra.h)
+AM_INIT_AUTOMAKE(zebra, 0.93)
+AM_CONFIG_HEADER(config.h)
+
+dnl -----------------------------------
+dnl Get hostname and other information.
+dnl -----------------------------------
+AC_CANONICAL_HOST
+
+dnl ------------
+dnl Check CFLAGS
+dnl ------------
+AC_ARG_WITH(cflags,
+[ --with-cflags Set CFLAGS for use in compilation.])
+if test "x$with_cflags" != "x" ; then
+ CFLAGS="$with_cflags" ; cflags_specified=yes ;
+elif test -n "$CFLAGS" ; then
+ cflags_specified=yes ;
+fi
+
+dnl --------
+dnl Check CC
+dnl --------
+AC_PROG_CC
+
+dnl -----------------------------------------
+dnl If CLFAGS doesn\'t exist set default value
+dnl -----------------------------------------
+if test "x$cflags_specified" = "x" ; then
+ CFLAGS="$CFLAGS -Wall"
+fi
+
+dnl --------------
+dnl Check programs
+dnl --------------
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+AC_CHECK_TOOL(AR, ar)
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+
+dnl ---------
+dnl AIX check
+dnl ---------
+AC_AIX
+
+dnl ----------------------
+dnl Packages configuration
+dnl ----------------------
+AC_ARG_ENABLE(vtysh,
+[ --enable-vtysh, Make integrated VTY version of zebra])
+AC_ARG_ENABLE(ipv6,
+[ --disable-ipv6 turn off IPv6 related features and daemons])
+AC_ARG_ENABLE(zebra,
+[ --disable-zebra do not build zebra daemon])
+AC_ARG_ENABLE(bgpd,
+[ --disable-bgpd do not build bgpd])
+AC_ARG_ENABLE(ripd,
+[ --disable-ripd do not build ripd])
+AC_ARG_ENABLE(ripngd,
+[ --disable-ripngd do not build ripngd])
+AC_ARG_ENABLE(ospfd,
+[ --disable-ospfd do not build ospfd])
+AC_ARG_ENABLE(ospf6d,
+[ --disable-ospf6d do not build ospf6d])
+AC_ARG_ENABLE(bgp-announce,
+[ --disable-bgp-announce, turn off BGP route announcement])
+AC_ARG_ENABLE(netlink,
+[ --enable-netlink force to use Linux netlink interface])
+AC_ARG_ENABLE(broken-aliases,
+[ --enable-broken-aliases enable aliases as distinct interfaces for Linux 2.2.X])
+AC_ARG_ENABLE(snmp,
+[ --enable-snmp enable SNMP support])
+AC_ARG_WITH(libpam,
+[ --with-libpam use libpam for PAM support in vtysh])
+AC_ARG_ENABLE(tcpsock,
+[ --enable-tcp-zebra enable TCP/IP socket connection between zebra and protocol daemon])
+dnl Temporary option until OSPF NSSA implementation complete
+AC_ARG_ENABLE(nssa,
+[ --enable-nssa enable OSPF NSSA option])
+AC_ARG_ENABLE(opaque-lsa,
+[ --enable-opaque-lsa enable OSPF Opaque-LSA support (RFC2370)])
+AC_ARG_ENABLE(ospf-te,
+[ --enable-ospf-te enable Traffic Engineering Extension to OSPF])
+AC_ARG_ENABLE(multipath,
+[ --enable-multipath=ARG enable multipath function, ARG must be digit])
+
+dnl AC_ARG_ENABLE(rtadv,
+dnl [ --enable-rtadv enable IPV6 router advertisment option])
+
+if test "${enable_broken_aliases}" = "yes"; then
+ if test "${enable_netlink}" = "yes"
+ then
+ echo "Sorry, you can't use netlink with broken aliases"
+ exit 1
+ fi
+ AC_DEFINE(HAVE_BROKEN_ALIASES)
+ enable_netlink=no
+fi
+
+if test "${enable_tcp_zebra}" = "yes"; then
+ AC_DEFINE(HAVE_TCP_ZEBRA)
+fi
+
+if test "${enable_nssa}" = "yes"; then
+ AC_DEFINE(HAVE_NSSA)
+fi
+
+if test "${enable_opaque_lsa}" = "yes"; then
+ AC_DEFINE(HAVE_OPAQUE_LSA)
+fi
+
+if test "${enable_ospf_te}" = "yes"; then
+ AC_DEFINE(HAVE_OPAQUE_LSA)
+ AC_DEFINE(HAVE_OSPF_TE)
+fi
+
+dnl if test "${enable_rtadv}" = "yes"; then
+dnl AC_DEFINE(HAVE_RTADV)
+dnl fi
+
+changequote(, )dnl
+
+MULTIPATH_NUM=1
+
+case "${enable_multipath}" in
+ [0-9]|[1-9][0-9])
+ MULTIPATH_NUM="${enable_multipath}"
+ ;;
+ "")
+ ;;
+ *)
+ echo "Please specify digit to --enable-multipath ARG."
+ exit 1
+ ;;
+esac
+
+changequote([, ])dnl
+
+AC_SUBST(MULTIPATH_NUM)
+
+dnl -------------------
+dnl Check header files.
+dnl -------------------
+AC_STDC_HEADERS
+AC_CHECK_HEADERS(string.h stropts.h sys/conf.h sys/ksym.h sys/time.h sys/times.h sys/select.h sys/sysctl.h sys/sockio.h sys/types.h net/if_dl.h net/if_var.h linux/version.h kvm.h netdb.h netinet/in.h net/netopt.h netinet/in_var.h netinet/in6_var.h netinet/in6.h inet/nd.h asm/types.h netinet/icmp6.h netinet6/nd6.h libutil.h)
+
+dnl check some types
+AC_C_CONST
+dnl AC_TYPE_PID_T
+AC_TYPE_SIGNAL
+
+dnl Some systems (Solaris 2.x) require libnsl (Network Services Library)
+case "$host" in
+ *-sunos5.6* | *-solaris2.6*)
+ opsys=sol2-6
+ AC_DEFINE(SUNOS_5)
+ AC_CHECK_LIB(xnet, main)
+ CURSES=-lcurses
+ ;;
+ *-sunos5* | *-solaris2*)
+ AC_DEFINE(SUNOS_5)
+ AC_CHECK_LIB(socket, main)
+ AC_CHECK_LIB(nsl, main)
+ CURSES=-lcurses
+ ;;
+ *-linux-*)
+ opsys=gnu-linux
+ AC_DEFINE(GNU_LINUX)
+ ;;
+ *-nec-sysv4*)
+ AC_CHECK_LIB(nsl, gethostbyname)
+ AC_CHECK_LIB(socket, socket)
+ ;;
+ *-freebsd3.2)
+ AC_DEFINE(FREEBSD_32)
+ ;;
+ *-openbsd*)
+ opsys=openbsd
+ AC_DEFINE(OPEN_BSD)
+ ;;
+ *-bsdi*)
+ opsys=bsdi
+ OTHER_METHOD="mtu_kvm.o"
+ AC_CHECK_LIB(kvm, main)
+ ;;
+esac
+
+case "${host_cpu}-${host_os}" in
+ i?86-solaris*)
+ AC_DEFINE(SOLARIS_X86)
+ ;;
+esac
+
+dnl ---------------------
+dnl Integrated VTY option
+dnl ---------------------
+case "${enable_vtysh}" in
+ "yes") VTYSH="vtysh";
+ AC_DEFINE(VTYSH)
+ AC_CHECK_LIB(tinfo, tputs, , AC_CHECK_LIB(ncurses, tputs))
+ AC_CHECK_LIB(readline, main)
+ if test $ac_cv_lib_readline_main = no; then
+ AC_MSG_ERROR([vtysh needs libreadline but was not found on your system.])
+ fi
+ AC_CHECK_HEADER(readline/history.h)
+ if test $ac_cv_header_readline_history_h = no;then
+ AC_MSG_ERROR([readline is too old to have readline/history.h, please update to the latest readline library.])
+ fi
+ ;;
+ "no" ) VTYSH="";;
+ * ) ;;
+esac
+
+dnl ----------
+dnl PAM module
+dnl ----------
+if test "$with_libpam" = "yes"; then
+dnl took this test from proftpd's configure.in and suited to our needs
+dnl -------------------------------------------------------------------------
+dnl
+dnl This next check looks funky due to a linker problem with some versions
+dnl of the PAM library. Prior to 0.72 release, the Linux PAM shared library
+dnl omitted requiring libdl linking information. PAM-0.72 or better ships
+dnl with RedHat 6.2 and Debian 2.2 or better.
+AC_CHECK_LIB(pam, pam_start,
+ [AC_CHECK_LIB(pam, misc_conv,
+ [AC_DEFINE(USE_PAM)
+ LIBPAM="-lpam"],
+ [AC_DEFINE(USE_PAM)
+ LIBPAM="-lpam -lpam_misc"]
+ )
+ ],
+
+ [AC_CHECK_LIB(pam, pam_end,
+ [AC_CHECK_LIB(pam, misc_conv,
+ [AC_DEFINE(USE_PAM)
+ LIBPAM="-lpam -ldl"],
+ [AC_DEFINE(USE_PAM)
+ LIBPAM="-lpam -ldl -lpam_misc"]
+ )
+ ],AC_MSG_WARN([*** pam support will not be built ***]),
+ [-ldl])
+ ]
+)
+fi
+AC_SUBST(LIBPAM)
+
+dnl -------------------------------
+dnl Endian-ness check
+dnl -------------------------------
+AC_DEFUN(ZEBRA_AC_C_BIGENDIAN,
+[AC_CACHE_CHECK(whether byte ordering is bigendian, ac_cv_c_bigendian,
+[ac_cv_c_bigendian=unknown
+# See if sys/param.h defines the BYTE_ORDER macro.
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/param.h>], [
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif], [# It does; now see whether it defined to BIG_ENDIAN or not.
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/param.h>], [
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif], ac_cv_c_bigendian=yes, ac_cv_c_bigendian=no)])
+if test $ac_cv_c_bigendian = unknown; then
+AC_TRY_RUN([main () {
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long l;
+ char c[sizeof (long)];
+ } u;
+ u.l = 1;
+ exit (u.c[sizeof (long) - 1] == 1);
+}], ac_cv_c_bigendian=no, ac_cv_c_bigendian=yes, ac_cv_c_bigendian=no)
+fi])
+if test $ac_cv_c_bigendian = yes; then
+ AC_DEFINE(WORDS_BIGENDIAN,1,Big endian words)
+fi
+])
+
+dnl -------------------------------
+dnl check the size in byte of the C
+dnl -------------------------------
+dnl AC_CHECK_SIZEOF(char)
+dnl AC_CHECK_SIZEOF(int)
+dnl AC_CHECK_SIZEOF(short)
+dnl AC_CHECK_SIZEOF(long)
+
+dnl ----------------------------
+dnl check existance of functions
+dnl ----------------------------
+AC_CHECK_FUNCS(bcopy bzero strerror inet_aton daemon snprintf vsnprintf strlcat strlcpy if_nametoindex if_indextoname getifaddrs)
+AC_CHECK_FUNCS(setproctitle, ,[AC_CHECK_LIB(util, setproctitle, [LIBS="$LIBS -lutil"; AC_DEFINE(HAVE_SETPROCTITLE)])])
+
+dnl ------------------------------------
+dnl Determine routing get and set method
+dnl ------------------------------------
+AC_MSG_CHECKING(zebra between kernel interface method)
+if test x"$opsys" = x"gnu-linux"; then
+ if test "${enable_netlink}" = "yes";then
+ AC_MSG_RESULT(netlink)
+ RT_METHOD=rt_netlink.o
+ AC_DEFINE(HAVE_NETLINK)
+ netlink=yes
+ elif test "${enable_netlink}" = "no"; then
+ AC_MSG_RESULT(ioctl)
+ RT_METHOD=rt_ioctl.o
+ netlink=no
+ else
+ AC_EGREP_CPP(yes,
+ [#include <linux/autoconf.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > 131328 /* 2.1.0 or later */
+#ifdef CONFIG_RTNETLINK
+ yes
+#endif
+#endif
+#if LINUX_VERSION_CODE > 132112 /* 2.4.17 or later */
+ yes
+#endif
+ ],
+ [AC_MSG_RESULT(netlink)
+ RT_METHOD=rt_netlink.o
+ AC_DEFINE(HAVE_NETLINK)
+ netlink=yes],
+ [AC_MSG_RESULT(ioctl)
+ RT_METHOD=rt_ioctl.o])
+ fi
+else
+ if test "$opsys" = "sol2-6";then
+ AC_MSG_RESULT(solaris)
+ KERNEL_METHOD="kernel_socket.o"
+ RT_METHOD="rt_socket.o"
+ else
+ AC_TRY_RUN([#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+main ()
+{
+ int ac_sock;
+
+ ac_sock = socket (AF_ROUTE, SOCK_RAW, 0);
+ if (ac_sock < 0 && errno == EINVAL)
+ exit (1);
+ exit (0);
+}],
+ [AC_DEFINE(HAVE_AF_ROUTE)
+ KERNEL_METHOD=kernel_socket.o
+ RT_METHOD=rt_socket.o
+ AC_MSG_RESULT(socket)],
+ [RT_METHOD=rt_ioctl.o
+ AC_MSG_RESULT(ioctl)],
+ [KERNEL_METHOD=kernel_socket.o
+ RT_METHOD=rt_socket.o
+ AC_MSG_RESULT(socket)])
+ fi
+fi
+AC_SUBST(RT_METHOD)
+AC_SUBST(KERNEL_METHOD)
+AC_SUBST(OTHER_METHOD)
+
+dnl ------------------------------
+dnl check kernel route read method
+dnl ------------------------------
+AC_CACHE_CHECK(route read method check, zebra_rtread,
+[if test "$netlink" = yes; then
+ RTREAD_METHOD="rtread_netlink.o"
+ zebra_rtread="netlink"
+else
+for zebra_rtread in /proc/net/route /dev/ip /dev/null;
+do
+ test x`ls $zebra_rtread 2>/dev/null` = x"$zebra_rtread" && break
+done
+case $zebra_rtread in
+ "/proc/net/route") RTREAD_METHOD="rtread_proc.o"
+ zebra_rtread="proc";;
+ "/dev/ip") RTREAD_METHOD="rtread_getmsg.o"
+ zebra_rtread="getmsg";;
+ *) RTREAD_METHOD="rtread_sysctl.o"
+ zebra_rtread="sysctl";;
+esac
+fi])
+AC_SUBST(RTREAD_METHOD)
+
+dnl -----------------------------
+dnl check interface lookup method
+dnl -----------------------------
+AC_MSG_CHECKING(interface looking up method)
+if test "$netlink" = yes; then
+ AC_MSG_RESULT(netlink)
+ IF_METHOD=if_netlink.o
+else
+ if test "$opsys" = "sol2-6";then
+ AC_MSG_RESULT(solaris)
+ IF_METHOD=if_ioctl.o
+ elif test "$opsys" = "openbsd";then
+ AC_MSG_RESULT(openbsd)
+ IF_METHOD=if_ioctl.o
+ elif grep NET_RT_IFLIST /usr/include/sys/socket.h >/dev/null 2>&1; then
+ AC_MSG_RESULT(sysctl)
+ IF_METHOD=if_sysctl.o
+ AC_DEFINE(HAVE_NET_RT_IFLIST)
+ else
+ AC_MSG_RESULT(ioctl)
+ IF_METHOD=if_ioctl.o
+ fi
+fi
+AC_SUBST(IF_METHOD)
+
+dnl -----------------------
+dnl check proc file system.
+dnl -----------------------
+if test -r /proc/net/dev; then
+ AC_DEFINE(HAVE_PROC_NET_DEV)
+ IF_PROC=if_proc.o
+fi
+
+if test -r /proc/net/if_inet6; then
+ AC_DEFINE(HAVE_PROC_NET_IF_INET6)
+ IF_PROC=if_proc.o
+fi
+AC_SUBST(IF_PROC)
+
+dnl -----------------------------
+dnl check ipforward detect method
+dnl -----------------------------
+AC_CACHE_CHECK(ipforward method check, zebra_ipforward_path,
+[for zebra_ipforward_path in /proc/net/snmp /dev/ip /dev/null;
+do
+ test x`ls $zebra_ipforward_path 2>/dev/null` = x"$zebra_ipforward_path" && break
+done
+case $zebra_ipforward_path in
+ "/proc/net/snmp") IPFORWARD=ipforward_proc.o
+ zebra_ipforward_path="proc";;
+ "/dev/ip")
+ case "$host" in
+ *-nec-sysv4*) IPFORWARD=ipforward_ews.o
+ zebra_ipforward_path="ews";;
+ *) IPFORWARD=ipforward_solaris.o
+ zebra_ipforward_path="solaris";;
+ esac;;
+ *) IPFORWARD=ipforward_sysctl.o
+ zebra_ipforward_path="sysctl";;
+esac])
+AC_SUBST(IPFORWARD)
+
+AC_CHECK_FUNCS(getaddrinfo, [have_getaddrinfo=yes], [have_getaddrinfo=no])
+
+dnl ----------
+dnl IPv6 check
+dnl ----------
+AC_MSG_CHECKING(whether does this OS have IPv6 stack)
+if test "${enable_ipv6}" = "no"; then
+ AC_MSG_RESULT(disabled)
+else
+dnl ----------
+dnl INRIA IPv6
+dnl ----------
+if grep IPV6_INRIA_VERSION /usr/include/netinet/in.h >/dev/null 2>&1; then
+ zebra_cv_ipv6=yes
+ AC_DEFINE(HAVE_IPV6)
+ AC_DEFINE(INRIA_IPV6)
+ RIPNGD="ripngd"
+ OSPF6D="ospf6d"
+ LIB_IPV6=""
+ AC_MSG_RESULT(INRIA IPv6)
+fi
+dnl ---------
+dnl KAME IPv6
+dnl ---------
+if grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then
+ zebra_cv_ipv6=yes
+ AC_DEFINE(HAVE_IPV6)
+ AC_DEFINE(KAME)
+ RIPNGD="ripngd"
+ OSPF6D="ospf6d"
+ if test -d /usr/local/v6/lib -a -f /usr/local/v6/lib/libinet6.a; then
+ LIB_IPV6="-L/usr/local/v6/lib -linet6"
+ fi
+ AC_MSG_RESULT(KAME)
+fi
+dnl ---------
+dnl NRL check
+dnl ---------
+if grep NRL /usr/include/netinet6/in6.h >/dev/null 2>&1; then
+ zebra_cv_ipv6=yes
+ AC_DEFINE(HAVE_IPV6)
+ AC_DEFINE(NRL)
+ RIPNGD="ripngd"
+ OSPF6D="ospf6d"
+ if test x"$opsys" = x"bsdi";then
+ AC_DEFINE(BSDI_NRL)
+ AC_MSG_RESULT(BSDI_NRL)
+ else
+ AC_MSG_RESULT(NRL)
+ fi
+fi
+
+dnl ----------
+dnl Linux IPv6
+dnl ----------
+if test "${enable_ipv6}" = "yes"; then
+ AC_EGREP_CPP(yes, [
+ #include <linux/version.h>
+ /* 2.1.128 or later */
+ #if LINUX_VERSION_CODE >= 0x020180
+ yes
+ #endif],
+ [zebra_cv_ipv6=yes; zebra_cv_linux_ipv6=yes;AC_MSG_RESULT(Linux IPv6)])
+else
+ if test x`ls /proc/net/ipv6_route 2>/dev/null` = x"/proc/net/ipv6_route"
+ then
+ zebra_cv_ipv6=yes
+ zebra_cv_linux_ipv6=yes
+ AC_MSG_RESULT(Linux IPv6)
+ fi
+fi
+
+if test "$zebra_cv_linux_ipv6" = "yes";then
+ AC_DEFINE(HAVE_IPV6)
+ AC_MSG_CHECKING(for GNU libc 2.1)
+ AC_EGREP_CPP(yes, [
+#include <features.h>
+#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
+ yes
+#endif], [glibc=yes; AC_MSG_RESULT(yes)], AC_MSG_RESULT(no))
+ AC_DEFINE(LINUX_IPV6)
+ RIPNGD="ripngd"
+ OSPF6D="ospf6d"
+ if test "$glibc" != "yes"; then
+ INCLUDES="-I/usr/inet6/include"
+ if test x`ls /usr/inet6/lib/libinet6.a 2>/dev/null` != x;then
+ LIB_IPV6="-L/usr/inet6/lib -linet6"
+ fi
+ fi
+fi
+
+dnl -----------------------
+dnl Set IPv6 related values
+dnl -----------------------
+LIBS="$LIB_IPV6 $LIBS"
+AC_SUBST(LIB_IPV6)
+
+if test x"$RIPNGD" = x""; then
+ AC_MSG_RESULT(IPv4 only)
+fi
+fi
+
+dnl --------------------
+dnl Daemon disable check
+dnl --------------------
+if test "${enable_zebra}" = "no";then
+ ZEBRA=""
+else
+ ZEBRA="zebra"
+fi
+
+if test "${enable_bgpd}" = "no";then
+ BGPD=""
+else
+ BGPD="bgpd"
+fi
+
+if test "${enable_ripd}" = "no";then
+ RIPD=""
+else
+ RIPD="ripd"
+fi
+
+if test "${enable_ospfd}" = "no";then
+ OSPFD=""
+else
+ OSPFD="ospfd"
+fi
+
+case "${enable_ripngd}" in
+ "yes") RIPNGD="ripngd";;
+ "no" ) RIPNGD="";;
+ * ) ;;
+esac
+
+case "${enable_ospf6d}" in
+ "yes") OSPF6D="ospf6d";;
+ "no" ) OSPF6D="";;
+ * ) ;;
+esac
+
+if test "${enable_bgp_announce}" = "no";then
+ AC_DEFINE(DISABLE_BGP_ANNOUNCE)
+fi
+
+AC_SUBST(ZEBRA)
+AC_SUBST(BGPD)
+AC_SUBST(RIPD)
+AC_SUBST(RIPNGD)
+AC_SUBST(OSPFD)
+AC_SUBST(OSPF6D)
+AC_SUBST(VTYSH)
+AC_SUBST(INCLUDES)
+AC_SUBST(CURSES)
+AC_CHECK_LIB(c, inet_ntop, [AC_DEFINE(HAVE_INET_NTOP)])
+AC_CHECK_LIB(c, inet_pton, [AC_DEFINE(HAVE_INET_PTON)])
+AC_CHECK_LIB(crypt, crypt)
+AC_CHECK_LIB(resolv, res_init)
+AC_CHECK_LIB(m, main)
+
+dnl ---------------------------------------------------
+dnl BSD/OS 4.1 define inet_XtoY function as __inet_XtoY
+dnl ---------------------------------------------------
+AC_CHECK_FUNC(__inet_ntop, AC_DEFINE(HAVE_INET_NTOP))
+AC_CHECK_FUNC(__inet_pton, AC_DEFINE(HAVE_INET_PTON))
+AC_CHECK_FUNC(__inet_aton, AC_DEFINE(HAVE_INET_ATON))
+
+dnl ---------------------------
+dnl check system has GNU regexp
+dnl ---------------------------
+dnl AC_MSG_CHECKING(whether system has GNU regex)
+AC_CHECK_LIB(c, regexec,
+[AC_DEFINE(HAVE_GNU_REGEX)
+ LIB_REGEX=""],
+[LIB_REGEX="regex.o"])
+AC_SUBST(LIB_REGEX)
+
+dnl AC_MSG_CHECKING(whether system has GNU regex)
+dnl if grep RE_NO_GNU_OPS /usr/include/regex.h >/dev/null 2>&1; then
+dnl AC_MSG_RESULT(yes)
+dnl AC_DEFINE(HAVE_GNU_REGEX)
+dnl LIB_REGEX=""
+dnl else
+dnl AC_MSG_RESULT(no)
+dnl LIB_REGEX="regex.o"
+dnl fi
+dnl AC_SUBST(LIB_REGEX)
+
+dnl ------------------
+dnl check SNMP library
+dnl ------------------
+if test "${enable_snmp}" = "yes";then
+dnl AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes)
+ old_libs="${LIBS}"
+ LIBS="-L/usr/local/lib"
+ unset ac_cv_lib_snmp_asn_parse_int
+ AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes, )
+ if test "${HAVE_SNMP}" = ""; then
+ unset ac_cv_lib_snmp_asn_parse_int
+ AC_CHECK_LIB(crypto, main, [NEED_CRYPTO=yes ], )
+ if test "${NEED_CRYPTO}" = ""; then
+ AC_CHECK_LIB(snmp, asn_parse_int, [HAVE_SNMP=yes; NEED_CRYPTO=yes ],)
+ else
+ AC_CHECK_LIB(snmp, asn_parse_int, [HAVE_SNMP=yes; NEED_CRYPTO=yes;LIBS="$LIBS -lcrypto" ],,"-lcrypto")
+ fi
+ fi
+ LIBS="${old_libs}"
+
+ if test "${HAVE_SNMP}" = ""; then
+ old_libs="${LIBS}"
+ LIBS="-L/usr/local/lib"
+ AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes)
+ LIBS="${old_libs}"
+ fi
+ if test "${HAVE_SNMP}" = "yes"; then
+ for ac_snmp in /usr/include/ucd-snmp/asn1.h /usr/local/include/ucd-snmp/asn1.h /dev/null
+ do
+ test -f "${ac_snmp}" && break
+ done
+ case ${ac_snmp} in
+ /usr/include/ucd-snmp/*)
+ AC_DEFINE(HAVE_SNMP)
+ CFLAGS="${CFLAGS} -I/usr/include/ucd-snmp"
+ LIBS="${LIBS} -lsnmp"
+ ;;
+ /usr/local/include/ucd-snmp/*)
+ AC_DEFINE(HAVE_SNMP)
+ CFLAGS="${CFLAGS} -I/usr/local/include/ucd-snmp"
+ LIBS="${LIBS} -L/usr/local/lib -lsnmp"
+ ;;
+ esac
+ if test "${NEED_CRYPTO}" = "yes"; then
+ LIBS="${LIBS} -lcrypto"
+ fi
+ fi
+fi
+
+dnl ----------------------------
+dnl check sa_len of sockaddr
+dnl ----------------------------
+AC_MSG_CHECKING(whether struct sockaddr has a sa_len field)
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/socket.h>
+],[static struct sockaddr ac_i;int ac_j = sizeof (ac_i.sa_len);],
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SA_LEN)],
+ AC_MSG_RESULT(no))
+
+dnl ----------------------------
+dnl check sin_len of sockaddr_in
+dnl ----------------------------
+AC_MSG_CHECKING(whether struct sockaddr_in has a sin_len field)
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <netinet/in.h>
+],[static struct sockaddr_in ac_i;int ac_j = sizeof (ac_i.sin_len);],
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SIN_LEN)],
+ AC_MSG_RESULT(no))
+
+dnl ----------------------------
+dnl check sun_len of sockaddr_un
+dnl ----------------------------
+AC_MSG_CHECKING(whether struct sockaddr_un has a sun_len field)
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/un.h>
+],[static struct sockaddr_un ac_i;int ac_j = sizeof (ac_i.sun_len);],
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SUN_LEN)],
+ AC_MSG_RESULT(no))
+
+dnl -----------------------------------
+dnl check sin6_scope_id of sockaddr_in6
+dnl -----------------------------------
+if test "$zebra_cv_ipv6" = yes; then
+ AC_MSG_CHECKING(whether struct sockaddr_in6 has a sin6_scope_id field)
+ AC_TRY_COMPILE([#include <sys/types.h>
+#include <netinet/in.h>
+],[static struct sockaddr_in6 ac_i;int ac_j = sizeof (ac_i.sin6_scope_id);],
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SIN6_SCOPE_ID)],
+ AC_MSG_RESULT(no))
+fi
+
+dnl ----------------------------
+dnl check socklen_t exist or not
+dnl ----------------------------
+AC_MSG_CHECKING(whther socklen_t is defined)
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+],[socklen_t ac_x;],
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SOCKLEN_T)],
+ AC_MSG_RESULT(no))
+
+dnl ------------------------
+dnl check struct sockaddr_dl
+dnl ------------------------
+AC_MSG_CHECKING(whether struct sockaddr_dl exist)
+AC_EGREP_HEADER(sockaddr_dl,
+net/if_dl.h,
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SOCKADDR_DL)],
+ AC_MSG_RESULT(no))
+
+dnl --------------------------
+dnl check structure ifaliasreq
+dnl --------------------------
+AC_MSG_CHECKING(whether struct ifaliasreq exist)
+AC_EGREP_HEADER(ifaliasreq,
+net/if.h,
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_IFALIASREQ)],
+ AC_MSG_RESULT(no))
+
+dnl ----------------------------
+dnl check structure in6_aliasreq
+dnl ----------------------------
+AC_MSG_CHECKING(whether struct if6_aliasreq exist)
+AC_EGREP_HEADER(in6_aliasreq,
+netinet6/in6_var.h,
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_IN6_ALIASREQ)],
+ AC_MSG_RESULT(no))
+
+dnl ---------------------------
+dnl check structure rt_addrinfo
+dnl ---------------------------
+AC_MSG_CHECKING(whether struct rt_addrinfo exist)
+AC_EGREP_HEADER(rt_addrinfo,
+net/route.h,
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_RT_ADDRINFO)],
+ AC_MSG_RESULT(no))
+
+dnl --------------------------
+dnl check structure in_pktinfo
+dnl --------------------------
+AC_MSG_CHECKING(whether struct in_pktinfo exist)
+AC_TRY_COMPILE([#include <netinet/in.h>
+],[struct in_pktinfo ac_x;],
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_INPKTINFO)],
+ AC_MSG_RESULT(no))
+
+dnl --------------------------------------
+dnl checking for getrusage struct and call
+dnl --------------------------------------
+AC_MSG_CHECKING(whether getrusage is available)
+AC_TRY_COMPILE([#include <sys/resource.h>
+],[struct rusage ac_x; getrusage (RUSAGE_SELF, &ac_x);],
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_RUSAGE)],
+ AC_MSG_RESULT(no))
+
+dnl -------------
+dnl check version
+dnl -------------
+file="${srcdir}/lib/version.h"
+VERSION=`sed -ne 's/^#.*ZEBRA_VERSION.*\"\([^\"]*\)\"$/\1/p' $file`
+AC_SUBST(VERSION)
+
+dnl ------------------------------
+dnl set paths for process id files
+dnl ------------------------------
+AC_CACHE_CHECK(pid file directory,ac_piddir,
+[for ZEBRA_PID_DIR in /var/run dnl
+ /var/adm dnl
+ /etc dnl
+ /dev/null;
+do
+ test -d $ZEBRA_PID_DIR && break
+done
+ac_piddir=$ZEBRA_PID_DIR
+if test $ZEBRA_PID_DIR = "/dev/null"; then
+ echo "PID DIRECTORY NOT FOUND!"
+fi])
+AC_DEFINE_UNQUOTED(PATH_ZEBRA_PID, "$ac_piddir/zebra.pid")
+AC_DEFINE_UNQUOTED(PATH_RIPD_PID, "$ac_piddir/ripd.pid")
+AC_DEFINE_UNQUOTED(PATH_RIPNGD_PID, "$ac_piddir/ripngd.pid")
+AC_DEFINE_UNQUOTED(PATH_BGPD_PID, "$ac_piddir/bgpd.pid")
+AC_DEFINE_UNQUOTED(PATH_OSPFD_PID, "$ac_piddir/ospfd.pid")
+AC_DEFINE_UNQUOTED(PATH_OSPF6D_PID, "$ac_piddir/ospf6d.pid")
+
+
+dnl ---------------------------
+dnl Check htonl works correctly
+dnl ---------------------------
+AC_MSG_CHECKING(for working htonl)
+AC_CACHE_VAL(ac_cv_htonl_works, [
+AC_TRY_LINK([#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif],
+[htonl (0);],
+ac_cv_htonl_works=yes,
+ac_cv_htonl_works=no)])
+AC_MSG_RESULT($ac_cv_htonl_works)
+
+AC_OUTPUT(Makefile lib/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile ospf6d/Makefile vtysh/Makefile doc/Makefile)
+
+echo "
+zebra configuration
+-------------------
+zebra version : ${VERSION}
+host operationg system : ${host_os}
+source code location : ${srcdir}
+compiler : ${CC}
+compiler flags : ${CFLAGS}
+directory for pid files : ${ac_piddir}
+"
diff --git a/depcomp b/depcomp
new file mode 100755
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 <oliva@dcc.unicamp.br>.
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+# `libtool' can also be set to `yes' or `no'.
+
+if test -z "$depfile"; then
+ base=`echo "$object" | sed -e 's,^.*/,,' -e 's,\.\([^.]*\)$,.P\1,'`
+ dir=`echo "$object" | sed 's,/.*$,/,'`
+ if test "$dir" = "$object"; then
+ dir=
+ fi
+ # FIXME: should be _deps on DOS.
+ depfile="$dir.deps/$base"
+fi
+
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+ "$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+ tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'. On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like `#:fec' to the end of the
+ # dependency line.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+ tr '
+' ' ' >> $depfile
+ echo >> $depfile
+
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> $depfile
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. This file always lives in the current directory.
+ # Also, the AIX compiler puts `$object:' at the start of each line;
+ # $object doesn't have directory information.
+ stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'`
+ tmpdepfile="$stripped.u"
+ outname="$stripped.o"
+ if test "$libtool" = yes; then
+ "$@" -Wc,-M
+ else
+ "$@" -M
+ fi
+
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+
+ if test -f "$tmpdepfile"; then
+ # Each line is of the form `foo.o: dependent.h'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
+ sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in `foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+ if test "$libtool" = yes; then
+ tmpdepfile1="$dir.libs/$base.lo.d"
+ tmpdepfile2="$dir.libs/$base.d"
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1="$dir$base.o.d"
+ tmpdepfile2="$dir$base.d"
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2"
+ exit $stat
+ fi
+
+ if test -f "$tmpdepfile1"; then
+ tmpdepfile="$tmpdepfile1"
+ else
+ tmpdepfile="$tmpdepfile2"
+ fi
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a space and a tab in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the proprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'. We will use -o /dev/null later,
+ # however we can't do the remplacement now because
+ # `-o $object' might simply not be used
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ "$@" -o /dev/null $dashmflag | sed 's:^[^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # X makedepend
+ shift
+ cleared=no
+ for arg in "$@"; do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ -*)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix="`echo $object | sed 's/^.*\././'`"
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the proprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E |
+ sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+ sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the proprocessed file to stdout, regardless of -o,
+ # because we must use -o when running libtool.
+ "$@" || exit $?
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
+ echo " " >> "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/doc/.cvsignore b/doc/.cvsignore
new file mode 100644
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 <kunihiro@ipinfusion.com>
+
+ * zebra-0.93 released.
+
+2001-02-07 Pekka Savola <pekkas@netcore.fi>
+
+ * Correct bad English ;-).
+
+2001-02-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.91 released.
+
+2001-01-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.90 released.
+
+2000-10-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.89 released.
+
+2000-10-02 Horms <horms@vergenet.net>
+
+ * Makefile.am: Fix texinfo file installation problem.
+
+2000-08-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.88 released.
+
+ * ospfd.texi (Redistribute routes to OSPF): distance <1-255>
+ @var{source} command is temporary disabled. So it is removed from
+ document.
+
+2000-07-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh.1: Add man entry for vtysh.
+
+ * bgpd.1: Change section to 8.
+ * ospfd.1: Likewise.
+ * ospf6d.1: Likewise.
+ * ripd.1: Likewise.
+ * ripngd.1: Likewise.
+ * zebra.1: Likewise.
+
+1999-09-01 "A.Waddington" <waddington@usa.net>
+
+ * zebra.texi: Replace @command with @code until it gets ready.
+ Remove @macro.
+
+1999-08-26 Andrew Waddington <waddington@usa.net>
+
+ * bgpd.1: Add man page.
+ ospf6d.1: Likewise.
+ ospfd.1: Likewise.
+ ripd.1: Likewise.
+ ripngd.1: Likewise.
+ zebra.1: Likewise.
+
+1999-08-14 Andrew Waddington <waddington@usa.net>
+
+ * zebra.texi: Many typo is fixed. Some grammatical rectifications
+ is made.
+
+1999-07-27 Gerhard Poul <gpoul@gnu.org>
+
+ * zebra.texi: Update zebra.texi.
+
+1999-07-02 Gerhard Poul <gpoul@gnu.org>
+
+ * draft-zebra-00.ms: New file added. This is groff version of
+ draft-zebra-00.txt. This is a master file of draft-zebra-00.txt.
+
+ * draft-zebra-00.txt: Generated from draft-zebra-00.txt.
+
+1999-05-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra.texi (Top): Add ospf6d chapter.
+
+1999-03-31 Jeroen Ruigrok/Asmodai <asmodai@wxs.nl>
+
+ * zebra.texi: Improve some sections.
+
+1999-03-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * archfig.tex, zebra.sty, zebra.tex: Temporary removed due to the
+ description is out of date.
+
+1999-02-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * texinfo.tex: New file added. Automake complains the absence of
+ texinfo.tex.
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
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 <bug-zebra@gnu.org>
+
+
+.SH AUTHOR[S]
+See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors.
+
diff --git a/doc/bgpd.texi b/doc/bgpd.texi
new file mode 100644
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 <kunihiro@zebra.org>
+@c See file zebra.texi for copying conditions.
+@node BGP
+@comment node-name, next, previous, up
+@chapter BGP
+
+ BGP stands for a Border Gateway Protocol. The lastest BGP version
+is 4. It is referred as BGP-4. BGP-4 is one of the Exterior Gateway
+Protocols and de-fact standard of Inter Domain routing protocol.
+BGP-4 is described in @code{RFC1771} - @cite{A Border Gateway Protocol
+4 (BGP-4)}.
+
+ Many extentions are added to @code{RFC1771}. @code{RFC2858} -
+@cite{Multiprotocol Extensions for BGP-4} provide multiprotocol
+support to BGP-4.
+
+@menu
+* Starting BGP::
+* BGP router::
+* BGP network::
+* BGP Peer::
+* BGP Peer Group::
+* BGP Address Family::
+* Autonomous System::
+* BGP Communities Attribute::
+* BGP Extended Communities Attribute::
+* Displaying BGP routes::
+* Capability Negotiation::
+* Route Reflector::
+* Route Server::
+* How to set up a 6-Bone connection::
+* Dump BGP packets and table::
+@end menu
+
+@node Starting BGP, BGP router, BGP, BGP
+@comment node-name, next, previous, up
+@section Starting BGP
+
+Default configuration file of @command{bgpd} is @file{bgpd.conf}.
+@command{bgpd} searches the current directory first then
+@value{INSTALL_PREFIX_ETC}/bgpd.conf. All of bgpd's command must be
+configured in @file{bgpd.conf}.
+
+@command{bgpd} specific invocation options are described below. Common
+options may also be specified (@pxref{Common Invocation Options}).
+
+@table @samp
+@item -p @var{PORT}
+@itemx --bgp_port=@var{PORT}
+Set the bgp protocol's port number.
+
+@item -r
+@itemx --retain
+When program terminates, retain BGP routes added by zebra.
+@end table
+
+@node BGP router, BGP network, Starting BGP, BGP
+@comment node-name, next, previous, up
+@section BGP router
+
+ First of all you must configure BGP router with @command{router bgp}
+command. To configure BGP router, you need AS number. AS number is an
+identification of autonomous system. BGP protocol uses the AS number
+for detecting whether the BGP connection is internal one or external one.
+
+@deffn Command {router bgp @var{asn}} {}
+Enable a BGP protocol process with the specified @var{asn}. After
+this statement you can input any @code{BGP Commands}. You can not
+create different BGP process under different @var{asn} without
+specifying @code{multiple-instance} (@pxref{Multiple instance}).
+@end deffn
+
+@deffn Command {no router bgp @var{asn}} {}
+Destroy a BGP protocol process with the specified @var{asn}.
+@end deffn
+
+@deffn {BGP} {bgp router-id @var{A.B.C.D}} {}
+This command specifies the router-ID. If @command{bgpd} connects to @command{zebra} it gets
+interface and address information. In that case default router ID value
+is selected as the largest IP Address of the interfaces. When
+@code{router zebra} is not enabled @command{bgpd} can't get interface information
+so @code{router-id} is set to 0.0.0.0. So please set router-id by hand.
+@end deffn
+
+@menu
+* BGP distance::
+* BGP decision process::
+@end menu
+
+@node BGP distance, BGP decision process, BGP router, BGP router
+@comment node-name, next, previous, up
+@subsection BGP distance
+
+@deffn {BGP} {distance bgp <1-255> <1-255> <1-255>} {}
+This command change distance value of BGP. Each argument is distance
+value for external routes, internal routes and local routes.
+@end deffn
+
+@deffn {BGP} {distance <1-255> @var{A.B.C.D/M}} {}
+@deffnx {BGP} {distance <1-255> @var{A.B.C.D/M} @var{word}} {}
+This command set distance value to
+@end deffn
+
+@node BGP decision process, , BGP distance, BGP router
+@comment node-name, next, previous, up
+@subsection BGP decision process
+
+@table @asis
+@item 1. Weight check
+
+@item 2. Local preference check.
+
+@item 3. Local route check.
+
+@item 4. AS path length check.
+
+@item 5. Origin check.
+
+@item 6. MED check.
+@end table
+
+@node BGP network, BGP Peer, BGP router, BGP
+@comment node-name, next, previous, up
+@section BGP network
+
+@menu
+* BGP route::
+* Route Aggregation::
+* Redistribute to BGP::
+@end menu
+
+@node BGP route, Route Aggregation, BGP network, BGP network
+@comment node-name, next, previous, up
+@subsection BGP route
+
+@deffn {BGP} {network @var{A.B.C.D/M}} {}
+This command adds the announcement network.
+@example
+@group
+router bgp 1
+ network 10.0.0.0/8
+@end group
+@end example
+This configuration example says that network 10.0.0.0/8 will be
+announced to all neighbors. Some vendors' routers don't advertise
+routes if they aren't present in their IGP routing tables; @code{bgp}
+doesn't care about IGP routes when announcing its routes.
+@end deffn
+
+@deffn {BGP} {no network @var{A.B.C.D/M}} {}
+@end deffn
+
+@node Route Aggregation, Redistribute to BGP, BGP route, BGP network
+@comment node-name, next, previous, up
+@subsection Route Aggregation
+
+@deffn {BGP} {aggregate-address @var{A.B.C.D/M}} {}
+This command specifies an aggregate address.
+@end deffn
+
+@deffn {BGP} {aggregate-address @var{A.B.C.D/M} as-set} {}
+This command specifies an aggregate address. Resulting routes inlucde
+AS set.
+@end deffn
+
+@deffn {BGP} {aggregate-address @var{A.B.C.D/M} summary-only} {}
+This command specifies an aggregate address. Aggreated routes will
+not be announce.
+@end deffn
+
+@deffn {BGP} {no aggregate-address @var{A.B.C.D/M}} {}
+@end deffn
+
+@node Redistribute to BGP, , Route Aggregation, BGP network
+@comment node-name, next, previous, up
+@subsection Redistribute to BGP
+
+@deffn {BGP} {redistribute kernel} {}
+Redistribute kernel route to BGP process.
+@end deffn
+
+@deffn {BGP} {redistribute static} {}
+Redistribute static route to BGP process.
+@end deffn
+
+@deffn {BGP} {redistribute connected} {}
+Redistribute connected route to BGP process.
+@end deffn
+
+@deffn {BGP} {redistribute rip} {}
+Redistribute RIP route to BGP process.
+@end deffn
+
+@deffn {BGP} {redistribute ospf} {}
+Redistribute OSPF route to BGP process.
+@end deffn
+
+@node BGP Peer, BGP Peer Group, BGP network, BGP
+@comment node-name, next, previous, up
+@section BGP Peer
+
+@menu
+* Defining Peer::
+* BGP Peer commands::
+* Peer filtering::
+@end menu
+
+@node Defining Peer, BGP Peer commands, BGP Peer, BGP Peer
+@comment node-name, next, previous, up
+@subsection Defining Peer
+
+@deffn {BGP} {neighbor @var{peer} remote-as @var{asn}} {}
+Creates a new neighbor whose remote-as is @var{asn}. @var{peer}
+can be an IPv4 address or an IPv6 address.
+@example
+@group
+router bgp 1
+ neighbor 10.0.0.1 remote-as 2
+@end group
+@end example
+In this case my router, in AS-1, is trying to peer with AS-2 at
+10.0.0.1.
+
+This command must be the first command used when configuring a neighbor.
+If the remote-as is not specified, @command{bgpd} will complain like this:
+@example
+can't find neighbor 10.0.0.1
+@end example
+@end deffn
+
+@node BGP Peer commands, Peer filtering, Defining Peer, BGP Peer
+@comment node-name, next, previous, up
+@subsection BGP Peer commands
+
+In a @code{router bgp} clause there are neighbor specific configurations
+required.
+
+@deffn {BGP} {neighbor @var{peer} shutdown} {}
+@deffnx {BGP} {no neighbor @var{peer} shutdown} {}
+Shutdown the peer. We can delete the neighbor's configuration by
+@code{no neighbor @var{peer} remote-as @var{as-number}} but all
+configuration of the neighbor will be deleted. When you want to
+preserve the configuration, but want to drop the BGP peer, use this
+syntax.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} ebgp-multihop} {}
+@deffnx {BGP} {no neighbor @var{peer} ebgp-multihop} {}
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} description ...} {}
+@deffnx {BGP} {no neighbor @var{peer} description ...} {}
+Set description of the peer.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} version @var{version}} {}
+Set up the neighbor's BGP version. @var{version} can be @var{4},
+@var{4+} or @var{4-}. BGP version @var{4} is the default value used for
+BGP peering. BGP version @var{4+} means that the neighbor supports
+Multiprotocol Extensions for BGP-4. BGP version @var{4-} is similar but
+the neighbor speaks the old Internet-Draft revision 00's Multiprotocol
+Extensions for BGP-4. Some routing software is still using this
+version.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} interface @var{ifname}} {}
+@deffnx {BGP} {no neighbor @var{peer} interface @var{ifname}} {}
+When you connect to a BGP peer over an IPv6 link-local address, you have
+to specify the @var{ifname} of the interface used for the connection.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} next-hop-self} {}
+@deffnx {BGP} {no neighbor @var{peer} next-hop-self} {}
+This command specifies an announced route's nexthop as being equivalent
+to the address of the bgp router.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} update-source} {}
+@deffnx {BGP} {no neighbor @var{peer} update-source} {}
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} default-originate} {}
+@deffnx {BGP} {no neighbor @var{peer} default-originate} {}
+@command{bgpd}'s default is to not announce the default route (0.0.0.0/0) even it
+is in routing table. When you want to announce default routes to the
+peer, use this command.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} port @var{port}} {}
+@deffnx {BGP} {neighbor @var{peer} port @var{port}} {}
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} send-community} {}
+@deffnx {BGP} {neighbor @var{peer} send-community} {}
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} weight @var{weight}} {}
+@deffnx {BGP} {no neighbor @var{peer} weight @var{weight}} {}
+This command specifies a default @var{weight} value for the neighbor's
+routes.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} maximum-prefix @var{number}} {}
+@deffnx {BGP} {no neighbor @var{peer} maximum-prefix @var{number}} {}
+@end deffn
+
+@node Peer filtering, , BGP Peer commands, BGP Peer
+@comment node-name, next, previous, up
+@subsection Peer filtering
+
+@deffn {BGP} {neighbor @var{peer} distribute-list @var{name} [in|out]} {}
+This command specifies a distribute-list for the peer. @var{direct} is
+@samp{in} or @samp{out}.
+@end deffn
+
+@deffn {BGP command} {neighbor @var{peer} prefix-list @var{name} [in|out]} {}
+@end deffn
+
+@deffn {BGP command} {neighbor @var{peer} filter-list @var{name} [in|out]} {}
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} route-map @var{name} [in|out]} {}
+Apply a route-map on the neighbor. @var{direct} must be @code{in} or
+@code{out}.
+@end deffn
+
+@c -----------------------------------------------------------------------
+@node BGP Peer Group, BGP Address Family, BGP Peer, BGP
+@comment node-name, next, previous, up
+@section BGP Peer Group
+
+@deffn {BGP} {neighbor @var{word} peer-group} {}
+This command defines a new peer group.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} peer-group @var{word}} {}
+This command bind specific peer to peer group @var{word}.
+@end deffn
+
+@node BGP Address Family, Autonomous System, BGP Peer Group, BGP
+@comment node-name, next, previous, up
+@section BGP Address Family
+
+
+
+@page
+@c -----------------------------------------------------------------------
+@node Autonomous System, BGP Communities Attribute, BGP Address Family, BGP
+@comment node-name, next, previous, up
+@section Autonomous System
+
+ AS (Autonomous System) is one of the essential element of BGP. BGP
+is a distance vector routing protocol. AS framework provides distance
+vector metric and loop detection to BGP. @code{RFC1930} -
+@cite{Guidelines for creation, selection, and registration of an
+Autonomous System (AS)} describes how to use AS.
+
+ AS number is tow octet digita value. So the value range is from 1
+to 65535. AS numbers 64512 through 65535 are defined as private AS
+numbers. Private AS numbers must not to be advertised in the global
+Internet.
+
+@menu
+* AS Path Regular Expression::
+* Display BGP Routes by AS Path::
+* AS Path Access List::
+* Using AS Path in Route Map::
+* Private AS Numbers::
+@end menu
+
+@node AS Path Regular Expression, Display BGP Routes by AS Path, Autonomous System, Autonomous System
+@comment node-name, next, previous, up
+@subsection AS Path Regular Expression
+
+ AS path regular expression can be used for displaying BGP routes and
+AS path access list. AS path regular expression is based on
+@code{POSIX 1003.2} regular expressions. Following description is
+just a subset of @code{POSIX} regular expression. User can use full
+@code{POSIX} regular expression. Adding to that special character '_'
+is added for AS path regular expression.
+
+@table @code
+@item .
+Matches any single character.
+@item *
+Matches 0 or more occurrences of pattern.
+@item +
+Matches 1 or more occurrences of pattern.
+@item ?
+Match 0 or 1 occurrences of pattern.
+@item ^
+Matches the beginning of the line.
+@item $
+Matches the end of the line.
+@item _
+Character @code{_} has special meanings in AS path regular expression.
+It matches to space and comma , and AS set delimiter @{ and @} and AS
+confederation delimiter @code{(} and @code{)}. And it also matches to
+the beginning of the line and the end of the line. So @code{_} can be
+used for AS value boundaries match. @code{show ip bgp regexp _7675_}
+matches to all of BGP routes which as AS number include @var{7675}.
+@end table
+
+@node Display BGP Routes by AS Path, AS Path Access List, AS Path Regular Expression, Autonomous System
+@comment node-name, next, previous, up
+@subsection Display BGP Routes by AS Path
+
+ To show BGP routes which has specific AS path information @code{show
+ip bgp} command can be used.
+
+@deffn Command {show ip bgp regexp @var{line}} {}
+This commands display BGP routes that matches AS path regular
+expression @var{line}.
+@end deffn
+
+@node AS Path Access List, Using AS Path in Route Map, Display BGP Routes by AS Path, Autonomous System
+@comment node-name, next, previous, up
+@subsection AS Path Access List
+
+ AS path access list is user defined AS path.
+
+@deffn {Command} {ip as-path access-list @var{word} @{permit|deny@} @var{line}} {}
+This command defines a new AS path access list.
+@end deffn
+
+@deffn {Command} {no ip as-path access-list @var{word}} {}
+@deffnx {Command} {no ip as-path access-list @var{word} @{permit|deny@} @var{line}} {}
+@end deffn
+
+@node Using AS Path in Route Map, Private AS Numbers, AS Path Access List, Autonomous System
+@comment node-name, next, previous, up
+@subsection Using AS Path in Route Map
+
+@deffn {Route Map} {match as-path @var{word}} {}
+@end deffn
+
+@deffn {Route Map} {set as-path prepend @var{as-path}} {}
+@end deffn
+
+@node Private AS Numbers, , Using AS Path in Route Map, Autonomous System
+@comment node-name, next, previous, up
+@subsection Private AS Numbers
+
+@page
+@c -----------------------------------------------------------------------
+@node BGP Communities Attribute, BGP Extended Communities Attribute, Autonomous System, BGP
+@comment node-name, next, previous, up
+@section BGP Communities Attribute
+
+ BGP communities attribute is widely used for implementing policy
+routing. Network operators can manipulate BGP communities attribute
+based on their network policy. BGP communities attribute is defined
+in @code{RFC1997} - @cite{BGP Communities Attribute} and
+@code{RFC1998} - @cite{An Application of the BGP Community Attribute
+in Multi-home Routing}. It is an optional transitive attribute,
+therefore local policy can travel through different autonomous system.
+
+ Communities attribute is a set of communities values. Each
+communities value is 4 octet long. The following format is used to
+define communities value.
+
+@table @code
+@item AS:VAL
+This format represents 4 octet communities value. @code{AS} is high
+order 2 octet in digit format. @code{VAL} is low order 2 octet in
+digit format. This format is useful to define AS oriented policy
+value. For example, @code{7675:80} can be used when AS 7675 wants to
+pass local policy value 80 to neighboring peer.
+@item internet
+@code{internet} represents well-known communities value 0.
+@item no-export
+@code{no-export} represents well-known communities value @code{NO_EXPORT}@*
+@r{(0xFFFFFF01)}. All routes carry this value must not be advertised
+to outside a BGP confederation boundary. If neighboring BGP peer is
+part of BGP confederation, the peer is considered as inside a BGP
+confederation boundary, so the route will be announced to the peer.
+@item no-advertise
+@code{no-advertise} represents well-known communities value
+@code{NO_ADVERTISE}@*@r{(0xFFFFFF02)}. All routes carry this value
+must not be advertise to other BGP peers.
+@item local-AS
+@code{local-AS} represents well-known communities value
+@code{NO_EXPORT_SUBCONFED} @r{(0xFFFFFF03)}. All routes carry this
+value must not be advertised to external BGP peers. Even if the
+neighboring router is part of confederation, it is considered as
+external BGP peer, so the route will not be announced to the peer.
+@end table
+
+ When BGP communities attribute is received, duplicated communities
+value in the communities attribute is ignored and each communities
+values are sorted in numerical order.
+
+@menu
+* BGP Community Lists::
+* Numbered BGP Community Lists::
+* BGP Community in Route Map::
+* Display BGP Routes by Community::
+* Using BGP Communities Attribute::
+@end menu
+
+@node BGP Community Lists, Numbered BGP Community Lists, BGP Communities Attribute, BGP Communities Attribute
+@comment node-name, next, previous, up
+@subsection BGP Community Lists
+
+ BGP community list is a user defined BGP communites attribute list.
+BGP community list can be used for matching or manipulating BGP
+communities attribute in updates.
+
+ There are two types of community list. One is standard community
+list and another is expanded community list. Standard community list
+defines communities attribute. Expanded community list defines
+communities attribute string with regular expression. Standard
+community list is compiled into binary format when user define it.
+Standard community list will be directly compared to BGP communities
+attribute in BGP updates. Therefore the comparison is faster than
+expanded community list.
+
+@deffn Command {ip community-list standard @var{name} @{permit|deny@} @var{community}} {}
+This command defines a new standard community list. @var{community}
+is communities value. The @var{community} is compiled into community
+structure. We can define multiple community list under same name. In
+that case match will happen user defined order. Once the
+community list matches to communities attribute in BGP updates it
+return permit or deny by the community list definition. When there is
+no matched entry, deny will be returned. When @var{community} is
+empty it matches to any routes.
+@end deffn
+
+@deffn Command {ip community-list expanded @var{name} @{permit|deny@} @var{line}} {}
+This command defines a new expanded community list. @var{line} is a
+string expression of communities attribute. @var{line} can include
+regular expression to match communities attribute in BGP updates.
+@end deffn
+
+@deffn Command {no ip community-list @var{name}} {}
+@deffnx Command {no ip community-list standard @var{name}} {}
+@deffnx Command {no ip community-list expanded @var{name}} {}
+These commands delete community lists specified by @var{name}. All of
+community lists shares a single name space. So community lists can be
+removed simpley specifying community lists name.
+@end deffn
+
+@deffn {Command} {show ip community-list} {}
+@deffnx {Command} {show ip community-list @var{name}} {}
+This command display current community list information. When
+@var{name} is specified the specified community list's information is
+shown.
+
+@example
+# show ip community-list
+Named Community standard list CLIST
+ permit 7675:80 7675:100 no-export
+ deny internet
+Named Community expanded list EXPAND
+ permit :
+
+# show ip community-list CLIST
+Named Community standard list CLIST
+ permit 7675:80 7675:100 no-export
+ deny internet
+@end example
+@end deffn
+
+@node Numbered BGP Community Lists, BGP Community in Route Map, BGP Community Lists, BGP Communities Attribute
+@comment node-name, next, previous, up
+@subsection Numbered BGP Community Lists
+
+ When number is used for BGP community list name, the number has
+special meanings. Community list number in the range from 1 and 99 is
+standard community list. Community list number in the range from 100
+to 199 is expanded community list. These community lists are called
+as numbered community lists. On the other hand normal community lists
+is called as named community lists.
+
+@deffn Command {ip community-list <1-99> @{permit|deny@} @var{community}} {}
+This command defines a new community list. <1-99> is standard
+community list number. Community list name within this range defines
+standard community list. When @var{community} is empty it matches to
+any routes.
+@end deffn
+
+@deffn Command {ip community-list <100-199> @{permit|deny@} @var{community}} {}
+This command defines a new community list. <100-199> is expanded
+community list number. Community list name within this range defines
+expanded community list.
+@end deffn
+
+@deffn Command {ip community-list @var{name} @{permit|deny@} @var{community}} {}
+When community list type is not specifed, the community list type is
+automatically detected. If @var{community} can be compiled into
+communities attribute, the community list is defined as a standard
+community list. Otherwise it is defined as an expanded community
+list. This feature is left for backward compability. Use of this
+feature is not recommended.
+@end deffn
+
+@node BGP Community in Route Map, Display BGP Routes by Community, Numbered BGP Community Lists, BGP Communities Attribute
+@comment node-name, next, previous, up
+@subsection BGP Community in Route Map
+
+ In Route Map (@pxref{Route Map}), we can match or set BGP
+communities attribute. Using this feature network operator can
+implement their network policy based on BGP communities attribute.
+
+ Following commands can be used in Route Map.
+
+@deffn {Route Map} {match community @var{word}} {}
+@deffnx {Route Map} {match community @var{word} exact-match} {}
+This command perform match to BGP updates using community list
+@var{word}. When the one of BGP communities value match to the one of
+communities value in community list, it is match. When
+@code{exact-match} keyword is spcified, match happen only when BGP
+updates have completely same communities value specified in the
+community list.
+@end deffn
+
+@deffn {Route Map} {set community none} {}
+@deffnx {Route Map} {set community @var{community}} {}
+@deffnx {Route Map} {set community @var{community} additive} {}
+This command manipulate communities value in BGP updates. When
+@code{none} is specified as communities value, it removes entire
+communities attribute from BGP updates. When @var{community} is not
+@code{none}, specified communities value is set to BGP updates. If
+BGP updates already has BGP communities value, the existing BGP
+communities value is replaced with specified @var{community} value.
+When @code{additive} keyword is specified, @var{community} is appended
+to the existing communities value.
+@end deffn
+
+@deffn {Route Map} {set comm-list @var{word} delete} {}
+This command remove communities value from BGP communities attribute.
+The @var{word} is community list name. When BGP route's communities
+value matches to the community list @var{word}, the communities value
+is removed. When all of communities value is removed eventually, the
+BGP update's communities attribute is completely removed.
+@end deffn
+
+@node Display BGP Routes by Community, Using BGP Communities Attribute, BGP Community in Route Map, BGP Communities Attribute
+@comment node-name, next, previous, up
+@subsection Display BGP Routes by Community
+
+ To show BGP routes which has specific BGP communities attribute,
+@code{show ip bgp} command can be used. The @var{community} value and
+community list can be used for @code{show ip bgp} command.
+
+@deffn Command {show ip bgp community} {}
+@deffnx Command {show ip bgp community @var{community}} {}
+@deffnx Command {show ip bgp community @var{community} exact-match} {}
+@code{show ip bgp community} displays BGP routes which has communities
+attribute. When @var{community} is specified, BGP routes that matches
+@var{community} value is displayed. For this command, @code{internet}
+keyword can't be used for @var{community} value. When
+@code{exact-match} is specified, it display only routes that have an
+exact match.
+@end deffn
+
+@deffn Command {show ip bgp community-list @var{word}} {}
+@deffnx Command {show ip bgp community-list @var{word} exact-match} {}
+This commands display BGP routes that matches community list
+@var{word}. When @code{exact-match} is specified, display only routes
+that have an exact match.
+@end deffn
+
+@node Using BGP Communities Attribute, , Display BGP Routes by Community, BGP Communities Attribute
+@comment node-name, next, previous, up
+@subsection Using BGP Communities Attribute
+
+ Following configuration is the most typical usage of BGP communities
+attribute. AS 7675 provides upstream Internet connection to AS 100.
+When following configuration exists in AS 7675, AS 100 networks
+operator can set local preference in AS 7675 network by setting BGP
+communities attribute to the updates.
+
+@example
+router bgp 7675
+ neighbor 192.168.0.1 remote-as 100
+ neighbor 192.168.0.1 route-map RMAP in
+!
+ip community-list 70 permit 7675:70
+ip community-list 70 deny
+ip community-list 80 permit 7675:80
+ip community-list 80 deny
+ip community-list 90 permit 7675:90
+ip community-list 90 deny
+!
+route-map RMAP permit 10
+ match community 70
+ set local-preference 70
+!
+route-map RMAP permit 20
+ match community 80
+ set local-preference 80
+!
+route-map RMAP permit 30
+ match community 90
+ set local-preference 90
+@end example
+
+ Following configuration announce 10.0.0.0/8 from AS 100 to AS 7675.
+The route has communities value 7675:80 so when above configuration
+exists in AS 7675, announced route's local preference will be set to
+value 80.
+
+@example
+router bgp 100
+ network 10.0.0.0/8
+ neighbor 192.168.0.2 remote-as 7675
+ neighbor 192.168.0.2 route-map RMAP out
+!
+ip prefix-list PLIST permit 10.0.0.0/8
+!
+route-map RMAP permit 10
+ match ip address prefix-list PLIST
+ set community 7675:80
+@end example
+
+ Following configuration is an example of BGP route filtering using
+communities attribute. This configuration only permit BGP routes
+which has BGP communities value 0:80 or 0:90. Network operator can
+put special internal communities value at BGP border router, then
+limit the BGP routes announcement into the internal network.
+
+@example
+router bgp 7675
+ neighbor 192.168.0.1 remote-as 100
+ neighbor 192.168.0.1 route-map RMAP in
+!
+ip community-list 1 permit 0:80 0:90
+!
+route-map RMAP permit in
+ match community 1
+@end example
+
+ Following exmaple filter BGP routes which has communities value 1:1.
+When there is no match community-list returns deny. To avoid
+filtering all of routes, we need to define permit any at last.
+
+@example
+router bgp 7675
+ neighbor 192.168.0.1 remote-as 100
+ neighbor 192.168.0.1 route-map RMAP in
+!
+ip community-list standard FILTER deny 1:1
+ip community-list standard FILTER permit
+!
+route-map RMAP permit 10
+ match community FILTER
+@end example
+
+ Communities value keyword @code{internet} has special meanings in
+standard community lists. In below example @code{internet} act as
+match any. It matches all of BGP routes even if the route does not
+have communities attribute at all. So community list @code{INTERNET}
+is same as above example's @code{FILTER}.
+
+@example
+ip community-list standard INTERNET deny 1:1
+ip community-list standard INTERNET permit internet
+@end example
+
+ Following configuration is an example of communities value deletion.
+With this configuration communities value 100:1 and 100:2 is removed
+from BGP updates. For communities value deletion, only @code{permit}
+community-list is used. @code{deny} community-list is ignored.
+
+@example
+router bgp 7675
+ neighbor 192.168.0.1 remote-as 100
+ neighbor 192.168.0.1 route-map RMAP in
+!
+ip community-list standard DEL permit 100:1 100:2
+!
+route-map RMAP permit 10
+ set comm-list DEL delete
+@end example
+
+@c -----------------------------------------------------------------------
+@node BGP Extended Communities Attribute, Displaying BGP routes, BGP Communities Attribute, BGP
+@comment node-name, next, previous, up
+@section BGP Extended Communities Attribute
+
+ BGP extended communities attribute is introduced with MPLS VPN/BGP
+technology. MPLS VPN/BGP expands capability of network infrastructure
+to provide VPN functionality. At the same time it requires a new
+framework for policy routing. With BGP Extended Communities Attribute
+we can use Route Target or Site of Origin for implementing network
+policy for MPLS VPN/BGP.
+
+ BGP Extended Communities Attribute is similar to BGP Communities
+Attribute. It is an optional transitive attribute. BGP Extended
+Communities Attribute can carry multiple Extended Community value.
+Each Extended Community value is eight octet length.
+
+ BGP Extended Communities Attribute provides an extended range
+compared with BGP Communities Attribute. Adding to that there is a
+type field in each value to provides community space structure.
+
+ There are two format to define Extended Community value. One is AS
+based format the other is IP address based format.
+
+@table @code
+@item AS:VAL
+This is a format to define AS based Extended Community value.
+@code{AS} part is 2 octets Global Administrator subfield in Extended
+Community value. @code{VAL} part is 4 octets Local Administrator
+subfield. @code{7675:100} represents AS 7675 policy value 100.
+@item IP-Address:VAL
+This is a format to define IP address based Extended Community value.
+@code{IP-Address} part is 4 octets Global Administrator subfield.
+@code{VAL} part is 2 octets Local Administrator subfield.
+@code{10.0.0.1:100} represents
+@end table
+
+@menu
+* BGP Extended Community Lists::
+* BGP Extended Communities in Route Map::
+@end menu
+
+@node BGP Extended Community Lists, BGP Extended Communities in Route Map, BGP Extended Communities Attribute, BGP Extended Communities Attribute
+@comment node-name, next, previous, up
+@subsection BGP Extended Community Lists
+
+ Expanded Community Lists is a user defined BGP Expanded Community
+Lists.
+
+@deffn Command {ip extcommunity-list standard @var{name} @{permit|deny@} @var{extcommunity}} {}
+This command defines a new standard extcommunity-list.
+@var{extcommunity} is extended communities value. The
+@var{extcommunity} is compiled into extended community structure. We
+can define multiple extcommunity-list under same name. In that case
+match will happen user defined order. Once the extcommunity-list
+matches to extended communities attribute in BGP updates it return
+permit or deny based upon the extcommunity-list definition. When
+there is no matched entry, deny will be returned. When
+@var{extcommunity} is empty it matches to any routes.
+@end deffn
+
+@deffn Command {ip extcommunity-list expanded @var{name} @{permit|deny@} @var{line}} {}
+This command defines a new expanded extcommunity-list. @var{line} is
+a string expression of extended communities attribute. @var{line} can
+include regular expression to match extended communities attribute in
+BGP updates.
+@end deffn
+
+@deffn Command {no ip extcommunity-list @var{name}} {}
+@deffnx Command {no ip extcommunity-list standard @var{name}} {}
+@deffnx Command {no ip extcommunity-list expanded @var{name}} {}
+These commands delete extended community lists specified by
+@var{name}. All of extended community lists shares a single name
+space. So extended community lists can be removed simpley specifying
+the name.
+@end deffn
+
+@deffn {Command} {show ip extcommunity-list} {}
+@deffnx {Command} {show ip extcommunity-list @var{name}} {}
+This command display current extcommunity-list information. When
+@var{name} is specified the community list's information is shown.
+
+@example
+# show ip extcommunity-list
+@end example
+@end deffn
+
+@node BGP Extended Communities in Route Map, , BGP Extended Community Lists, BGP Extended Communities Attribute
+@comment node-name, next, previous, up
+@subsection BGP Extended Communities in Route Map
+
+@deffn {Route Map} {match extcommunity @var{word}} {}
+@end deffn
+
+@deffn {Route Map} {set extcommunity rt @var{extcommunity}} {}
+This command set Route Target value.
+@end deffn
+
+@deffn {Route Map} {set extcommunity soo @var{extcommunity}} {}
+This command set Site of Origin value.
+@end deffn
+
+@c -----------------------------------------------------------------------
+@node Displaying BGP routes, Capability Negotiation, BGP Extended Communities Attribute, BGP
+@comment node-name, next, previous, up
+@section Displaying BGP Routes
+
+@menu
+* Show IP BGP::
+* More Show IP BGP::
+@end menu
+
+@node Show IP BGP, More Show IP BGP, Displaying BGP routes, Displaying BGP routes
+@comment node-name, next, previous, up
+@subsection Show IP BGP
+
+@deffn {Command} {show ip bgp} {}
+@deffnx {Command} {show ip bgp @var{A.B.C.D}} {}
+@deffnx {Command} {show ip bgp @var{X:X::X:X}} {}
+This command displays BGP routes. When no route is specified it
+display all of IPv4 BGP routes.
+@end deffn
+
+@example
+BGP table version is 0, local router ID is 10.1.1.1
+Status codes: s suppressed, d damped, h history, * valid, > best, i - internal
+Origin codes: i - IGP, e - EGP, ? - incomplete
+
+ Network Next Hop Metric LocPrf Weight Path
+*> 1.1.1.1/32 0.0.0.0 0 32768 i
+
+Total number of prefixes 1
+@end example
+
+@node More Show IP BGP, , Show IP BGP, Displaying BGP routes
+@comment node-name, next, previous, up
+@subsection More Show IP BGP
+
+@deffn {Command} {show ip bgp regexp @var{line}} {}
+This command display BGP routes using AS path regular expression (@pxref{Display BGP Routes by AS Path}).
+@end deffn
+
+@deffn Command {show ip bgp community @var{community}} {}
+@deffnx Command {show ip bgp community @var{community} exact-match} {}
+This command display BGP routes using @var{community} (@pxref{Display
+BGP Routes by Community}).
+@end deffn
+
+@deffn Command {show ip bgp community-list @var{word}} {}
+@deffnx Command {show ip bgp community-list @var{word} exact-match} {}
+This command display BGP routes using community list (@pxref{Display
+BGP Routes by Community}).
+@end deffn
+
+@deffn {Command} {show ip bgp summary} {}
+@end deffn
+
+@deffn {Command} {show ip bgp neighbor [@var{peer}]} {}
+@end deffn
+
+@deffn {Command} {clear ip bgp @var{peer}} {}
+Clear peers which have addresses of X.X.X.X
+@end deffn
+
+@deffn {Command} {clear ip bgp @var{peer} soft in} {}
+Clear peer using soft reconfiguration.
+@end deffn
+
+@deffn {Command} {show debug} {}
+@end deffn
+
+@deffn {Command} {debug event} {}
+@end deffn
+
+@deffn {Command} {debug update} {}
+@end deffn
+
+@deffn {Command} {debug keepalive} {}
+@end deffn
+
+@deffn {Command} {no debug event} {}
+@end deffn
+
+@deffn {Command} {no debug update} {}
+@end deffn
+
+@deffn {Command} {no debug keepalive} {}
+@end deffn
+
+@node Capability Negotiation, Route Reflector, Displaying BGP routes, BGP
+@comment node-name, next, previous, up
+@section Capability Negotiation
+
+ When adding IPv6 routing information exchange feature to BGP. There
+were some proposals. @acronym{IETF} @acronym{IDR} working group finally
+take a proposal called Multiprotocol Extension for BGP. The
+specification is described in RFC2283. The protocol does not define new
+protocols. It defines new attributes to existing BGP. When it is used
+exchanging IPv6 routing information it is called BGP-4+. When it is
+used for exchanging multicast routing information it is called MBGP.
+
+ @command{bgpd} supports Multiprotocol Extension for BGP. So if remote peer
+supports the protocol, @command{bgpd} can exchange IPv6 and/or multicast routing
+information.
+
+ Traditional BGP does not have the feature to detect remote peer's
+capability whether it can handle other than IPv4 unicast routes. This
+is a big problem using Multiprotocol Extension for BGP to operational
+network. @cite{draft-ietf-idr-bgp4-cap-neg-04.txt} is proposing a
+feature called Capability Negotiation. @command{bgpd} use this Capability
+Negotiation to detect remote peer's capabilities. If the peer is only
+configured as IPv4 unicast neighbor, @command{bgpd} does not send these Capability
+Negotiation packets.
+
+ By default, Zebra will bring up peering with minimal common capability
+for the both sides. For example, local router has unicast and multicast
+capabilitie and remote router has unicast capability. In this case,
+the local router will establish the connection with unicast only capability.
+When there are no common capabilities, Zebra sends Unsupported Capability
+error and then resets the connection.
+
+ If you want to completely match capabilities with remote peer. Please
+use @command{strict-capability-match} command.
+
+@deffn {BGP} {neighbor @var{peer} strict-capability-match} {}
+@deffnx {BGP} {no neighbor @var{peer} strict-capability-match} {}
+Strictly compares remote capabilities and local capabilities. If capabilities
+are different, send Unsupported Capability error then reset connection.
+@end deffn
+
+ You may want to disable sending Capability Negotiation OPEN message
+optional parameter to the peer when remote peer does not implement
+Capability Negotiation. Please use @command{dont-capability-negotiate}
+command to disable the feature.
+
+@deffn {BGP} {neighbor @var{peer} dont-capability-negotiate} {}
+@deffnx {BGP} {no neighbor @var{peer} dont-capability-negotiate} {}
+Suppress sending Capability Negotiation as OPEN message optional
+parameter to the peer. This command only affects the peer is configured
+other than IPv4 unicast configuration.
+@end deffn
+
+ When remote peer does not have capability negotiation feature, remote
+peer will not send any capabilities at all. In that case, bgp configures
+the peer with configured capabilities.
+
+ You may prefer locally configured capabilities more than the negotiated
+capabilities even though remote peer sends capabilities. If the peer is
+configured by @command{override-capability}, @command{bgpd} ignores received
+capabilities then override negotiated capabilities with configured values.
+
+@deffn {BGP} {neighbor @var{peer} override-capability} {}
+@deffnx {BGP} {no neighbor @var{peer} override-capability} {}
+Override the result of Capability Negotiation with local configuration.
+Ignore remote peer's capability value.
+@end deffn
+
+@node Route Reflector, Route Server, Capability Negotiation, BGP
+@comment node-name, next, previous, up
+@section Route Reflector
+
+@deffn {BGP} {bgp cluster-id @var{a.b.c.d}} {}
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} route-reflector-client} {}
+@deffnx {BGP} {no neighbor @var{peer} route-reflector-client} {}
+@end deffn
+
+@node Route Server, How to set up a 6-Bone connection, Route Reflector, BGP
+@comment node-name, next, previous, up
+@section Route Server
+
+At an Internet Exchange point, many ISPs are connected to each other by
+external BGP peering. Normally these external BGP connection are done by
+@code{full mesh} method. As with internal BGP full mesh formation,
+this method has a scaling problem.
+
+This scaling problem is well known. Route Server is a method to resolve
+the problem. Each ISP's BGP router only peers to Route Server. Route
+Server serves as BGP information exchange to other BGP routers. By
+applying this method, numbers of BGP connections is reduced from
+O(n*(n-1)/2) to O(n).
+
+Unlike normal BGP router, Route Server must have several routing tables
+for managing different routing policies for each BGP speaker. We call the
+routing tables as different @code{view}s. @command{bgpd} can work as
+normal BGP router or Route Server or both at the same time.
+
+@menu
+* Multiple instance::
+* BGP instance and view::
+* Routing policy::
+* Viewing the view::
+@end menu
+
+@node Multiple instance, BGP instance and view, Route Server, Route Server
+@comment node-name, next, previous, up
+@subsection Multiple instance
+
+To enable multiple view function of @code{bgpd}, you must turn on
+multiple instance feature beforehand.
+
+@deffn {Command} {bgp multiple-instance} {}
+Enable BGP multiple instance feature. After this feature is enabled,
+you can make multiple BGP instances or multiple BGP views.
+@end deffn
+
+@deffn {Command} {no bgp multiple-instance} {}
+Disable BGP multiple instance feature. You can not disable this feature
+when BGP multiple instances or views exist.
+@end deffn
+
+When you want to make configuration more Cisco like one,
+
+@deffn {Command} {bgp config-type cisco} {}
+Cisco compatible BGP configuration output.
+@end deffn
+
+When bgp config-type cisco is specified,
+
+``no synchronization'' is displayed.
+``no auto-summary'' is desplayed.
+
+``network'' and ``aggregate-address'' argument is displayed as
+``A.B.C.D M.M.M.M''
+
+Zebra: network 10.0.0.0/8
+Cisco: network 10.0.0.0
+
+Zebra: aggregate-address 192.168.0.0/24
+Cisco: aggregate-address 192.168.0.0 255.255.255.0
+
+Community attribute handling is also different. If there is no
+configuration is specified community attribute and extended community
+attribute are sent to neighbor. When user manually disable the
+feature community attribute is not sent to the neighbor. In case of
+``bgp config-type cisco'' is specified, community attribute is not
+sent to the neighbor by default. To send community attribute user has
+to specify ``neighbor A.B.C.D send-community'' command.
+
+!
+router bgp 1
+ neighbor 10.0.0.1 remote-as 1
+ no neighbor 10.0.0.1 send-community
+!
+
+!
+router bgp 1
+ neighbor 10.0.0.1 remote-as 1
+ neighbor 10.0.0.1 send-community
+!
+
+@deffn {Command} {bgp config-type zebra} {}
+Zebra style BGP configuration. This is default.
+@end deffn
+
+@node BGP instance and view, Routing policy, Multiple instance, Route Server
+@comment node-name, next, previous, up
+@subsection BGP instance and view
+
+BGP instance is a normal BGP process. The result of route selection
+goes to the kernel routing table. You can setup different AS at the
+same time when BGP multiple instance feature is enabled.
+
+@deffn {Command} {router bgp @var{as-number}} {}
+Make a new BGP instance. You can use arbitrary word for the @var{name}.
+@end deffn
+
+@example
+@group
+bgp multiple-instance
+!
+router bgp 1
+ neighbor 10.0.0.1 remote-as 2
+ neighbor 10.0.0.2 remote-as 3
+!
+router bgp 2
+ neighbor 10.0.0.3 remote-as 4
+ neighbor 10.0.0.4 remote-as 5
+@end group
+@end example
+
+BGP view is almost same as normal BGP process. The result of
+route selection does not go to the kernel routing table. BGP view is
+only for exchanging BGP routing information.
+
+@deffn {Command} {router bgp @var{as-number} view @var{name}} {}
+Make a new BGP view. You can use arbitrary word for the @var{name}. This
+view's route selection result does not go to the kernel routing table.
+@end deffn
+
+With this command, you can setup Route Server like below.
+
+@example
+@group
+bgp multiple-instance
+!
+router bgp 1 view 1
+ neighbor 10.0.0.1 remote-as 2
+ neighbor 10.0.0.2 remote-as 3
+!
+router bgp 2 view 2
+ neighbor 10.0.0.3 remote-as 4
+ neighbor 10.0.0.4 remote-as 5
+@end group
+@end example
+
+@node Routing policy, Viewing the view, BGP instance and view, Route Server
+@comment node-name, next, previous, up
+@subsection Routing policy
+
+You can set different routing policy for a peer. For example, you can
+set different filter for a peer.
+
+@example
+@group
+bgp multiple-instance
+!
+router bgp 1 view 1
+ neighbor 10.0.0.1 remote-as 2
+ neighbor 10.0.0.1 distribute-list 1 in
+!
+router bgp 1 view 2
+ neighbor 10.0.0.1 remote-as 2
+ neighbor 10.0.0.1 distribute-list 2 in
+@end group
+@end example
+
+This means BGP update from a peer 10.0.0.1 goes to both BGP view 1 and view
+2. When the update is inserted into view 1, distribute-list 1 is
+applied. On the other hand, when the update is inserted into view 2,
+distribute-list 2 is applied.
+
+@node Viewing the view, , Routing policy, Route Server
+@comment node-name, next, previous, up
+@subsection Viewing the view
+
+To display routing table of BGP view, you must specify view name.
+
+@deffn {Command} {show ip bgp view @var{name}} {}
+Display routing table of BGP view @var{name}.
+@end deffn
+
+@node How to set up a 6-Bone connection, Dump BGP packets and table, Route Server, BGP
+@comment node-name, next, previous, up
+@section How to set up a 6-Bone connection
+
+@example
+@group
+zebra configuration
+===================
+!
+! Actually there is no need to configure zebra
+!
+
+bgpd configuration
+==================
+!
+! This means that routes go through zebra and into the kernel.
+!
+router zebra
+!
+! MP-BGP configuration
+!
+router bgp 7675
+ bgp router-id 10.0.0.1
+ neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 remote-as @var{as-number}
+!
+ address-family ipv6
+ network 3ffe:506::/32
+ neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 activate
+ neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 route-map set-nexthop out
+ neighbor 3ffe:1cfa:0:2:2c0:4fff:fe68:a231 remote-as @var{as-number}
+ neighbor 3ffe:1cfa:0:2:2c0:4fff:fe68:a231 route-map set-nexthop out
+ exit-address-family
+!
+ipv6 access-list all permit any
+!
+! Set output nexthop address.
+!
+route-map set-nexthop permit 10
+ match ipv6 address all
+ set ipv6 nexthop global 3ffe:1cfa:0:2:2c0:4fff:fe68:a225
+ set ipv6 nexthop local fe80::2c0:4fff:fe68:a225
+!
+! logfile FILENAME is obsolete. Please use log file FILENAME
+!
+log file bgpd.log
+!
+@end group
+@end example
+
+@node Dump BGP packets and table, , How to set up a 6-Bone connection, BGP
+@comment node-name, next, previous, up
+@section Dump BGP packets and table
+
+@deffn Command {dump bgp all @var{path}} {}
+@deffnx Command {dump bgp all @var{path} @var{interval}} {}
+Dump all BGP packet and events to @var{path} file.
+@end deffn
+
+@deffn Command {dump bgp updates @var{path}} {}
+@deffnx Command {dump bgp updates @var{path} @var{interval}} {}
+Dump BGP updates to @var{path} file.
+@end deffn
+
+@deffn Command {dump bgp routes @var{path}} {}
+@deffnx Command {dump bgp routes @var{path}} {}
+Dump whole BGP routing table to @var{path}. This is heavy process.
+@end deffn
diff --git a/doc/draft-zebra-00.ms b/doc/draft-zebra-00.ms
new file mode 100644
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 <masklength,
+prefix>
+.sp
+.in 0
+.DS
++----------------------+
+|Subnet mask (1 octet) |
++----------------------+
+|IPv4 prefix (variable)|
++----------------------+
+.DE
+.sp
+.in 0
+.ne 4
+IPv6 reply message formats
+.sp
+.in 0
+.DS
+0 1 2 3
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+
+| Type (1) |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Gateway (16) |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.DE
+.sp
+.in 3
+Type field specify route's origin type.
+.sp
+.in 0
+.DS
+1 - ZEBRA_ROUTE_RESERVE
+2 - ZEBRA_ROUTE_CONNECT
+3 - ZEBRA_ROUTE_STATIC
+4 - ZEBRA_ROUTE_RIP
+5 - ZEBRA_ROUTE_RIPNG
+6 - ZEBRA_ROUTE_BGP
+7 - ZEBRA_ROUTE_RADIX
+.DE
+.sp
+.in 0
+.DS
++----------------------+
+| ifindex (4 octet) |
++----------------------+
+| prefixlen (1 octet)|
++----------------------+
+|IPv6 prefix (variable)|
++----------------------+
+.DE
+.sp
+.in 3
+I am not sure but it seems some operation systems IPv6
+implementation may need interface index when add and delete
+linklocal routes.
+.sp
+I have added ifindex field to specify IPv6 routes interface
+index. If this index is value zero, it will ignored.
+.sp
+.in 0
+.ne 4
+Interface information message format.
+.sp
+.in 0
+.DS
+0 1 2 3
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Interface name (20) |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Index (1) |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Inteface flag (4) |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Inteface metric (4) |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Inteface MTU (4) |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Inteface Address count (4) |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.DE
+.sp
+.in 3
+Address message format.
+.sp
+.in 0
+.ne 4
+Host inforamtion message format.
+.sp
+.in 0
+.DS
+0 1 2 3
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|IPv4 forwarding|IPv6 forwarding|
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.DE
+.sp
+.in 3
+Host information contain IPv4/IPv6 forwarding information.
diff --git a/doc/filter.texi b/doc/filter.texi
new file mode 100644
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 <bug-zebra@gnu.org>
+
+
+.SH AUTHOR[S]
+See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors.
+
diff --git a/doc/ospf6d.texi b/doc/ospf6d.texi
new file mode 100644
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 <cr>".
+@end deffn
+
+@deffn {Command} {show ipv6 ospf6 database} {}
+This command shows LSA database summary. You can specify the type of LSA.
+@end deffn
+
+@deffn {Command} {show ipv6 ospf6 interface} {}
+To see OSPF interface configuration like costs.
+@end deffn
+
+@deffn {Command} {show ipv6 ospf6 neighbor} {}
+Shows state and chosen (Backup) DR of neighbor.
+@end deffn
+
+@deffn {Command} {show ipv6 ospf6 request-list A.B.C.D} {}
+Shows requestlist of neighbor.
+@end deffn
+
+@deffn {Command} {show ipv6 route ospf6} {}
+This command shows internal routing table.
+@end deffn
diff --git a/doc/ospfd.8 b/doc/ospfd.8
new file mode 100644
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 <bug-zebra@gnu.org>
+
+
+.SH AUTHOR[S]
+See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors.
+
diff --git a/doc/ospfd.texi b/doc/ospfd.texi
new file mode 100644
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 <bug-zebra@gnu.org>
+
+
+.SH AUTHOR[S]
+See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors.
diff --git a/doc/ripd.texi b/doc/ripd.texi
new file mode 100644
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 <access-list>, @command{ripd} IPv4 address. Match if
+route has this next-hop (meaning next-hop listed in the rip route
+table - "show ip rip")
+@end deffn
+
+@deffn {Route Map} {match metric <0-4294967295>} {}
+This command match to the metric value of RIP updates. For other
+protocol compatibility metric range is shown as <0-4294967295>. But
+for RIP protocol only the value range <0-16> make sense.
+@end deffn
+
+@deffn {Route Map} {set ip next-hop A.B.C.D} {}
+This command set next hop value in RIPv2 protocol. This command does
+not affect RIPv1 because there is no next hop field in the packet.
+@end deffn
+
+@deffn {Route Map} {set metric <0-4294967295>} {}
+Set a metric for matched route when sending announcement. The metric
+value range is very large for compatibility with other protocols. For
+RIP, valid metric values are from 1 to 16.
+@end deffn
+
+@node RIP Authentication, RIP Timers, RIP route-map, RIP
+@comment node-name, next, previous, up
+@section RIP Authentication
+
+@deffn {Interface command} {ip rip authentication mode md5} {}
+@deffnx {Interface command} {no ip rip authentication mode md5} {}
+Set the interface with RIPv2 MD5 authentication.
+@end deffn
+
+@deffn {Interface command} {ip rip authentication mode text} {}
+@deffnx {Interface command} {no ip rip authentication mode text} {}
+Set the interface with RIPv2 simple password authentication.
+@end deffn
+
+@deffn {Interface command} {ip rip authentication string @var{string}} {}
+@deffnx {Interface command} {no ip rip authentication string @var{string}} {}
+RIP version 2 has simple text authentication. This command sets
+authentication string. The string must be shorter than 16 characters.
+@end deffn
+
+@deffn {Interface command} {ip rip authentication key-chain @var{key-chain}} {}
+@deffnx {Interface command} {no ip rip authentication key-chain @var{key-chain}} {}
+Specifiy Keyed MD5 chain.
+@end deffn
+
+@example
+!
+key chain test
+ key 1
+ key-string test
+!
+interface eth1
+ ip rip authentication mode md5
+ ip rip authentication key-chain test
+!
+@end example
+
+@node RIP Timers, Show RIP Information, RIP Authentication, RIP
+@comment node-name, next, previous, up
+@section RIP Timers
+
+@deffn {RIP command} {timers basic @var{update} @var{timeout} @var{garbage}} {}
+
+RIP protocol has several timers. User can configure those timers' values
+by @code{timers basic} command.
+
+The default settings for the timers are as follows:
+
+@itemize @bullet
+@item
+The update timer is 30 seconds. Every update timer seconds, the RIP
+process is awakened to send an unsolicited Response message containing
+the complete routing table to all neighboring RIP routers.
+
+@item
+The timeout timer is 180 seconds. Upon expiration of the timeout, the
+route is no longer valid; however, it is retained in the routing table
+for a short time so that neighbors can be notified that the route has
+been dropped.
+
+@item
+The garbage collect timer is 120 seconds. Upon expiration of the
+garbage-collection timer, the route is finally removed from the routing
+table.
+
+@end itemize
+
+The @code{timers basic} command allows the the default values of the timers
+listed above to be changed.
+@end deffn
+
+@deffn {RIP command} {no timers basic} {}
+The @code{no timers basic} command will reset the timers to the default
+settings listed above.
+@end deffn
+
+@node Show RIP Information, RIP Debug Commands, RIP Timers, RIP
+@comment node-name, next, previous, up
+@section Show RIP Information
+
+To display RIP routes.
+
+@deffn Command {show ip rip} {}
+Show RIP routes.
+@end deffn
+
+The command displays all RIP routes. For routes that are received
+through RIP, this command will display the time the packet was sent and
+the tag information. This command will also display this information
+for routes redistributed into RIP.
+
+@c Exmaple here.
+
+@deffn Command {show ip protocols} {}
+The command displays current RIP status. It includes RIP timer,
+filtering, version, RIP enabled interface and RIP peer inforation.
+@end deffn
+
+@example
+@group
+ripd> @b{show ip protocols}
+Routing Protocol is "rip"
+ Sending updates every 30 seconds with +/-50%, next due in 35 seconds
+ Timeout after 180 seconds, garbage collect after 120 seconds
+ Outgoing update filter list for all interface is not set
+ Incoming update filter list for all interface is not set
+ Default redistribution metric is 1
+ Redistributing: kernel connected
+ Default version control: send version 2, receive version 2
+ Interface Send Recv
+ Routing for Networks:
+ eth0
+ eth1
+ 1.1.1.1
+ 203.181.89.241
+ Routing Information Sources:
+ Gateway BadPackets BadRoutes Distance Last Update
+@end group
+@end example
+
+@node RIP Debug Commands, , Show RIP Information, RIP
+@comment node-name, next, previous, up
+@section RIP Debug Commands
+
+Debug for RIP protocol.
+
+@deffn Command {debug rip events} {}
+Debug rip events.
+@end deffn
+
+@code{debug rip} will show RIP events. Sending and receiving
+packets, timers, and changes in interfaces are events shown with @command{ripd}.
+
+@deffn Command {debug rip packet} {}
+Debug rip packet.
+@end deffn
+
+@code{debug rip packet} will display detailed information about the RIP
+packets. The origin and port number of the packet as well as a packet
+dump is shown.
+
+@deffn Command {debug rip zebra} {}
+Debug rip between zebra communication.
+@end deffn
+
+This command will show the communication between @command{ripd} and @command{zebra}. The
+main information will include addition and deletion of paths to the
+kernel and the sending and receiving of interface information.
+
+@deffn Command {show debugging rip} {}
+Display @command{ripd}'s debugging option.
+@end deffn
+
+@code{show debugging rip} will show all information currently set for ripd
+debug.
diff --git a/doc/ripngd.8 b/doc/ripngd.8
new file mode 100644
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 <bug-zebra@gnu.org>
+
+
+.SH AUTHOR[S]
+See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors.
+
diff --git a/doc/ripngd.texi b/doc/ripngd.texi
new file mode 100644
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 <number>.
+ %
+ \ifnum\lccode\expandafter`\thearg=0\relax
+ \numericenumerate % a number (we hope)
+ \else
+ % It's a letter.
+ \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax
+ \lowercaseenumerate % lowercase letter
+ \else
+ \uppercaseenumerate % uppercase letter
+ \fi
+ \fi
+ \else
+ % Multiple tokens in the argument. We hope it's a number.
+ \numericenumerate
+ \fi
+}
+
+% An @enumerate whose labels are integers. The starting integer is
+% given in \thearg.
+%
+\def\numericenumerate{%
+ \itemno = \thearg
+ \startenumeration{\the\itemno}%
+}
+
+% The starting (lowercase) letter is in \thearg.
+\def\lowercaseenumerate{%
+ \itemno = \expandafter`\thearg
+ \startenumeration{%
+ % Be sure we're not beyond the end of the alphabet.
+ \ifnum\itemno=0
+ \errmessage{No more lowercase letters in @enumerate; get a bigger
+ alphabet}%
+ \fi
+ \char\lccode\itemno
+ }%
+}
+
+% The starting (uppercase) letter is in \thearg.
+\def\uppercaseenumerate{%
+ \itemno = \expandafter`\thearg
+ \startenumeration{%
+ % Be sure we're not beyond the end of the alphabet.
+ \ifnum\itemno=0
+ \errmessage{No more uppercase letters in @enumerate; get a bigger
+ alphabet}
+ \fi
+ \char\uccode\itemno
+ }%
+}
+
+% Call itemizey, adding a period to the first argument and supplying the
+% common last two arguments. Also subtract one from the initial value in
+% \itemno, since @item increments \itemno.
+%
+\def\startenumeration#1{%
+ \advance\itemno by -1
+ \itemizey{#1.}\Eenumerate\flushcr
+}
+
+% @alphaenumerate and @capsenumerate are abbreviations for giving an arg
+% to @enumerate.
+%
+\def\alphaenumerate{\enumerate{a}}
+\def\capsenumerate{\enumerate{A}}
+\def\Ealphaenumerate{\Eenumerate}
+\def\Ecapsenumerate{\Eenumerate}
+
+% Definition of @item while inside @itemize.
+
+\def\itemizeitem{%
+\advance\itemno by 1
+{\let\par=\endgraf \smallbreak}%
+\ifhmode \errmessage{In hmode at itemizeitem}\fi
+{\parskip=0in \hskip 0pt
+\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}%
+\vadjust{\penalty 1200}}%
+\flushcr}
+
+% @multitable macros
+% Amy Hendrickson, 8/18/94, 3/6/96
+%
+% @multitable ... @end multitable will make as many columns as desired.
+% Contents of each column will wrap at width given in preamble. Width
+% can be specified either with sample text given in a template line,
+% or in percent of \hsize, the current width of text on page.
+
+% Table can continue over pages but will only break between lines.
+
+% To make preamble:
+%
+% Either define widths of columns in terms of percent of \hsize:
+% @multitable @columnfractions .25 .3 .45
+% @item ...
+%
+% Numbers following @columnfractions are the percent of the total
+% current hsize to be used for each column. You may use as many
+% columns as desired.
+
+
+% Or use a template:
+% @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+% @item ...
+% using the widest term desired in each column.
+%
+% For those who want to use more than one line's worth of words in
+% the preamble, break the line within one argument and it
+% will parse correctly, i.e.,
+%
+% @multitable {Column 1 template} {Column 2 template} {Column 3
+% template}
+% Not:
+% @multitable {Column 1 template} {Column 2 template}
+% {Column 3 template}
+
+% Each new table line starts with @item, each subsequent new column
+% starts with @tab. Empty columns may be produced by supplying @tab's
+% with nothing between them for as many times as empty columns are needed,
+% ie, @tab@tab@tab will produce two empty columns.
+
+% @item, @tab, @multitable or @end multitable do not need to be on their
+% own lines, but it will not hurt if they are.
+
+% Sample multitable:
+
+% @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+% @item first col stuff @tab second col stuff @tab third col
+% @item
+% first col stuff
+% @tab
+% second col stuff
+% @tab
+% third col
+% @item first col stuff @tab second col stuff
+% @tab Many paragraphs of text may be used in any column.
+%
+% They will wrap at the width determined by the template.
+% @item@tab@tab This will be in third column.
+% @end multitable
+
+% Default dimensions may be reset by user.
+% @multitableparskip is vertical space between paragraphs in table.
+% @multitableparindent is paragraph indent in table.
+% @multitablecolmargin is horizontal space to be left between columns.
+% @multitablelinespace is space to leave between table items, baseline
+% to baseline.
+% 0pt means it depends on current normal line spacing.
+%
+\newskip\multitableparskip
+\newskip\multitableparindent
+\newdimen\multitablecolspace
+\newskip\multitablelinespace
+\multitableparskip=0pt
+\multitableparindent=6pt
+\multitablecolspace=12pt
+\multitablelinespace=0pt
+
+% Macros used to set up halign preamble:
+%
+\let\endsetuptable\relax
+\def\xendsetuptable{\endsetuptable}
+\let\columnfractions\relax
+\def\xcolumnfractions{\columnfractions}
+\newif\ifsetpercent
+
+% #1 is the part of the @columnfraction before the decimal point, which
+% is presumably either 0 or the empty string (but we don't check, we
+% just throw it away). #2 is the decimal part, which we use as the
+% percent of \hsize for this column.
+\def\pickupwholefraction#1.#2 {%
+ \global\advance\colcount by 1
+ \expandafter\xdef\csname col\the\colcount\endcsname{.#2\hsize}%
+ \setuptable
+}
+
+\newcount\colcount
+\def\setuptable#1{%
+ \def\firstarg{#1}%
+ \ifx\firstarg\xendsetuptable
+ \let\go = \relax
+ \else
+ \ifx\firstarg\xcolumnfractions
+ \global\setpercenttrue
+ \else
+ \ifsetpercent
+ \let\go\pickupwholefraction
+ \else
+ \global\advance\colcount by 1
+ \setbox0=\hbox{#1\unskip }% Add a normal word space as a separator;
+ % typically that is always in the input, anyway.
+ \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}%
+ \fi
+ \fi
+ \ifx\go\pickupwholefraction
+ % Put the argument back for the \pickupwholefraction call, so
+ % we'll always have a period there to be parsed.
+ \def\go{\pickupwholefraction#1}%
+ \else
+ \let\go = \setuptable
+ \fi%
+ \fi
+ \go
+}
+
+% multitable syntax
+\def\tab{&\hskip1sp\relax} % 2/2/96
+ % tiny skip here makes sure this column space is
+ % maintained, even if it is never used.
+
+% @multitable ... @end multitable definitions:
+%
+\def\multitable{\parsearg\dotable}
+\def\dotable#1{\bgroup
+ \vskip\parskip
+ \let\item\crcr
+ \tolerance=9500
+ \hbadness=9500
+ \setmultitablespacing
+ \parskip=\multitableparskip
+ \parindent=\multitableparindent
+ \overfullrule=0pt
+ \global\colcount=0
+ \def\Emultitable{\global\setpercentfalse\cr\egroup\egroup}%
+ %
+ % To parse everything between @multitable and @item:
+ \setuptable#1 \endsetuptable
+ %
+ % \everycr will reset column counter, \colcount, at the end of
+ % each line. Every column entry will cause \colcount to advance by one.
+ % The table preamble
+ % looks at the current \colcount to find the correct column width.
+ \everycr{\noalign{%
+ %
+ % \filbreak%% keeps underfull box messages off when table breaks over pages.
+ % Maybe so, but it also creates really weird page breaks when the table
+ % breaks over pages. Wouldn't \vfil be better? Wait until the problem
+ % manifests itself, so it can be fixed for real --karl.
+ \global\colcount=0\relax}}%
+ %
+ % This preamble sets up a generic column definition, which will
+ % be used as many times as user calls for columns.
+ % \vtop will set a single line and will also let text wrap and
+ % continue for many paragraphs if desired.
+ \halign\bgroup&\global\advance\colcount by 1\relax
+ \multistrut\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname
+ %
+ % In order to keep entries from bumping into each other
+ % we will add a \leftskip of \multitablecolspace to all columns after
+ % the first one.
+ %
+ % If a template has been used, we will add \multitablecolspace
+ % to the width of each template entry.
+ %
+ % If the user has set preamble in terms of percent of \hsize we will
+ % use that dimension as the width of the column, and the \leftskip
+ % will keep entries from bumping into each other. Table will start at
+ % left margin and final column will justify at right margin.
+ %
+ % Make sure we don't inherit \rightskip from the outer environment.
+ \rightskip=0pt
+ \ifnum\colcount=1
+ % The first column will be indented with the surrounding text.
+ \advance\hsize by\leftskip
+ \else
+ \ifsetpercent \else
+ % If user has not set preamble in terms of percent of \hsize
+ % we will advance \hsize by \multitablecolspace.
+ \advance\hsize by \multitablecolspace
+ \fi
+ % In either case we will make \leftskip=\multitablecolspace:
+ \leftskip=\multitablecolspace
+ \fi
+ % Ignoring space at the beginning and end avoids an occasional spurious
+ % blank line, when TeX decides to break the line at the space before the
+ % box from the multistrut, so the strut ends up on a line by itself.
+ % For example:
+ % @multitable @columnfractions .11 .89
+ % @item @code{#}
+ % @tab Legal holiday which is valid in major parts of the whole country.
+ % Is automatically provided with highlighting sequences respectively marking
+ % characters.
+ \noindent\ignorespaces##\unskip\multistrut}\cr
+}
+
+\def\setmultitablespacing{% test to see if user has set \multitablelinespace.
+% If so, do nothing. If not, give it an appropriate dimension based on
+% current baselineskip.
+\ifdim\multitablelinespace=0pt
+%% strut to put in table in case some entry doesn't have descenders,
+%% to keep lines equally spaced
+\let\multistrut = \strut
+%% Test to see if parskip is larger than space between lines of
+%% table. If not, do nothing.
+%% If so, set to same dimension as multitablelinespace.
+\else
+\gdef\multistrut{\vrule height\multitablelinespace depth\dp0
+width0pt\relax} \fi
+\ifdim\multitableparskip>\multitablelinespace
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller
+ %% than skip between lines in the table.
+\fi%
+\ifdim\multitableparskip=0pt
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller
+ %% than skip between lines in the table.
+\fi}
+
+
+\message{conditionals,}
+% Prevent errors for section commands.
+% Used in @ignore and in failing conditionals.
+\def\ignoresections{%
+ \let\chapter=\relax
+ \let\unnumbered=\relax
+ \let\top=\relax
+ \let\unnumberedsec=\relax
+ \let\unnumberedsection=\relax
+ \let\unnumberedsubsec=\relax
+ \let\unnumberedsubsection=\relax
+ \let\unnumberedsubsubsec=\relax
+ \let\unnumberedsubsubsection=\relax
+ \let\section=\relax
+ \let\subsec=\relax
+ \let\subsubsec=\relax
+ \let\subsection=\relax
+ \let\subsubsection=\relax
+ \let\appendix=\relax
+ \let\appendixsec=\relax
+ \let\appendixsection=\relax
+ \let\appendixsubsec=\relax
+ \let\appendixsubsection=\relax
+ \let\appendixsubsubsec=\relax
+ \let\appendixsubsubsection=\relax
+ \let\contents=\relax
+ \let\smallbook=\relax
+ \let\titlepage=\relax
+}
+
+% Used in nested conditionals, where we have to parse the Texinfo source
+% and so want to turn off most commands, in case they are used
+% incorrectly.
+%
+\def\ignoremorecommands{%
+ \let\defcodeindex = \relax
+ \let\defcv = \relax
+ \let\deffn = \relax
+ \let\deffnx = \relax
+ \let\defindex = \relax
+ \let\defivar = \relax
+ \let\defmac = \relax
+ \let\defmethod = \relax
+ \let\defop = \relax
+ \let\defopt = \relax
+ \let\defspec = \relax
+ \let\deftp = \relax
+ \let\deftypefn = \relax
+ \let\deftypefun = \relax
+ \let\deftypevar = \relax
+ \let\deftypevr = \relax
+ \let\defun = \relax
+ \let\defvar = \relax
+ \let\defvr = \relax
+ \let\ref = \relax
+ \let\xref = \relax
+ \let\printindex = \relax
+ \let\pxref = \relax
+ \let\settitle = \relax
+ \let\setchapternewpage = \relax
+ \let\setchapterstyle = \relax
+ \let\everyheading = \relax
+ \let\evenheading = \relax
+ \let\oddheading = \relax
+ \let\everyfooting = \relax
+ \let\evenfooting = \relax
+ \let\oddfooting = \relax
+ \let\headings = \relax
+ \let\include = \relax
+ \let\lowersections = \relax
+ \let\down = \relax
+ \let\raisesections = \relax
+ \let\up = \relax
+ \let\set = \relax
+ \let\clear = \relax
+ \let\item = \relax
+}
+
+% Ignore @ignore ... @end ignore.
+%
+\def\ignore{\doignore{ignore}}
+
+% Ignore @ifinfo, @ifhtml, @ifnottex, @html, @menu, and @direntry text.
+%
+\def\ifinfo{\doignore{ifinfo}}
+\def\ifhtml{\doignore{ifhtml}}
+\def\ifnottex{\doignore{ifnottex}}
+\def\html{\doignore{html}}
+\def\menu{\doignore{menu}}
+\def\direntry{\doignore{direntry}}
+
+% @dircategory CATEGORY -- specify a category of the dir file
+% which this file should belong to. Ignore this in TeX.
+\let\dircategory = \comment
+
+% Ignore text until a line `@end #1'.
+%
+\def\doignore#1{\begingroup
+ % Don't complain about control sequences we have declared \outer.
+ \ignoresections
+ %
+ % Define a command to swallow text until we reach `@end #1'.
+ % This @ is a catcode 12 token (that is the normal catcode of @ in
+ % this texinfo.tex file). We change the catcode of @ below to match.
+ \long\def\doignoretext##1@end #1{\enddoignore}%
+ %
+ % Make sure that spaces turn into tokens that match what \doignoretext wants.
+ \catcode32 = 10
+ %
+ % Ignore braces, too, so mismatched braces don't cause trouble.
+ \catcode`\{ = 9
+ \catcode`\} = 9
+ %
+ % We must not have @c interpreted as a control sequence.
+ \catcode`\@ = 12
+ %
+ % Make the letter c a comment character so that the rest of the line
+ % will be ignored. This way, the document can have (for example)
+ % @c @end ifinfo
+ % and the @end ifinfo will be properly ignored.
+ % (We've just changed @ to catcode 12.)
+ \catcode`\c = 14
+ %
+ % And now expand that command.
+ \doignoretext
+}
+
+% What we do to finish off ignored text.
+%
+\def\enddoignore{\endgroup\ignorespaces}%
+
+\newif\ifwarnedobs\warnedobsfalse
+\def\obstexwarn{%
+ \ifwarnedobs\relax\else
+ % We need to warn folks that they may have trouble with TeX 3.0.
+ % This uses \immediate\write16 rather than \message to get newlines.
+ \immediate\write16{}
+ \immediate\write16{WARNING: for users of Unix TeX 3.0!}
+ \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).}
+ \immediate\write16{If you are running another version of TeX, relax.}
+ \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.}
+ \immediate\write16{ Then upgrade your TeX installation if you can.}
+ \immediate\write16{ (See ftp://ftp.gnu.org/pub/gnu/TeX.README.)}
+ \immediate\write16{If you are stuck with version 3.0, run the}
+ \immediate\write16{ script ``tex3patch'' from the Texinfo distribution}
+ \immediate\write16{ to use a workaround.}
+ \immediate\write16{}
+ \global\warnedobstrue
+ \fi
+}
+
+% **In TeX 3.0, setting text in \nullfont hangs tex. For a
+% workaround (which requires the file ``dummy.tfm'' to be installed),
+% uncomment the following line:
+%%%%%\font\nullfont=dummy\let\obstexwarn=\relax
+
+% Ignore text, except that we keep track of conditional commands for
+% purposes of nesting, up to an `@end #1' command.
+%
+\def\nestedignore#1{%
+ \obstexwarn
+ % We must actually expand the ignored text to look for the @end
+ % command, so that nested ignore constructs work. Thus, we put the
+ % text into a \vbox and then do nothing with the result. To minimize
+ % the change of memory overflow, we follow the approach outlined on
+ % page 401 of the TeXbook: make the current font be a dummy font.
+ %
+ \setbox0 = \vbox\bgroup
+ % Don't complain about control sequences we have declared \outer.
+ \ignoresections
+ %
+ % Define `@end #1' to end the box, which will in turn undefine the
+ % @end command again.
+ \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}%
+ %
+ % We are going to be parsing Texinfo commands. Most cause no
+ % trouble when they are used incorrectly, but some commands do
+ % complicated argument parsing or otherwise get confused, so we
+ % undefine them.
+ %
+ % We can't do anything about stray @-signs, unfortunately;
+ % they'll produce `undefined control sequence' errors.
+ \ignoremorecommands
+ %
+ % Set the current font to be \nullfont, a TeX primitive, and define
+ % all the font commands to also use \nullfont. We don't use
+ % dummy.tfm, as suggested in the TeXbook, because not all sites
+ % might have that installed. Therefore, math mode will still
+ % produce output, but that should be an extremely small amount of
+ % stuff compared to the main input.
+ %
+ \nullfont
+ \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont
+ \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont
+ \let\tensf = \nullfont
+ % Similarly for index fonts (mostly for their use in
+ % smallexample)
+ \let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont
+ \let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont
+ \let\indsf = \nullfont
+ %
+ % Don't complain when characters are missing from the fonts.
+ \tracinglostchars = 0
+ %
+ % Don't bother to do space factor calculations.
+ \frenchspacing
+ %
+ % Don't report underfull hboxes.
+ \hbadness = 10000
+ %
+ % Do minimal line-breaking.
+ \pretolerance = 10000
+ %
+ % Do not execute instructions in @tex
+ \def\tex{\doignore{tex}}%
+ % Do not execute macro definitions.
+ % `c' is a comment character, so the word `macro' will get cut off.
+ \def\macro{\doignore{ma}}%
+}
+
+% @set VAR sets the variable VAR to an empty value.
+% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE.
+%
+% Since we want to separate VAR from REST-OF-LINE (which might be
+% empty), we can't just use \parsearg; we have to insert a space of our
+% own to delimit the rest of the line, and then take it out again if we
+% didn't need it. Make sure the catcode of space is correct to avoid
+% losing inside @example, for instance.
+%
+\def\set{\begingroup\catcode` =10
+ \catcode`\-=12 \catcode`\_=12 % Allow - and _ in VAR.
+ \parsearg\setxxx}
+\def\setxxx#1{\setyyy#1 \endsetyyy}
+\def\setyyy#1 #2\endsetyyy{%
+ \def\temp{#2}%
+ \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty
+ \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted.
+ \fi
+ \endgroup
+}
+% Can't use \xdef to pre-expand #2 and save some time, since \temp or
+% \next or other control sequences that we've defined might get us into
+% an infinite loop. Consider `@set foo @cite{bar}'.
+\def\setzzz#1#2 \endsetzzz{\expandafter\gdef\csname SET#1\endcsname{#2}}
+
+% @clear VAR clears (i.e., unsets) the variable VAR.
+%
+\def\clear{\parsearg\clearxxx}
+\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax}
+
+% @value{foo} gets the text saved in variable foo.
+{
+ \catcode`\_ = \active
+ %
+ % We might end up with active _ or - characters in the argument if
+ % we're called from @code, as @code{@value{foo-bar_}}. So \let any
+ % such active characters to their normal equivalents.
+ \gdef\value{\begingroup
+ \catcode`\-=12 \catcode`\_=12
+ \indexbreaks \let_\normalunderscore
+ \valuexxx}
+}
+\def\valuexxx#1{\expandablevalue{#1}\endgroup}
+
+% We have this subroutine so that we can handle at least some @value's
+% properly in indexes (we \let\value to this in \indexdummies). Ones
+% whose names contain - or _ still won't work, but we can't do anything
+% about that. The command has to be fully expandable, since the result
+% winds up in the index file. This means that if the variable's value
+% contains other Texinfo commands, it's almost certain it will fail
+% (although perhaps we could fix that with sufficient work to do a
+% one-level expansion on the result, instead of complete).
+%
+\def\expandablevalue#1{%
+ \expandafter\ifx\csname SET#1\endcsname\relax
+ {[No value for ``#1'']}%
+ \else
+ \csname SET#1\endcsname
+ \fi
+}
+
+% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined
+% with @set.
+%
+\def\ifset{\parsearg\ifsetxxx}
+\def\ifsetxxx #1{%
+ \expandafter\ifx\csname SET#1\endcsname\relax
+ \expandafter\ifsetfail
+ \else
+ \expandafter\ifsetsucceed
+ \fi
+}
+\def\ifsetsucceed{\conditionalsucceed{ifset}}
+\def\ifsetfail{\nestedignore{ifset}}
+\defineunmatchedend{ifset}
+
+% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been
+% defined with @set, or has been undefined with @clear.
+%
+\def\ifclear{\parsearg\ifclearxxx}
+\def\ifclearxxx #1{%
+ \expandafter\ifx\csname SET#1\endcsname\relax
+ \expandafter\ifclearsucceed
+ \else
+ \expandafter\ifclearfail
+ \fi
+}
+\def\ifclearsucceed{\conditionalsucceed{ifclear}}
+\def\ifclearfail{\nestedignore{ifclear}}
+\defineunmatchedend{ifclear}
+
+% @iftex, @ifnothtml, @ifnotinfo always succeed; we read the text
+% following, through the first @end iftex (etc.). Make `@end iftex'
+% (etc.) valid only after an @iftex.
+%
+\def\iftex{\conditionalsucceed{iftex}}
+\def\ifnothtml{\conditionalsucceed{ifnothtml}}
+\def\ifnotinfo{\conditionalsucceed{ifnotinfo}}
+\defineunmatchedend{iftex}
+\defineunmatchedend{ifnothtml}
+\defineunmatchedend{ifnotinfo}
+
+% We can't just want to start a group at @iftex (for example) and end it
+% at @end iftex, since then @set commands inside the conditional have no
+% effect (they'd get reverted at the end of the group). So we must
+% define \Eiftex to redefine itself to be its previous value. (We can't
+% just define it to fail again with an ``unmatched end'' error, since
+% the @ifset might be nested.)
+%
+\def\conditionalsucceed#1{%
+ \edef\temp{%
+ % Remember the current value of \E#1.
+ \let\nece{prevE#1} = \nece{E#1}%
+ %
+ % At the `@end #1', redefine \E#1 to be its previous value.
+ \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}%
+ }%
+ \temp
+}
+
+% We need to expand lots of \csname's, but we don't want to expand the
+% control sequences after we've constructed them.
+%
+\def\nece#1{\expandafter\noexpand\csname#1\endcsname}
+
+% @defininfoenclose.
+\let\definfoenclose=\comment
+
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within \newindex.
+{\catcode`\@=11
+\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}}
+
+% \newindex {foo} defines an index named foo.
+% It automatically defines \fooindex such that
+% \fooindex ...rest of line... puts an entry in the index foo.
+% It also defines \fooindfile to be the number of the output channel for
+% the file that accumulates this index. The file's extension is foo.
+% The name of an index should be no more than 2 characters long
+% for the sake of vms.
+%
+\def\newindex#1{%
+ \iflinks
+ \expandafter\newwrite \csname#1indfile\endcsname
+ \openout \csname#1indfile\endcsname \jobname.#1 % Open the file
+ \fi
+ \expandafter\xdef\csname#1index\endcsname{% % Define @#1index
+ \noexpand\doindex{#1}}
+}
+
+% @defindex foo == \newindex{foo}
+
+\def\defindex{\parsearg\newindex}
+
+% Define @defcodeindex, like @defindex except put all entries in @code.
+
+\def\newcodeindex#1{%
+ \iflinks
+ \expandafter\newwrite \csname#1indfile\endcsname
+ \openout \csname#1indfile\endcsname \jobname.#1
+ \fi
+ \expandafter\xdef\csname#1index\endcsname{%
+ \noexpand\docodeindex{#1}}
+}
+
+\def\defcodeindex{\parsearg\newcodeindex}
+
+% @synindex foo bar makes index foo feed into index bar.
+% Do this instead of @defindex foo if you don't want it as a separate index.
+% The \closeout helps reduce unnecessary open files; the limit on the
+% Acorn RISC OS is a mere 16 files.
+\def\synindex#1 #2 {%
+ \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
+ \expandafter\closeout\csname#1indfile\endcsname
+ \expandafter\let\csname#1indfile\endcsname=\synindexfoo
+ \expandafter\xdef\csname#1index\endcsname{% define \xxxindex
+ \noexpand\doindex{#2}}%
+}
+
+% @syncodeindex foo bar similar, but put all entries made for index foo
+% inside @code.
+\def\syncodeindex#1 #2 {%
+ \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
+ \expandafter\closeout\csname#1indfile\endcsname
+ \expandafter\let\csname#1indfile\endcsname=\synindexfoo
+ \expandafter\xdef\csname#1index\endcsname{% define \xxxindex
+ \noexpand\docodeindex{#2}}%
+}
+
+% Define \doindex, the driver for all \fooindex macros.
+% Argument #1 is generated by the calling \fooindex macro,
+% and it is "foo", the name of the index.
+
+% \doindex just uses \parsearg; it calls \doind for the actual work.
+% This is because \doind is more useful to call from other macros.
+
+% There is also \dosubind {index}{topic}{subtopic}
+% which makes an entry in a two-level index such as the operation index.
+
+\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer}
+\def\singleindexer #1{\doind{\indexname}{#1}}
+
+% like the previous two, but they put @code around the argument.
+\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer}
+\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}}
+
+\def\indexdummies{%
+\def\ { }%
+% Take care of the plain tex accent commands.
+\def\"{\realbackslash "}%
+\def\`{\realbackslash `}%
+\def\'{\realbackslash '}%
+\def\^{\realbackslash ^}%
+\def\~{\realbackslash ~}%
+\def\={\realbackslash =}%
+\def\b{\realbackslash b}%
+\def\c{\realbackslash c}%
+\def\d{\realbackslash d}%
+\def\u{\realbackslash u}%
+\def\v{\realbackslash v}%
+\def\H{\realbackslash H}%
+% Take care of the plain tex special European modified letters.
+\def\oe{\realbackslash oe}%
+\def\ae{\realbackslash ae}%
+\def\aa{\realbackslash aa}%
+\def\OE{\realbackslash OE}%
+\def\AE{\realbackslash AE}%
+\def\AA{\realbackslash AA}%
+\def\o{\realbackslash o}%
+\def\O{\realbackslash O}%
+\def\l{\realbackslash l}%
+\def\L{\realbackslash L}%
+\def\ss{\realbackslash ss}%
+% Take care of texinfo commands likely to appear in an index entry.
+% (Must be a way to avoid doing expansion at all, and thus not have to
+% laboriously list every single command here.)
+\def\@{@}% will be @@ when we switch to @ as escape char.
+% Need these in case \tex is in effect and \{ is a \delimiter again.
+% But can't use \lbracecmd and \rbracecmd because texindex assumes
+% braces and backslashes are used only as delimiters.
+\let\{ = \mylbrace
+\let\} = \myrbrace
+\def\_{{\realbackslash _}}%
+\def\w{\realbackslash w }%
+\def\bf{\realbackslash bf }%
+%\def\rm{\realbackslash rm }%
+\def\sl{\realbackslash sl }%
+\def\sf{\realbackslash sf}%
+\def\tt{\realbackslash tt}%
+\def\gtr{\realbackslash gtr}%
+\def\less{\realbackslash less}%
+\def\hat{\realbackslash hat}%
+\def\TeX{\realbackslash TeX}%
+\def\dots{\realbackslash dots }%
+\def\result{\realbackslash result}%
+\def\equiv{\realbackslash equiv}%
+\def\expansion{\realbackslash expansion}%
+\def\print{\realbackslash print}%
+\def\error{\realbackslash error}%
+\def\point{\realbackslash point}%
+\def\copyright{\realbackslash copyright}%
+\def\tclose##1{\realbackslash tclose {##1}}%
+\def\code##1{\realbackslash code {##1}}%
+\def\uref##1{\realbackslash uref {##1}}%
+\def\url##1{\realbackslash url {##1}}%
+\def\env##1{\realbackslash env {##1}}%
+\def\command##1{\realbackslash command {##1}}%
+\def\option##1{\realbackslash option {##1}}%
+\def\dotless##1{\realbackslash dotless {##1}}%
+\def\samp##1{\realbackslash samp {##1}}%
+\def\,##1{\realbackslash ,{##1}}%
+\def\t##1{\realbackslash t {##1}}%
+\def\r##1{\realbackslash r {##1}}%
+\def\i##1{\realbackslash i {##1}}%
+\def\b##1{\realbackslash b {##1}}%
+\def\sc##1{\realbackslash sc {##1}}%
+\def\cite##1{\realbackslash cite {##1}}%
+\def\key##1{\realbackslash key {##1}}%
+\def\file##1{\realbackslash file {##1}}%
+\def\var##1{\realbackslash var {##1}}%
+\def\kbd##1{\realbackslash kbd {##1}}%
+\def\dfn##1{\realbackslash dfn {##1}}%
+\def\emph##1{\realbackslash emph {##1}}%
+\def\acronym##1{\realbackslash acronym {##1}}%
+%
+% Handle some cases of @value -- where the variable name does not
+% contain - or _, and the value does not contain any
+% (non-fully-expandable) commands.
+\let\value = \expandablevalue
+%
+\unsepspaces
+% Turn off macro expansion
+\turnoffmacros
+}
+
+% If an index command is used in an @example environment, any spaces
+% therein should become regular spaces in the raw index file, not the
+% expansion of \tie (\\leavevmode \penalty \@M \ ).
+{\obeyspaces
+ \gdef\unsepspaces{\obeyspaces\let =\space}}
+
+% \indexnofonts no-ops all font-change commands.
+% This is used when outputting the strings to sort the index by.
+\def\indexdummyfont#1{#1}
+\def\indexdummytex{TeX}
+\def\indexdummydots{...}
+
+\def\indexnofonts{%
+% Just ignore accents.
+\let\,=\indexdummyfont
+\let\"=\indexdummyfont
+\let\`=\indexdummyfont
+\let\'=\indexdummyfont
+\let\^=\indexdummyfont
+\let\~=\indexdummyfont
+\let\==\indexdummyfont
+\let\b=\indexdummyfont
+\let\c=\indexdummyfont
+\let\d=\indexdummyfont
+\let\u=\indexdummyfont
+\let\v=\indexdummyfont
+\let\H=\indexdummyfont
+\let\dotless=\indexdummyfont
+% Take care of the plain tex special European modified letters.
+\def\oe{oe}%
+\def\ae{ae}%
+\def\aa{aa}%
+\def\OE{OE}%
+\def\AE{AE}%
+\def\AA{AA}%
+\def\o{o}%
+\def\O{O}%
+\def\l{l}%
+\def\L{L}%
+\def\ss{ss}%
+\let\w=\indexdummyfont
+\let\t=\indexdummyfont
+\let\r=\indexdummyfont
+\let\i=\indexdummyfont
+\let\b=\indexdummyfont
+\let\emph=\indexdummyfont
+\let\strong=\indexdummyfont
+\let\cite=\indexdummyfont
+\let\sc=\indexdummyfont
+%Don't no-op \tt, since it isn't a user-level command
+% and is used in the definitions of the active chars like <, >, |...
+%\let\tt=\indexdummyfont
+\let\tclose=\indexdummyfont
+\let\code=\indexdummyfont
+\let\url=\indexdummyfont
+\let\uref=\indexdummyfont
+\let\env=\indexdummyfont
+\let\command=\indexdummyfont
+\let\option=\indexdummyfont
+\let\file=\indexdummyfont
+\let\samp=\indexdummyfont
+\let\kbd=\indexdummyfont
+\let\key=\indexdummyfont
+\let\var=\indexdummyfont
+\let\TeX=\indexdummytex
+\let\dots=\indexdummydots
+\def\@{@}%
+}
+
+% To define \realbackslash, we must make \ not be an escape.
+% We must first make another character (@) an escape
+% so we do not become unable to do a definition.
+
+{\catcode`\@=0 \catcode`\\=\other
+ @gdef@realbackslash{\}}
+
+\let\indexbackslash=0 %overridden during \printindex.
+\let\SETmarginindex=\relax % put index entries in margin (undocumented)?
+
+% For \ifx comparisons.
+\def\emptymacro{\empty}
+
+% Most index entries go through here, but \dosubind is the general case.
+%
+\def\doind#1#2{\dosubind{#1}{#2}\empty}
+
+% Workhorse for all \fooindexes.
+% #1 is name of index, #2 is stuff to put there, #3 is subentry --
+% \empty if called from \doind, as we usually are. The main exception
+% is with defuns, which call us directly.
+%
+\def\dosubind#1#2#3{%
+ % Put the index entry in the margin if desired.
+ \ifx\SETmarginindex\relax\else
+ \insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}%
+ \fi
+ {%
+ \count255=\lastpenalty
+ {%
+ \indexdummies % Must do this here, since \bf, etc expand at this stage
+ \escapechar=`\\
+ {%
+ \let\folio = 0% We will expand all macros now EXCEPT \folio.
+ \def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now
+ % so it will be output as is; and it will print as backslash.
+ %
+ \def\thirdarg{#3}%
+ %
+ % If third arg is present, precede it with space in sort key.
+ \ifx\thirdarg\emptymacro
+ \let\subentry = \empty
+ \else
+ \def\subentry{ #3}%
+ \fi
+ %
+ % First process the index entry with all font commands turned
+ % off to get the string to sort by.
+ {\indexnofonts \xdef\indexsorttmp{#2\subentry}}%
+ %
+ % Now the real index entry with the fonts.
+ \toks0 = {#2}%
+ %
+ % If third (subentry) arg is present, add it to the index
+ % string. And include a space.
+ \ifx\thirdarg\emptymacro \else
+ \toks0 = \expandafter{\the\toks0 \space #3}%
+ \fi
+ %
+ % Set up the complete index entry, with both the sort key
+ % and the original text, including any font commands. We write
+ % three arguments to \entry to the .?? file, texindex reduces to
+ % two when writing the .??s sorted result.
+ \edef\temp{%
+ \write\csname#1indfile\endcsname{%
+ \realbackslash entry{\indexsorttmp}{\folio}{\the\toks0}}%
+ }%
+ %
+ % If a skip is the last thing on the list now, preserve it
+ % by backing up by \lastskip, doing the \write, then inserting
+ % the skip again. Otherwise, the whatsit generated by the
+ % \write will make \lastskip zero. The result is that sequences
+ % like this:
+ % @end defun
+ % @tindex whatever
+ % @defun ...
+ % will have extra space inserted, because the \medbreak in the
+ % start of the @defun won't see the skip inserted by the @end of
+ % the previous defun.
+ %
+ % But don't do any of this if we're not in vertical mode. We
+ % don't want to do a \vskip and prematurely end a paragraph.
+ %
+ % Avoid page breaks due to these extra skips, too.
+ %
+ \iflinks
+ \ifvmode
+ \skip0 = \lastskip
+ \ifdim\lastskip = 0pt \else \nobreak\vskip-\lastskip \fi
+ \fi
+ %
+ \temp % do the write
+ %
+ %
+ \ifvmode \ifdim\skip0 = 0pt \else \nobreak\vskip\skip0 \fi \fi
+ \fi
+ }%
+ }%
+ \penalty\count255
+ }%
+}
+
+% The index entry written in the file actually looks like
+% \entry {sortstring}{page}{topic}
+% or
+% \entry {sortstring}{page}{topic}{subtopic}
+% The texindex program reads in these files and writes files
+% containing these kinds of lines:
+% \initial {c}
+% before the first topic whose initial is c
+% \entry {topic}{pagelist}
+% for a topic that is used without subtopics
+% \primary {topic}
+% for the beginning of a topic that is used with subtopics
+% \secondary {subtopic}{pagelist}
+% for each subtopic.
+
+% Define the user-accessible indexing commands
+% @findex, @vindex, @kindex, @cindex.
+
+\def\findex {\fnindex}
+\def\kindex {\kyindex}
+\def\cindex {\cpindex}
+\def\vindex {\vrindex}
+\def\tindex {\tpindex}
+\def\pindex {\pgindex}
+
+\def\cindexsub {\begingroup\obeylines\cindexsub}
+{\obeylines %
+\gdef\cindexsub "#1" #2^^M{\endgroup %
+\dosubind{cp}{#2}{#1}}}
+
+% Define the macros used in formatting output of the sorted index material.
+
+% @printindex causes a particular index (the ??s file) to get printed.
+% It does not print any chapter heading (usually an @unnumbered).
+%
+\def\printindex{\parsearg\doprintindex}
+\def\doprintindex#1{\begingroup
+ \dobreak \chapheadingskip{10000}%
+ %
+ \indexfonts \rm
+ \tolerance = 9500
+ \indexbreaks
+ %
+ % See if the index file exists and is nonempty.
+ % Change catcode of @ here so that if the index file contains
+ % \initial {@}
+ % as its first line, TeX doesn't complain about mismatched braces
+ % (because it thinks @} is a control sequence).
+ \catcode`\@ = 11
+ \openin 1 \jobname.#1s
+ \ifeof 1
+ % \enddoublecolumns gets confused if there is no text in the index,
+ % and it loses the chapter title and the aux file entries for the
+ % index. The easiest way to prevent this problem is to make sure
+ % there is some text.
+ \putwordIndexNonexistent
+ \else
+ %
+ % If the index file exists but is empty, then \openin leaves \ifeof
+ % false. We have to make TeX try to read something from the file, so
+ % it can discover if there is anything in it.
+ \read 1 to \temp
+ \ifeof 1
+ \putwordIndexIsEmpty
+ \else
+ % Index files are almost Texinfo source, but we use \ as the escape
+ % character. It would be better to use @, but that's too big a change
+ % to make right now.
+ \def\indexbackslash{\rawbackslashxx}%
+ \catcode`\\ = 0
+ \escapechar = `\\
+ \begindoublecolumns
+ \input \jobname.#1s
+ \enddoublecolumns
+ \fi
+ \fi
+ \closein 1
+\endgroup}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+\def\initial#1{{%
+ % Some minor font changes for the special characters.
+ \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt
+ %
+ % Remove any glue we may have, we'll be inserting our own.
+ \removelastskip
+ %
+ % We like breaks before the index initials, so insert a bonus.
+ \penalty -300
+ %
+ % Typeset the initial. Making this add up to a whole number of
+ % baselineskips increases the chance of the dots lining up from column
+ % to column. It still won't often be perfect, because of the stretch
+ % we need before each entry, but it's better.
+ %
+ % No shrink because it confuses \balancecolumns.
+ \vskip 1.67\baselineskip plus .5\baselineskip
+ \leftline{\secbf #1}%
+ \vskip .33\baselineskip plus .1\baselineskip
+ %
+ % Do our best not to break after the initial.
+ \nobreak
+}}
+
+% This typesets a paragraph consisting of #1, dot leaders, and then #2
+% flush to the right margin. It is used for index and table of contents
+% entries. The paragraph is indented by \leftskip.
+%
+\def\entry#1#2{\begingroup
+ %
+ % Start a new paragraph if necessary, so our assignments below can't
+ % affect previous text.
+ \par
+ %
+ % Do not fill out the last line with white space.
+ \parfillskip = 0in
+ %
+ % No extra space above this paragraph.
+ \parskip = 0in
+ %
+ % Do not prefer a separate line ending with a hyphen to fewer lines.
+ \finalhyphendemerits = 0
+ %
+ % \hangindent is only relevant when the entry text and page number
+ % don't both fit on one line. In that case, bob suggests starting the
+ % dots pretty far over on the line. Unfortunately, a large
+ % indentation looks wrong when the entry text itself is broken across
+ % lines. So we use a small indentation and put up with long leaders.
+ %
+ % \hangafter is reset to 1 (which is the value we want) at the start
+ % of each paragraph, so we need not do anything with that.
+ \hangindent = 2em
+ %
+ % When the entry text needs to be broken, just fill out the first line
+ % with blank space.
+ \rightskip = 0pt plus1fil
+ %
+ % A bit of stretch before each entry for the benefit of balancing columns.
+ \vskip 0pt plus1pt
+ %
+ % Start a ``paragraph'' for the index entry so the line breaking
+ % parameters we've set above will have an effect.
+ \noindent
+ %
+ % Insert the text of the index entry. TeX will do line-breaking on it.
+ #1%
+ % The following is kludged to not output a line of dots in the index if
+ % there are no page numbers. The next person who breaks this will be
+ % cursed by a Unix daemon.
+ \def\tempa{{\rm }}%
+ \def\tempb{#2}%
+ \edef\tempc{\tempa}%
+ \edef\tempd{\tempb}%
+ \ifx\tempc\tempd\ \else%
+ %
+ % If we must, put the page number on a line of its own, and fill out
+ % this line with blank space. (The \hfil is overwhelmed with the
+ % fill leaders glue in \indexdotfill if the page number does fit.)
+ \hfil\penalty50
+ \null\nobreak\indexdotfill % Have leaders before the page number.
+ %
+ % The `\ ' here is removed by the implicit \unskip that TeX does as
+ % part of (the primitive) \par. Without it, a spurious underfull
+ % \hbox ensues.
+ \ #2% The page number ends the paragraph.
+ \fi%
+ \par
+\endgroup}
+
+% Like \dotfill except takes at least 1 em.
+\def\indexdotfill{\cleaders
+ \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill}
+
+\def\primary #1{\line{#1\hfil}}
+
+\newskip\secondaryindent \secondaryindent=0.5cm
+
+\def\secondary #1#2{
+{\parfillskip=0in \parskip=0in
+\hangindent =1in \hangafter=1
+\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par
+}}
+
+% Define two-column mode, which we use to typeset indexes.
+% Adapted from the TeXbook, page 416, which is to say,
+% the manmac.tex format used to print the TeXbook itself.
+\catcode`\@=11
+
+\newbox\partialpage
+\newdimen\doublecolumnhsize
+
+\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns
+ % Grab any single-column material above us.
+ \output = {%
+ %
+ % Here is a possibility not foreseen in manmac: if we accumulate a
+ % whole lot of material, we might end up calling this \output
+ % routine twice in a row (see the doublecol-lose test, which is
+ % essentially a couple of indexes with @setchapternewpage off). In
+ % that case we just ship out what is in \partialpage with the normal
+ % output routine. Generally, \partialpage will be empty when this
+ % runs and this will be a no-op. See the indexspread.tex test case.
+ \ifvoid\partialpage \else
+ \onepageout{\pagecontents\partialpage}%
+ \fi
+ %
+ \global\setbox\partialpage = \vbox{%
+ % Unvbox the main output page.
+ \unvbox\PAGE
+ \kern-\topskip \kern\baselineskip
+ }%
+ }%
+ \eject % run that output routine to set \partialpage
+ %
+ % Use the double-column output routine for subsequent pages.
+ \output = {\doublecolumnout}%
+ %
+ % Change the page size parameters. We could do this once outside this
+ % routine, in each of @smallbook, @afourpaper, and the default 8.5x11
+ % format, but then we repeat the same computation. Repeating a couple
+ % of assignments once per index is clearly meaningless for the
+ % execution time, so we may as well do it in one place.
+ %
+ % First we halve the line length, less a little for the gutter between
+ % the columns. We compute the gutter based on the line length, so it
+ % changes automatically with the paper format. The magic constant
+ % below is chosen so that the gutter has the same value (well, +-<1pt)
+ % as it did when we hard-coded it.
+ %
+ % We put the result in a separate register, \doublecolumhsize, so we
+ % can restore it in \pagesofar, after \hsize itself has (potentially)
+ % been clobbered.
+ %
+ \doublecolumnhsize = \hsize
+ \advance\doublecolumnhsize by -.04154\hsize
+ \divide\doublecolumnhsize by 2
+ \hsize = \doublecolumnhsize
+ %
+ % Double the \vsize as well. (We don't need a separate register here,
+ % since nobody clobbers \vsize.)
+ \advance\vsize by -\ht\partialpage
+ \vsize = 2\vsize
+}
+
+% The double-column output routine for all double-column pages except
+% the last.
+%
+\def\doublecolumnout{%
+ \splittopskip=\topskip \splitmaxdepth=\maxdepth
+ % Get the available space for the double columns -- the normal
+ % (undoubled) page height minus any material left over from the
+ % previous page.
+ \dimen@ = \vsize
+ \divide\dimen@ by 2
+ %
+ % box0 will be the left-hand column, box2 the right.
+ \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@
+ \onepageout\pagesofar
+ \unvbox255
+ \penalty\outputpenalty
+}
+\def\pagesofar{%
+ % Re-output the contents of the output page -- any previous material,
+ % followed by the two boxes we just split, in box0 and box2.
+ \unvbox\partialpage
+ %
+ \hsize = \doublecolumnhsize
+ \wd0=\hsize \wd2=\hsize
+ \hbox to\pagewidth{\box0\hfil\box2}%
+}
+\def\enddoublecolumns{%
+ \output = {%
+ % Split the last of the double-column material. Leave it on the
+ % current page, no automatic page break.
+ \balancecolumns
+ %
+ % If we end up splitting too much material for the current page,
+ % though, there will be another page break right after this \output
+ % invocation ends. Having called \balancecolumns once, we do not
+ % want to call it again. Therefore, reset \output to its normal
+ % definition right away. (We hope \balancecolumns will never be
+ % called on to balance too much material, but if it is, this makes
+ % the output somewhat more palatable.)
+ \global\output = {\onepageout{\pagecontents\PAGE}}%
+ }%
+ \eject
+ \endgroup % started in \begindoublecolumns
+ %
+ % \pagegoal was set to the doubled \vsize above, since we restarted
+ % the current page. We're now back to normal single-column
+ % typesetting, so reset \pagegoal to the normal \vsize (after the
+ % \endgroup where \vsize got restored).
+ \pagegoal = \vsize
+}
+\def\balancecolumns{%
+ % Called at the end of the double column material.
+ \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120.
+ \dimen@ = \ht0
+ \advance\dimen@ by \topskip
+ \advance\dimen@ by-\baselineskip
+ \divide\dimen@ by 2 % target to split to
+ %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}%
+ \splittopskip = \topskip
+ % Loop until we get a decent breakpoint.
+ {%
+ \vbadness = 10000
+ \loop
+ \global\setbox3 = \copy0
+ \global\setbox1 = \vsplit3 to \dimen@
+ \ifdim\ht3>\dimen@
+ \global\advance\dimen@ by 1pt
+ \repeat
+ }%
+ %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}%
+ \setbox0=\vbox to\dimen@{\unvbox1}%
+ \setbox2=\vbox to\dimen@{\unvbox3}%
+ %
+ \pagesofar
+}
+\catcode`\@ = \other
+
+
+\message{sectioning,}
+% Define chapters, sections, etc.
+
+\newcount\chapno
+\newcount\secno \secno=0
+\newcount\subsecno \subsecno=0
+\newcount\subsubsecno \subsubsecno=0
+
+% This counter is funny since it counts through charcodes of letters A, B, ...
+\newcount\appendixno \appendixno = `\@
+\def\appendixletter{\char\the\appendixno}
+
+% Each @chapter defines this as the name of the chapter.
+% page headings and footings can use it. @section does likewise.
+\def\thischapter{}
+\def\thissection{}
+
+\newcount\absseclevel % used to calculate proper heading level
+\newcount\secbase\secbase=0 % @raise/lowersections modify this count
+
+% @raisesections: treat @section as chapter, @subsection as section, etc.
+\def\raisesections{\global\advance\secbase by -1}
+\let\up=\raisesections % original BFox name
+
+% @lowersections: treat @chapter as section, @section as subsection, etc.
+\def\lowersections{\global\advance\secbase by 1}
+\let\down=\lowersections % original BFox name
+
+% Choose a numbered-heading macro
+% #1 is heading level if unmodified by @raisesections or @lowersections
+% #2 is text for heading
+\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+ \chapterzzz{#2}
+\or
+ \seczzz{#2}
+\or
+ \numberedsubseczzz{#2}
+\or
+ \numberedsubsubseczzz{#2}
+\else
+ \ifnum \absseclevel<0
+ \chapterzzz{#2}
+ \else
+ \numberedsubsubseczzz{#2}
+ \fi
+\fi
+}
+
+% like \numhead, but chooses appendix heading levels
+\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+ \appendixzzz{#2}
+\or
+ \appendixsectionzzz{#2}
+\or
+ \appendixsubseczzz{#2}
+\or
+ \appendixsubsubseczzz{#2}
+\else
+ \ifnum \absseclevel<0
+ \appendixzzz{#2}
+ \else
+ \appendixsubsubseczzz{#2}
+ \fi
+\fi
+}
+
+% like \numhead, but chooses numberless heading levels
+\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+ \unnumberedzzz{#2}
+\or
+ \unnumberedseczzz{#2}
+\or
+ \unnumberedsubseczzz{#2}
+\or
+ \unnumberedsubsubseczzz{#2}
+\else
+ \ifnum \absseclevel<0
+ \unnumberedzzz{#2}
+ \else
+ \unnumberedsubsubseczzz{#2}
+ \fi
+\fi
+}
+
+% @chapter, @appendix, @unnumbered.
+\def\thischaptername{No Chapter Title}
+\outer\def\chapter{\parsearg\chapteryyy}
+\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz
+\def\chapterzzz #1{%
+\secno=0 \subsecno=0 \subsubsecno=0
+\global\advance \chapno by 1 \message{\putwordChapter\space \the\chapno}%
+\chapmacro {#1}{\the\chapno}%
+\gdef\thissection{#1}%
+\gdef\thischaptername{#1}%
+% We don't substitute the actual chapter name into \thischapter
+% because we don't want its macros evaluated now.
+\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}%
+ {\the\chapno}}}%
+\temp
+\donoderef
+\global\let\section = \numberedsec
+\global\let\subsection = \numberedsubsec
+\global\let\subsubsection = \numberedsubsubsec
+}
+
+\outer\def\appendix{\parsearg\appendixyyy}
+\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz
+\def\appendixzzz #1{%
+\secno=0 \subsecno=0 \subsubsecno=0
+\global\advance \appendixno by 1
+\message{\putwordAppendix\space \appendixletter}%
+\chapmacro {#1}{\putwordAppendix{} \appendixletter}%
+\gdef\thissection{#1}%
+\gdef\thischaptername{#1}%
+\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}%
+ {\putwordAppendix{} \appendixletter}}}%
+\temp
+\appendixnoderef
+\global\let\section = \appendixsec
+\global\let\subsection = \appendixsubsec
+\global\let\subsubsection = \appendixsubsubsec
+}
+
+% @centerchap is like @unnumbered, but the heading is centered.
+\outer\def\centerchap{\parsearg\centerchapyyy}
+\def\centerchapyyy #1{{\let\unnumbchapmacro=\centerchapmacro \unnumberedyyy{#1}}}
+
+% @top is like @unnumbered.
+\outer\def\top{\parsearg\unnumberedyyy}
+
+\outer\def\unnumbered{\parsearg\unnumberedyyy}
+\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz
+\def\unnumberedzzz #1{%
+\secno=0 \subsecno=0 \subsubsecno=0
+%
+% This used to be simply \message{#1}, but TeX fully expands the
+% argument to \message. Therefore, if #1 contained @-commands, TeX
+% expanded them. For example, in `@unnumbered The @cite{Book}', TeX
+% expanded @cite (which turns out to cause errors because \cite is meant
+% to be executed, not expanded).
+%
+% Anyway, we don't want the fully-expanded definition of @cite to appear
+% as a result of the \message, we just want `@cite' itself. We use
+% \the<toks register> to achieve this: TeX expands \the<toks> only once,
+% simply yielding the contents of <toks register>. (We also do this for
+% the toc entries.)
+\toks0 = {#1}\message{(\the\toks0)}%
+%
+\unnumbchapmacro {#1}%
+\gdef\thischapter{#1}\gdef\thissection{#1}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash unnumbchapentry{\the\toks0}}}%
+\temp
+\unnumbnoderef
+\global\let\section = \unnumberedsec
+\global\let\subsection = \unnumberedsubsec
+\global\let\subsubsection = \unnumberedsubsubsec
+}
+
+% Sections.
+\outer\def\numberedsec{\parsearg\secyyy}
+\def\secyyy #1{\numhead1{#1}} % normally calls seczzz
+\def\seczzz #1{%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}%
+ {\the\chapno}{\the\secno}}}%
+\temp
+\donoderef
+\nobreak
+}
+
+\outer\def\appendixsection{\parsearg\appendixsecyyy}
+\outer\def\appendixsec{\parsearg\appendixsecyyy}
+\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz
+\def\appendixsectionzzz #1{%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}%
+ {\appendixletter}{\the\secno}}}%
+\temp
+\appendixnoderef
+\nobreak
+}
+
+\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy}
+\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz
+\def\unnumberedseczzz #1{%
+\plainsecheading {#1}\gdef\thissection{#1}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsecentry{\the\toks0}}}%
+\temp
+\unnumbnoderef
+\nobreak
+}
+
+% Subsections.
+\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy}
+\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz
+\def\numberedsubseczzz #1{%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}%
+ {\the\chapno}{\the\secno}{\the\subsecno}}}%
+\temp
+\donoderef
+\nobreak
+}
+
+\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy}
+\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz
+\def\appendixsubseczzz #1{%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}%
+ {\appendixletter}{\the\secno}{\the\subsecno}}}%
+\temp
+\appendixnoderef
+\nobreak
+}
+
+\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy}
+\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz
+\def\unnumberedsubseczzz #1{%
+\plainsubsecheading {#1}\gdef\thissection{#1}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsecentry%
+ {\the\toks0}}}%
+\temp
+\unnumbnoderef
+\nobreak
+}
+
+% Subsubsections.
+\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy}
+\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz
+\def\numberedsubsubseczzz #1{%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}
+ {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}%
+ {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}%
+\temp
+\donoderef
+\nobreak
+}
+
+\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy}
+\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz
+\def\appendixsubsubseczzz #1{%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}
+ {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}%
+ {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}%
+\temp
+\appendixnoderef
+\nobreak
+}
+
+\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy}
+\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz
+\def\unnumberedsubsubseczzz #1{%
+\plainsubsubsecheading {#1}\gdef\thissection{#1}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsubsecentry%
+ {\the\toks0}}}%
+\temp
+\unnumbnoderef
+\nobreak
+}
+
+% These are variants which are not "outer", so they can appear in @ifinfo.
+% Actually, they should now be obsolete; ordinary section commands should work.
+\def\infotop{\parsearg\unnumberedzzz}
+\def\infounnumbered{\parsearg\unnumberedzzz}
+\def\infounnumberedsec{\parsearg\unnumberedseczzz}
+\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz}
+\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz}
+
+\def\infoappendix{\parsearg\appendixzzz}
+\def\infoappendixsec{\parsearg\appendixseczzz}
+\def\infoappendixsubsec{\parsearg\appendixsubseczzz}
+\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz}
+
+\def\infochapter{\parsearg\chapterzzz}
+\def\infosection{\parsearg\sectionzzz}
+\def\infosubsection{\parsearg\subsectionzzz}
+\def\infosubsubsection{\parsearg\subsubsectionzzz}
+
+% These macros control what the section commands do, according
+% to what kind of chapter we are in (ordinary, appendix, or unnumbered).
+% Define them by default for a numbered chapter.
+\global\let\section = \numberedsec
+\global\let\subsection = \numberedsubsec
+\global\let\subsubsection = \numberedsubsubsec
+
+% Define @majorheading, @heading and @subheading
+
+% NOTE on use of \vbox for chapter headings, section headings, and such:
+% 1) We use \vbox rather than the earlier \line to permit
+% overlong headings to fold.
+% 2) \hyphenpenalty is set to 10000 because hyphenation in a
+% heading is obnoxious; this forbids it.
+% 3) Likewise, headings look best if no \parindent is used, and
+% if justification is not attempted. Hence \raggedright.
+
+
+\def\majorheading{\parsearg\majorheadingzzz}
+\def\majorheadingzzz #1{%
+{\advance\chapheadingskip by 10pt \chapbreak }%
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\penalty 200}
+
+\def\chapheading{\parsearg\chapheadingzzz}
+\def\chapheadingzzz #1{\chapbreak %
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\penalty 200}
+
+% @heading, @subheading, @subsubheading.
+\def\heading{\parsearg\plainsecheading}
+\def\subheading{\parsearg\plainsubsecheading}
+\def\subsubheading{\parsearg\plainsubsubsecheading}
+
+% These macros generate a chapter, section, etc. heading only
+% (including whitespace, linebreaking, etc. around it),
+% given all the information in convenient, parsed form.
+
+%%% Args are the skip and penalty (usually negative)
+\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
+
+\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
+
+%%% Define plain chapter starts, and page on/off switching for it
+% Parameter controlling skip before chapter headings (if needed)
+
+\newskip\chapheadingskip
+
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+\def\chappager{\par\vfill\supereject}
+\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi}
+
+\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname}
+
+\def\CHAPPAGoff{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chapbreak
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGon{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chappager
+\global\let\pagealignmacro=\chappager
+\global\def\HEADINGSon{\HEADINGSsingle}}
+
+\def\CHAPPAGodd{
+\global\let\contentsalignmacro = \chapoddpage
+\global\let\pchapsepmacro=\chapoddpage
+\global\let\pagealignmacro=\chapoddpage
+\global\def\HEADINGSon{\HEADINGSdouble}}
+
+\CHAPPAGon
+
+\def\CHAPFplain{
+\global\let\chapmacro=\chfplain
+\global\let\unnumbchapmacro=\unnchfplain
+\global\let\centerchapmacro=\centerchfplain}
+
+% Plain chapter opening.
+% #1 is the text, #2 the chapter number or empty if unnumbered.
+\def\chfplain#1#2{%
+ \pchapsepmacro
+ {%
+ \chapfonts \rm
+ \def\chapnum{#2}%
+ \setbox0 = \hbox{#2\ifx\chapnum\empty\else\enspace\fi}%
+ \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright
+ \hangindent = \wd0 \centerparametersmaybe
+ \unhbox0 #1\par}%
+ }%
+ \nobreak\bigskip % no page break after a chapter title
+ \nobreak
+}
+
+% Plain opening for unnumbered.
+\def\unnchfplain#1{\chfplain{#1}{}}
+
+% @centerchap -- centered and unnumbered.
+\let\centerparametersmaybe = \relax
+\def\centerchfplain#1{{%
+ \def\centerparametersmaybe{%
+ \advance\rightskip by 3\rightskip
+ \leftskip = \rightskip
+ \parfillskip = 0pt
+ }%
+ \chfplain{#1}{}%
+}}
+
+\CHAPFplain % The default
+
+\def\unnchfopen #1{%
+\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\nobreak
+}
+
+\def\chfopen #1#2{\chapoddpage {\chapfonts
+\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}%
+\par\penalty 5000 %
+}
+
+\def\centerchfopen #1{%
+\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt
+ \hfill {\rm #1}\hfill}}\bigskip \par\nobreak
+}
+
+\def\CHAPFopen{
+\global\let\chapmacro=\chfopen
+\global\let\unnumbchapmacro=\unnchfopen
+\global\let\centerchapmacro=\centerchfopen}
+
+
+% Section titles.
+\newskip\secheadingskip
+\def\secheadingbreak{\dobreak \secheadingskip {-1000}}
+\def\secheading#1#2#3{\sectionheading{sec}{#2.#3}{#1}}
+\def\plainsecheading#1{\sectionheading{sec}{}{#1}}
+
+% Subsection titles.
+\newskip \subsecheadingskip
+\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}}
+\def\subsecheading#1#2#3#4{\sectionheading{subsec}{#2.#3.#4}{#1}}
+\def\plainsubsecheading#1{\sectionheading{subsec}{}{#1}}
+
+% Subsubsection titles.
+\let\subsubsecheadingskip = \subsecheadingskip
+\let\subsubsecheadingbreak = \subsecheadingbreak
+\def\subsubsecheading#1#2#3#4#5{\sectionheading{subsubsec}{#2.#3.#4.#5}{#1}}
+\def\plainsubsubsecheading#1{\sectionheading{subsubsec}{}{#1}}
+
+
+% Print any size section title.
+%
+% #1 is the section type (sec/subsec/subsubsec), #2 is the section
+% number (maybe empty), #3 the text.
+\def\sectionheading#1#2#3{%
+ {%
+ \expandafter\advance\csname #1headingskip\endcsname by \parskip
+ \csname #1headingbreak\endcsname
+ }%
+ {%
+ % Switch to the right set of fonts.
+ \csname #1fonts\endcsname \rm
+ %
+ % Only insert the separating space if we have a section number.
+ \def\secnum{#2}%
+ \setbox0 = \hbox{#2\ifx\secnum\empty\else\enspace\fi}%
+ %
+ \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright
+ \hangindent = \wd0 % zero if no section number
+ \unhbox0 #3}%
+ }%
+ \ifdim\parskip<10pt \nobreak\kern10pt\nobreak\kern-\parskip\fi \nobreak
+}
+
+
+\message{toc,}
+\newwrite\tocfile
+
+% Write an entry to the toc file, opening it if necessary.
+% Called from @chapter, etc. We supply {\folio} at the end of the
+% argument, which will end up as the last argument to the \...entry macro.
+%
+% We open the .toc file here instead of at @setfilename or any other
+% given time so that @contents can be put in the document anywhere.
+%
+\newif\iftocfileopened
+\def\writetocentry#1{%
+ \iftocfileopened\else
+ \immediate\openout\tocfile = \jobname.toc
+ \global\tocfileopenedtrue
+ \fi
+ \iflinks \write\tocfile{#1{\folio}}\fi
+}
+
+\newskip\contentsrightmargin \contentsrightmargin=1in
+\newcount\savepageno
+\newcount\lastnegativepageno \lastnegativepageno = -1
+
+% Finish up the main text and prepare to read what we've written
+% to \tocfile.
+%
+\def\startcontents#1{%
+ % If @setchapternewpage on, and @headings double, the contents should
+ % start on an odd page, unlike chapters. Thus, we maintain
+ % \contentsalignmacro in parallel with \pagealignmacro.
+ % From: Torbjorn Granlund <tege@matematik.su.se>
+ \contentsalignmacro
+ \immediate\closeout\tocfile
+ %
+ % Don't need to put `Contents' or `Short Contents' in the headline.
+ % It is abundantly clear what they are.
+ \unnumbchapmacro{#1}\def\thischapter{}%
+ \savepageno = \pageno
+ \begingroup % Set up to handle contents files properly.
+ \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11
+ % We can't do this, because then an actual ^ in a section
+ % title fails, e.g., @chapter ^ -- exponentiation. --karl, 9jul97.
+ %\catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi
+ \raggedbottom % Worry more about breakpoints than the bottom.
+ \advance\hsize by -\contentsrightmargin % Don't use the full line length.
+ %
+ % Roman numerals for page numbers.
+ \ifnum \pageno>0 \pageno = \lastnegativepageno \fi
+}
+
+
+% Normal (long) toc.
+\def\contents{%
+ \startcontents{\putwordTOC}%
+ \openin 1 \jobname.toc
+ \ifeof 1 \else
+ \closein 1
+ \input \jobname.toc
+ \fi
+ \vfill \eject
+ \contentsalignmacro % in case @setchapternewpage odd is in effect
+ \endgroup
+ \lastnegativepageno = \pageno
+ \pageno = \savepageno
+}
+
+% And just the chapters.
+\def\summarycontents{%
+ \startcontents{\putwordShortTOC}%
+ %
+ \let\chapentry = \shortchapentry
+ \let\unnumbchapentry = \shortunnumberedentry
+ % We want a true roman here for the page numbers.
+ \secfonts
+ \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl
+ \rm
+ \hyphenpenalty = 10000
+ \advance\baselineskip by 1pt % Open it up a little.
+ \def\secentry ##1##2##3##4{}
+ \def\unnumbsecentry ##1##2{}
+ \def\subsecentry ##1##2##3##4##5{}
+ \def\unnumbsubsecentry ##1##2{}
+ \def\subsubsecentry ##1##2##3##4##5##6{}
+ \def\unnumbsubsubsecentry ##1##2{}
+ \openin 1 \jobname.toc
+ \ifeof 1 \else
+ \closein 1
+ \input \jobname.toc
+ \fi
+ \vfill \eject
+ \contentsalignmacro % in case @setchapternewpage odd is in effect
+ \endgroup
+ \lastnegativepageno = \pageno
+ \pageno = \savepageno
+}
+\let\shortcontents = \summarycontents
+
+% These macros generate individual entries in the table of contents.
+% The first argument is the chapter or section name.
+% The last argument is the page number.
+% The arguments in between are the chapter number, section number, ...
+
+% Chapter-level things, for both the long and short contents.
+\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}}
+
+% See comments in \dochapentry re vbox and related settings
+\def\shortchapentry#1#2#3{%
+ \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}%
+}
+
+% Typeset the label for a chapter or appendix for the short contents.
+% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter.
+% We could simplify the code here by writing out an \appendixentry
+% command in the toc file for appendices, instead of using \chapentry
+% for both, but it doesn't seem worth it.
+\setbox0 = \hbox{\shortcontrm \putwordAppendix }
+\newdimen\shortappendixwidth \shortappendixwidth = \wd0
+
+\def\shortchaplabel#1{%
+ % We typeset #1 in a box of constant width, regardless of the text of
+ % #1, so the chapter titles will come out aligned.
+ \setbox0 = \hbox{#1}%
+ \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi
+ %
+ % This space should be plenty, since a single number is .5em, and the
+ % widest letter (M) is 1em, at least in the Computer Modern fonts.
+ % (This space doesn't include the extra space that gets added after
+ % the label; that gets put in by \shortchapentry above.)
+ \advance\dimen0 by 1.1em
+ \hbox to \dimen0{#1\hfil}%
+}
+
+\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}}
+\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}}
+
+% Sections.
+\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}}
+\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}}
+
+% Subsections.
+\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}}
+\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}}
+
+% And subsubsections.
+\def\subsubsecentry#1#2#3#4#5#6{%
+ \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}}
+\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}}
+
+% This parameter controls the indentation of the various levels.
+\newdimen\tocindent \tocindent = 3pc
+
+% Now for the actual typesetting. In all these, #1 is the text and #2 is the
+% page number.
+%
+% If the toc has to be broken over pages, we want it to be at chapters
+% if at all possible; hence the \penalty.
+\def\dochapentry#1#2{%
+ \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip
+ \begingroup
+ \chapentryfonts
+ \tocentry{#1}{\dopageno{#2}}%
+ \endgroup
+ \nobreak\vskip .25\baselineskip plus.1\baselineskip
+}
+
+\def\dosecentry#1#2{\begingroup
+ \secentryfonts \leftskip=\tocindent
+ \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+\def\dosubsecentry#1#2{\begingroup
+ \subsecentryfonts \leftskip=2\tocindent
+ \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+\def\dosubsubsecentry#1#2{\begingroup
+ \subsubsecentryfonts \leftskip=3\tocindent
+ \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+% Final typesetting of a toc entry; we use the same \entry macro as for
+% the index entries, but we want to suppress hyphenation here. (We
+% can't do that in the \entry macro, since index entries might consist
+% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.)
+\def\tocentry#1#2{\begingroup
+ \vskip 0pt plus1pt % allow a little stretch for the sake of nice page breaks
+ % Do not use \turnoffactive in these arguments. Since the toc is
+ % typeset in cmr, so characters such as _ would come out wrong; we
+ % have to do the usual translation tricks.
+ \entry{#1}{#2}%
+\endgroup}
+
+% Space between chapter (or whatever) number and the title.
+\def\labelspace{\hskip1em \relax}
+
+\def\dopageno#1{{\rm #1}}
+\def\doshortpageno#1{{\rm #1}}
+
+\def\chapentryfonts{\secfonts \rm}
+\def\secentryfonts{\textfonts}
+\let\subsecentryfonts = \textfonts
+\let\subsubsecentryfonts = \textfonts
+
+
+\message{environments,}
+
+% Since these characters are used in examples, it should be an even number of
+% \tt widths. Each \tt character is 1en, so two makes it 1em.
+% Furthermore, these definitions must come after we define our fonts.
+\newbox\dblarrowbox \newbox\longdblarrowbox
+\newbox\pushcharbox \newbox\bullbox
+\newbox\equivbox \newbox\errorbox
+
+%{\tentt
+%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil}
+%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil}
+%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil}
+%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil}
+% Adapted from the manmac format (p.420 of TeXbook)
+%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex
+% depth .1ex\hfil}
+%}
+
+% @point{}, @result{}, @expansion{}, @print{}, @equiv{}.
+\def\point{$\star$}
+\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}}
+\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}}
+\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}}
+\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}}
+
+% Adapted from the TeXbook's \boxit.
+{\tentt \global\dimen0 = 3em}% Width of the box.
+\dimen2 = .55pt % Thickness of rules
+% The text. (`r' is open on the right, `e' somewhat less so on the left.)
+\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt}
+
+\global\setbox\errorbox=\hbox to \dimen0{\hfil
+ \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right.
+ \advance\hsize by -2\dimen2 % Rules.
+ \vbox{
+ \hrule height\dimen2
+ \hbox{\vrule width\dimen2 \kern3pt % Space to left of text.
+ \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below.
+ \kern3pt\vrule width\dimen2}% Space to right.
+ \hrule height\dimen2}
+ \hfil}
+
+% The @error{} command.
+\def\error{\leavevmode\lower.7ex\copy\errorbox}
+
+% @tex ... @end tex escapes into raw Tex temporarily.
+% One exception: @ is still an escape character, so that @end tex works.
+% But \@ or @@ will get a plain tex @ character.
+
+\def\tex{\begingroup
+ \catcode `\\=0 \catcode `\{=1 \catcode `\}=2
+ \catcode `\$=3 \catcode `\&=4 \catcode `\#=6
+ \catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie
+ \catcode `\%=14
+ \catcode 43=12 % plus
+ \catcode`\"=12
+ \catcode`\==12
+ \catcode`\|=12
+ \catcode`\<=12
+ \catcode`\>=12
+ \escapechar=`\\
+ %
+ \let\b=\ptexb
+ \let\bullet=\ptexbullet
+ \let\c=\ptexc
+ \let\,=\ptexcomma
+ \let\.=\ptexdot
+ \let\dots=\ptexdots
+ \let\equiv=\ptexequiv
+ \let\!=\ptexexclam
+ \let\i=\ptexi
+ \let\{=\ptexlbrace
+ \let\+=\tabalign
+ \let\}=\ptexrbrace
+ \let\*=\ptexstar
+ \let\t=\ptext
+ %
+ \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}%
+ \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}%
+ \def\@{@}%
+\let\Etex=\endgroup}
+
+% Define @lisp ... @endlisp.
+% @lisp does a \begingroup so it can rebind things,
+% including the definition of @endlisp (which normally is erroneous).
+
+% Amount to narrow the margins by for @lisp.
+\newskip\lispnarrowing \lispnarrowing=0.4in
+
+% This is the definition that ^^M gets inside @lisp, @example, and other
+% such environments. \null is better than a space, since it doesn't
+% have any width.
+\def\lisppar{\null\endgraf}
+
+% Make each space character in the input produce a normal interword
+% space in the output. Don't allow a line break at this space, as this
+% is used only in environments like @example, where each line of input
+% should produce a line of output anyway.
+%
+{\obeyspaces %
+\gdef\sepspaces{\obeyspaces\let =\tie}}
+
+% Define \obeyedspace to be our active space, whatever it is. This is
+% for use in \parsearg.
+{\sepspaces%
+\global\let\obeyedspace= }
+
+% This space is always present above and below environments.
+\newskip\envskipamount \envskipamount = 0pt
+
+% Make spacing and below environment symmetrical. We use \parskip here
+% to help in doing that, since in @example-like environments \parskip
+% is reset to zero; thus the \afterenvbreak inserts no space -- but the
+% start of the next paragraph will insert \parskip
+%
+\def\aboveenvbreak{{\advance\envskipamount by \parskip
+\endgraf \ifdim\lastskip<\envskipamount
+\removelastskip \penalty-50 \vskip\envskipamount \fi}}
+
+\let\afterenvbreak = \aboveenvbreak
+
+% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins.
+\let\nonarrowing=\relax
+
+% @cartouche ... @end cartouche: draw rectangle w/rounded corners around
+% environment contents.
+\font\circle=lcircle10
+\newdimen\circthick
+\newdimen\cartouter\newdimen\cartinner
+\newskip\normbskip\newskip\normpskip\newskip\normlskip
+\circthick=\fontdimen8\circle
+%
+\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth
+\def\ctr{{\hskip 6pt\circle\char'010}}
+\def\cbl{{\circle\char'012\hskip -6pt}}
+\def\cbr{{\hskip 6pt\circle\char'011}}
+\def\carttop{\hbox to \cartouter{\hskip\lskip
+ \ctl\leaders\hrule height\circthick\hfil\ctr
+ \hskip\rskip}}
+\def\cartbot{\hbox to \cartouter{\hskip\lskip
+ \cbl\leaders\hrule height\circthick\hfil\cbr
+ \hskip\rskip}}
+%
+\newskip\lskip\newskip\rskip
+
+\long\def\cartouche{%
+\begingroup
+ \lskip=\leftskip \rskip=\rightskip
+ \leftskip=0pt\rightskip=0pt %we want these *outside*.
+ \cartinner=\hsize \advance\cartinner by-\lskip
+ \advance\cartinner by-\rskip
+ \cartouter=\hsize
+ \advance\cartouter by 18.4pt % allow for 3pt kerns on either
+% side, and for 6pt waste from
+% each corner char, and rule thickness
+ \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip
+ % Flag to tell @lisp, etc., not to narrow margin.
+ \let\nonarrowing=\comment
+ \vbox\bgroup
+ \baselineskip=0pt\parskip=0pt\lineskip=0pt
+ \carttop
+ \hbox\bgroup
+ \hskip\lskip
+ \vrule\kern3pt
+ \vbox\bgroup
+ \hsize=\cartinner
+ \kern3pt
+ \begingroup
+ \baselineskip=\normbskip
+ \lineskip=\normlskip
+ \parskip=\normpskip
+ \vskip -\parskip
+\def\Ecartouche{%
+ \endgroup
+ \kern3pt
+ \egroup
+ \kern3pt\vrule
+ \hskip\rskip
+ \egroup
+ \cartbot
+ \egroup
+\endgroup
+}}
+
+
+% This macro is called at the beginning of all the @example variants,
+% inside a group.
+\def\nonfillstart{%
+ \aboveenvbreak
+ \inENV % This group ends at the end of the body
+ \hfuzz = 12pt % Don't be fussy
+ \sepspaces % Make spaces be word-separators rather than space tokens.
+ \singlespace
+ \let\par = \lisppar % don't ignore blank lines
+ \obeylines % each line of input is a line of output
+ \parskip = 0pt
+ \parindent = 0pt
+ \emergencystretch = 0pt % don't try to avoid overfull boxes
+ % @cartouche defines \nonarrowing to inhibit narrowing
+ % at next level down.
+ \ifx\nonarrowing\relax
+ \advance \leftskip by \lispnarrowing
+ \exdentamount=\lispnarrowing
+ \let\exdent=\nofillexdent
+ \let\nonarrowing=\relax
+ \fi
+}
+
+% Define the \E... control sequence only if we are inside the particular
+% environment, so the error checking in \end will work.
+%
+% To end an @example-like environment, we first end the paragraph (via
+% \afterenvbreak's vertical glue), and then the group. That way we keep
+% the zero \parskip that the environments set -- \parskip glue will be
+% inserted at the beginning of the next paragraph in the document, after
+% the environment.
+%
+\def\nonfillfinish{\afterenvbreak\endgroup}
+
+% @lisp: indented, narrowed, typewriter font.
+\def\lisp{\begingroup
+ \nonfillstart
+ \let\Elisp = \nonfillfinish
+ \tt
+ \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special.
+ \gobble % eat return
+}
+
+% @example: Same as @lisp.
+\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp}
+
+% @small... is usually equivalent to the non-small (@smallbook
+% redefines). We must call \example (or whatever) last in the
+% definition, since it reads the return following the @example (or
+% whatever) command.
+%
+% This actually allows (for example) @end display inside an
+% @smalldisplay. Too bad, but makeinfo will catch the error anyway.
+%
+\def\smalldisplay{\begingroup\def\Esmalldisplay{\nonfillfinish\endgroup}\display}
+\def\smallexample{\begingroup\def\Esmallexample{\nonfillfinish\endgroup}\lisp}
+\def\smallformat{\begingroup\def\Esmallformat{\nonfillfinish\endgroup}\format}
+\def\smalllisp{\begingroup\def\Esmalllisp{\nonfillfinish\endgroup}\lisp}
+
+% Real @smallexample and @smalllisp (when @smallbook): use smaller fonts.
+% Originally contributed by Pavel@xerox.
+\def\smalllispx{\begingroup
+ \def\Esmalllisp{\nonfillfinish\endgroup}%
+ \def\Esmallexample{\nonfillfinish\endgroup}%
+ \indexfonts
+ \lisp
+}
+
+% @display: same as @lisp except keep current font.
+%
+\def\display{\begingroup
+ \nonfillstart
+ \let\Edisplay = \nonfillfinish
+ \gobble
+}
+
+% @smalldisplay (when @smallbook): @display plus smaller fonts.
+%
+\def\smalldisplayx{\begingroup
+ \def\Esmalldisplay{\nonfillfinish\endgroup}%
+ \indexfonts \rm
+ \display
+}
+
+% @format: same as @display except don't narrow margins.
+%
+\def\format{\begingroup
+ \let\nonarrowing = t
+ \nonfillstart
+ \let\Eformat = \nonfillfinish
+ \gobble
+}
+
+% @smallformat (when @smallbook): @format plus smaller fonts.
+%
+\def\smallformatx{\begingroup
+ \def\Esmallformat{\nonfillfinish\endgroup}%
+ \indexfonts \rm
+ \format
+}
+
+% @flushleft (same as @format).
+%
+\def\flushleft{\begingroup \def\Eflushleft{\nonfillfinish\endgroup}\format}
+
+% @flushright.
+%
+\def\flushright{\begingroup
+ \let\nonarrowing = t
+ \nonfillstart
+ \let\Eflushright = \nonfillfinish
+ \advance\leftskip by 0pt plus 1fill
+ \gobble
+}
+
+% @quotation does normal linebreaking (hence we can't use \nonfillstart)
+% and narrows the margins.
+%
+\def\quotation{%
+ \begingroup\inENV %This group ends at the end of the @quotation body
+ {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip
+ \singlespace
+ \parindent=0pt
+ % We have retained a nonzero parskip for the environment, since we're
+ % doing normal filling. So to avoid extra space below the environment...
+ \def\Equotation{\parskip = 0pt \nonfillfinish}%
+ %
+ % @cartouche defines \nonarrowing to inhibit narrowing at next level down.
+ \ifx\nonarrowing\relax
+ \advance\leftskip by \lispnarrowing
+ \advance\rightskip by \lispnarrowing
+ \exdentamount = \lispnarrowing
+ \let\nonarrowing = \relax
+ \fi
+}
+
+
+\message{defuns,}
+% Define formatter for defuns
+% First, allow user to change definition object font (\df) internally
+\def\setdeffont #1 {\csname DEF#1\endcsname}
+
+\newskip\defbodyindent \defbodyindent=.4in
+\newskip\defargsindent \defargsindent=50pt
+\newskip\deftypemargin \deftypemargin=12pt
+\newskip\deflastargmargin \deflastargmargin=18pt
+
+\newcount\parencount
+% define \functionparens, which makes ( and ) and & do special things.
+% \functionparens affects the group it is contained in.
+\def\activeparens{%
+\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active
+\catcode`\[=\active \catcode`\]=\active}
+
+% Make control sequences which act like normal parenthesis chars.
+\let\lparen = ( \let\rparen = )
+
+{\activeparens % Now, smart parens don't turn on until &foo (see \amprm)
+
+% Be sure that we always have a definition for `(', etc. For example,
+% if the fn name has parens in it, \boldbrax will not be in effect yet,
+% so TeX would otherwise complain about undefined control sequence.
+\global\let(=\lparen \global\let)=\rparen
+\global\let[=\lbrack \global\let]=\rbrack
+
+\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 }
+\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+% This is used to turn on special parens
+% but make & act ordinary (given that it's active).
+\gdef\boldbraxnoamp{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb\let&=\ampnr}
+
+% Definitions of (, ) and & used in args for functions.
+% This is the definition of ( outside of all parentheses.
+\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested
+ \global\advance\parencount by 1
+}
+%
+% This is the definition of ( when already inside a level of parens.
+\gdef\opnested{\char`\(\global\advance\parencount by 1 }
+%
+\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0.
+ % also in that case restore the outer-level definition of (.
+ \ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi
+ \global\advance \parencount by -1 }
+% If we encounter &foo, then turn on ()-hacking afterwards
+\gdef\amprm#1 {{\rm\&#1}\let(=\oprm \let)=\clrm\ }
+%
+\gdef\normalparens{\boldbrax\let&=\ampnr}
+} % End of definition inside \activeparens
+%% These parens (in \boldbrax) actually are a little bolder than the
+%% contained text. This is especially needed for [ and ]
+\def\opnr{{\sf\char`\(}\global\advance\parencount by 1 }
+\def\clnr{{\sf\char`\)}\global\advance\parencount by -1 }
+\def\ampnr{\&}
+\def\lbrb{{\bf\char`\[}}
+\def\rbrb{{\bf\char`\]}}
+
+% First, defname, which formats the header line itself.
+% #1 should be the function name.
+% #2 should be the type of definition, such as "Function".
+
+\def\defname #1#2{%
+% Get the values of \leftskip and \rightskip as they were
+% outside the @def...
+\dimen2=\leftskip
+\advance\dimen2 by -\defbodyindent
+\noindent
+\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}%
+\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line
+\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations
+\parshape 2 0in \dimen0 \defargsindent \dimen1
+% Now output arg 2 ("Function" or some such)
+% ending at \deftypemargin from the right margin,
+% but stuck inside a box of width 0 so it does not interfere with linebreaking
+{% Adjust \hsize to exclude the ambient margins,
+% so that \rightline will obey them.
+\advance \hsize by -\dimen2
+\rlap{\rightline{{\rm #2}\hskip -1.25pc }}}%
+% Make all lines underfull and no complaints:
+\tolerance=10000 \hbadness=10000
+\advance\leftskip by -\defbodyindent
+\exdentamount=\defbodyindent
+{\df #1}\enskip % Generate function name
+}
+
+% Actually process the body of a definition
+% #1 should be the terminating control sequence, such as \Edefun.
+% #2 should be the "another name" control sequence, such as \defunx.
+% #3 should be the control sequence that actually processes the header,
+% such as \defunheader.
+
+\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\activeparens\spacesplit#3}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup %
+\catcode 61=\active % 61 is `='
+\obeylines\activeparens\spacesplit#3}
+
+% #1 is the \E... control sequence to end the definition (which we define).
+% #2 is the \...x control sequence for consecutive fns (which we define).
+% #3 is the control sequence to call to resume processing.
+% #4, delimited by the space, is the class name.
+%
+\def\defmethparsebody#1#2#3#4 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#4}}}
+
+% @deftypemethod has an extra argument that nothing else does. Sigh.
+% #1 is the \E... control sequence to end the definition (which we define).
+% #2 is the \...x control sequence for consecutive fns (which we define).
+% #3 is the control sequence to call to resume processing.
+% #4, delimited by the space, is the class name.
+% #5 is the method's return type.
+%
+\def\deftypemethparsebody#1#2#3#4 #5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#4}{#5}}}
+
+\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\def#4{##1}%
+\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#5}}}
+
+% These parsing functions are similar to the preceding ones
+% except that they do not make parens into active characters.
+% These are used for "variables" since they have no arguments.
+
+\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\spacesplit#3}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup %
+\catcode 61=\active %
+\obeylines\spacesplit#3}
+
+% This is used for \def{tp,vr}parsebody. It could probably be used for
+% some of the others, too, with some judicious conditionals.
+%
+\def\parsebodycommon#1#2#3{%
+ \begingroup\inENV %
+ \medbreak %
+ % Define the end token that this defining construct specifies
+ % so that it will exit this group.
+ \def#1{\endgraf\endgroup\medbreak}%
+ \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}%
+ \parindent=0in
+ \advance\leftskip by \defbodyindent
+ \exdentamount=\defbodyindent
+ \begingroup\obeylines
+}
+
+\def\defvrparsebody#1#2#3#4 {%
+ \parsebodycommon{#1}{#2}{#3}%
+ \spacesplit{#3{#4}}%
+}
+
+% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the
+% type is just `struct', because we lose the braces in `{struct
+% termios}' when \spacesplit reads its undelimited argument. Sigh.
+% \let\deftpparsebody=\defvrparsebody
+%
+% So, to get around this, we put \empty in with the type name. That
+% way, TeX won't find exactly `{...}' as an undelimited argument, and
+% won't strip off the braces.
+%
+\def\deftpparsebody #1#2#3#4 {%
+ \parsebodycommon{#1}{#2}{#3}%
+ \spacesplit{\parsetpheaderline{#3{#4}}}\empty
+}
+
+% Fine, but then we have to eventually remove the \empty *and* the
+% braces (if any). That's what this does.
+%
+\def\removeemptybraces\empty#1\relax{#1}
+
+% After \spacesplit has done its work, this is called -- #1 is the final
+% thing to call, #2 the type name (which starts with \empty), and #3
+% (which might be empty) the arguments.
+%
+\def\parsetpheaderline#1#2#3{%
+ #1{\removeemptybraces#2\relax}{#3}%
+}%
+
+\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\def#4{##1}%
+\begingroup\obeylines\spacesplit{#3{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\spacesplit{#3{#5}}}
+
+% Split up #2 at the first space token.
+% call #1 with two arguments:
+% the first is all of #2 before the space token,
+% the second is all of #2 after that space token.
+% If #2 contains no space token, all of it is passed as the first arg
+% and the second is passed as empty.
+
+{\obeylines
+\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}%
+\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{%
+\ifx\relax #3%
+#1{#2}{}\else #1{#2}{#3#4}\fi}}
+
+% So much for the things common to all kinds of definitions.
+
+% Define @defun.
+
+% First, define the processing that is wanted for arguments of \defun
+% Use this to expand the args and terminate the paragraph they make up
+
+\def\defunargs #1{\functionparens \sl
+% Expand, preventing hyphenation at `-' chars.
+% Note that groups don't affect changes in \hyphenchar.
+\hyphenchar\tensl=0
+#1%
+\hyphenchar\tensl=45
+\ifnum\parencount=0 \else \errmessage{Unbalanced parentheses in @def}\fi%
+\interlinepenalty=10000
+\advance\rightskip by 0pt plus 1fil
+\endgraf\nobreak\vskip -\parskip\nobreak
+}
+
+\def\deftypefunargs #1{%
+% Expand, preventing hyphenation at `-' chars.
+% Note that groups don't affect changes in \hyphenchar.
+% Use \boldbraxnoamp, not \functionparens, so that & is not special.
+\boldbraxnoamp
+\tclose{#1}% avoid \code because of side effects on active chars
+\interlinepenalty=10000
+\advance\rightskip by 0pt plus 1fil
+\endgraf\nobreak\vskip -\parskip\nobreak
+}
+
+% Do complete processing of one @defun or @defunx line already parsed.
+
+% @deffn Command forward-char nchars
+
+\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader}
+
+\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defun == @deffn Function
+
+\def\defun{\defparsebody\Edefun\defunx\defunheader}
+
+\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{\putwordDeffunc}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @deftypefun int foobar (int @var{foo}, float @var{bar})
+
+\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader}
+
+% #1 is the data type. #2 is the name and args.
+\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax}
+% #1 is the data type, #2 the name, #3 the args.
+\def\deftypefunheaderx #1#2 #3\relax{%
+\doind {fn}{\code{#2}}% Make entry in function index
+\begingroup\defname {\defheaderxcond#1\relax$$$#2}{\putwordDeftypefun}%
+\deftypefunargs {#3}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar})
+
+\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader}
+
+% \defheaderxcond#1\relax$$$
+% puts #1 in @code, followed by a space, but does nothing if #1 is null.
+\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi}
+
+% #1 is the classification. #2 is the data type. #3 is the name and args.
+\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax}
+% #1 is the classification, #2 the data type, #3 the name, #4 the args.
+\def\deftypefnheaderx #1#2#3 #4\relax{%
+\doind {fn}{\code{#3}}% Make entry in function index
+\begingroup
+\normalparens % notably, turn off `&' magic, which prevents
+% at least some C++ text from working
+\defname {\defheaderxcond#2\relax$$$#3}{#1}%
+\deftypefunargs {#4}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defmac == @deffn Macro
+
+\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader}
+
+\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{\putwordDefmac}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defspec == @deffn Special Form
+
+\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader}
+
+\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{\putwordDefspec}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% This definition is run if you use @defunx
+% anywhere other than immediately after a @defun or @defunx.
+
+\def\deffnx #1 {\errmessage{@deffnx in invalid context}}
+\def\defunx #1 {\errmessage{@defunx in invalid context}}
+\def\defmacx #1 {\errmessage{@defmacx in invalid context}}
+\def\defspecx #1 {\errmessage{@defspecx in invalid context}}
+\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}}
+\def\deftypemethodx #1 {\errmessage{@deftypemethodx in invalid context}}
+\def\deftypefunx #1 {\errmessage{@deftypefunx in invalid context}}
+
+% @defmethod, and so on
+
+% @defop CATEGORY CLASS OPERATION ARG...
+
+\def\defop #1 {\def\defoptype{#1}%
+\defopparsebody\Edefop\defopx\defopheader\defoptype}
+
+\def\defopheader #1#2#3{%
+\dosubind {fn}{\code{#2}}{\putwordon\ #1}% Make entry in function index
+\begingroup\defname {#2}{\defoptype{}\putwordon\ #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @deftypemethod CLASS RETURN-TYPE METHOD ARG...
+%
+\def\deftypemethod{%
+ \deftypemethparsebody\Edeftypemethod\deftypemethodx\deftypemethodheader}
+%
+% #1 is the class name, #2 the data type, #3 the method name, #4 the args.
+\def\deftypemethodheader#1#2#3#4{%
+ \dosubind{fn}{\code{#3}}{\putwordon\ \code{#1}}% entry in function index
+ \begingroup
+ \defname{\defheaderxcond#2\relax$$$#3}{\putwordMethodon\ \code{#1}}%
+ \deftypefunargs{#4}%
+ \endgroup
+}
+
+% @defmethod == @defop Method
+%
+\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader}
+%
+% #1 is the class name, #2 the method name, #3 the args.
+\def\defmethodheader#1#2#3{%
+ \dosubind{fn}{\code{#2}}{\putwordon\ \code{#1}}% entry in function index
+ \begingroup
+ \defname{#2}{\putwordMethodon\ \code{#1}}%
+ \defunargs{#3}%
+ \endgroup
+}
+
+% @defcv {Class Option} foo-class foo-flag
+
+\def\defcv #1 {\def\defcvtype{#1}%
+\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype}
+
+\def\defcvarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{\putwordof\ #1}% Make entry in var index
+\begingroup\defname {#2}{\defcvtype\ \putwordof\ #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% @defivar == @defcv {Instance Variable}
+
+\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader}
+
+\def\defivarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{\putwordof\ #1}% Make entry in var index
+\begingroup\defname {#2}{\putwordDefivar\ \putwordof\ #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% These definitions are run if you use @defmethodx, etc.,
+% anywhere other than immediately after a @defmethod, etc.
+
+\def\defopx #1 {\errmessage{@defopx in invalid context}}
+\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}}
+\def\defcvx #1 {\errmessage{@defcvx in invalid context}}
+\def\defivarx #1 {\errmessage{@defivarx in invalid context}}
+
+% Now @defvar
+
+% First, define the processing that is wanted for arguments of @defvar.
+% This is actually simple: just print them in roman.
+% This must expand the args and terminate the paragraph they make up
+\def\defvarargs #1{\normalparens #1%
+\interlinepenalty=10000
+\endgraf\nobreak\vskip -\parskip\nobreak}
+
+% @defvr Counter foo-count
+
+\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader}
+
+\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup}
+
+% @defvar == @defvr Variable
+
+\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader}
+
+\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{\putwordDefvar}%
+\defvarargs {#2}\endgroup %
+}
+
+% @defopt == @defvr {User Option}
+
+\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader}
+
+\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{\putwordDefopt}%
+\defvarargs {#2}\endgroup %
+}
+
+% @deftypevar int foobar
+
+\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader}
+
+% #1 is the data type. #2 is the name, perhaps followed by text that
+% is actually part of the data type, which should not be put into the index.
+\def\deftypevarheader #1#2{%
+\dovarind#2 \relax% Make entry in variables index
+\begingroup\defname {\defheaderxcond#1\relax$$$#2}{\putwordDeftypevar}%
+\interlinepenalty=10000
+\endgraf\nobreak\vskip -\parskip\nobreak
+\endgroup}
+\def\dovarind#1 #2\relax{\doind{vr}{\code{#1}}}
+
+% @deftypevr {Global Flag} int enable
+
+\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader}
+
+\def\deftypevrheader #1#2#3{\dovarind#3 \relax%
+\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1}
+\interlinepenalty=10000
+\endgraf\nobreak\vskip -\parskip\nobreak
+\endgroup}
+
+% This definition is run if you use @defvarx
+% anywhere other than immediately after a @defvar or @defvarx.
+
+\def\defvrx #1 {\errmessage{@defvrx in invalid context}}
+\def\defvarx #1 {\errmessage{@defvarx in invalid context}}
+\def\defoptx #1 {\errmessage{@defoptx in invalid context}}
+\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}}
+\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}}
+
+% Now define @deftp
+% Args are printed in bold, a slight difference from @defvar.
+
+\def\deftpargs #1{\bf \defvarargs{#1}}
+
+% @deftp Class window height width ...
+
+\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader}
+
+\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}%
+\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup}
+
+% This definition is run if you use @deftpx, etc
+% anywhere other than immediately after a @deftp, etc.
+
+\def\deftpx #1 {\errmessage{@deftpx in invalid context}}
+
+
+\message{macros,}
+% @macro.
+
+% To do this right we need a feature of e-TeX, \scantokens,
+% which we arrange to emulate with a temporary file in ordinary TeX.
+\ifx\eTeXversion\undefined
+ \newwrite\macscribble
+ \def\scanmacro#1{%
+ \begingroup \newlinechar`\^^M
+ % Undo catcode changes of \startcontents and \doprintindex
+ \catcode`\@=0 \catcode`\\=12 \escapechar=`\@
+ % Append \endinput to make sure that TeX does not see the ending newline.
+ \toks0={#1\endinput}%
+ \immediate\openout\macscribble=\jobname.tmp
+ \immediate\write\macscribble{\the\toks0}%
+ \immediate\closeout\macscribble
+ \let\xeatspaces\eatspaces
+ \input \jobname.tmp
+ \endgroup
+}
+\else
+\def\scanmacro#1{%
+\begingroup \newlinechar`\^^M
+% Undo catcode changes of \startcontents and \doprintindex
+\catcode`\@=0 \catcode`\\=12 \escapechar=`\@
+\let\xeatspaces\eatspaces\scantokens{#1\endinput}\endgroup}
+\fi
+
+\newcount\paramno % Count of parameters
+\newtoks\macname % Macro name
+\newif\ifrecursive % Is it recursive?
+\def\macrolist{} % List of all defined macros in the form
+ % \do\macro1\do\macro2...
+
+% Utility routines.
+% Thisdoes \let #1 = #2, except with \csnames.
+\def\cslet#1#2{%
+\expandafter\expandafter
+\expandafter\let
+\expandafter\expandafter
+\csname#1\endcsname
+\csname#2\endcsname}
+
+% Trim leading and trailing spaces off a string.
+% Concepts from aro-bend problem 15 (see CTAN).
+{\catcode`\@=11
+\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }}
+\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@}
+\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @}
+\def\unbrace#1{#1}
+\unbrace{\gdef\trim@@@ #1 } #2@{#1}
+}
+
+% Trim a single trailing ^^M off a string.
+{\catcode`\^^M=12\catcode`\Q=3%
+\gdef\eatcr #1{\eatcra #1Q^^MQ}%
+\gdef\eatcra#1^^MQ{\eatcrb#1Q}%
+\gdef\eatcrb#1Q#2Q{#1}%
+}
+
+% Macro bodies are absorbed as an argument in a context where
+% all characters are catcode 10, 11 or 12, except \ which is active
+% (as in normal texinfo). It is necessary to change the definition of \.
+
+% It's necessary to have hard CRs when the macro is executed. This is
+% done by making ^^M (\endlinechar) catcode 12 when reading the macro
+% body, and then making it the \newlinechar in \scanmacro.
+
+\def\macrobodyctxt{%
+ \catcode`\~=12
+ \catcode`\^=12
+ \catcode`\_=12
+ \catcode`\|=12
+ \catcode`\<=12
+ \catcode`\>=12
+ \catcode`\+=12
+ \catcode`\{=12
+ \catcode`\}=12
+ \catcode`\@=12
+ \catcode`\^^M=12
+ \usembodybackslash}
+
+\def\macroargctxt{%
+ \catcode`\~=12
+ \catcode`\^=12
+ \catcode`\_=12
+ \catcode`\|=12
+ \catcode`\<=12
+ \catcode`\>=12
+ \catcode`\+=12
+ \catcode`\@=12
+ \catcode`\\=12}
+
+% \mbodybackslash is the definition of \ in @macro bodies.
+% It maps \foo\ => \csname macarg.foo\endcsname => #N
+% where N is the macro parameter number.
+% We define \csname macarg.\endcsname to be \realbackslash, so
+% \\ in macro replacement text gets you a backslash.
+
+{\catcode`@=0 @catcode`@\=@active
+ @gdef@usembodybackslash{@let\=@mbodybackslash}
+ @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname}
+}
+\expandafter\def\csname macarg.\endcsname{\realbackslash}
+
+\def\macro{\recursivefalse\parsearg\macroxxx}
+\def\rmacro{\recursivetrue\parsearg\macroxxx}
+
+\def\macroxxx#1{%
+ \getargs{#1}% now \macname is the macname and \argl the arglist
+ \ifx\argl\empty % no arguments
+ \paramno=0%
+ \else
+ \expandafter\parsemargdef \argl;%
+ \fi
+ \if1\csname ismacro.\the\macname\endcsname
+ \message{Warning: redefining \the\macname}%
+ \else
+ \expandafter\ifx\csname \the\macname\endcsname \relax
+ \else \errmessage{The name \the\macname\space is reserved}\fi
+ \global\cslet{macsave.\the\macname}{\the\macname}%
+ \global\expandafter\let\csname ismacro.\the\macname\endcsname=1%
+ % Add the macroname to \macrolist
+ \toks0 = \expandafter{\macrolist\do}%
+ \xdef\macrolist{\the\toks0
+ \expandafter\noexpand\csname\the\macname\endcsname}%
+ \fi
+ \begingroup \macrobodyctxt
+ \ifrecursive \expandafter\parsermacbody
+ \else \expandafter\parsemacbody
+ \fi}
+
+\def\unmacro{\parsearg\unmacroxxx}
+\def\unmacroxxx#1{%
+ \if1\csname ismacro.#1\endcsname
+ \global\cslet{#1}{macsave.#1}%
+ \global\expandafter\let \csname ismacro.#1\endcsname=0%
+ % Remove the macro name from \macrolist
+ \begingroup
+ \edef\tempa{\expandafter\noexpand\csname#1\endcsname}%
+ \def\do##1{%
+ \def\tempb{##1}%
+ \ifx\tempa\tempb
+ % remove this
+ \else
+ \toks0 = \expandafter{\newmacrolist\do}%
+ \edef\newmacrolist{\the\toks0\expandafter\noexpand\tempa}%
+ \fi}%
+ \def\newmacrolist{}%
+ % Execute macro list to define \newmacrolist
+ \macrolist
+ \global\let\macrolist\newmacrolist
+ \endgroup
+ \else
+ \errmessage{Macro #1 not defined}%
+ \fi
+}
+
+% This makes use of the obscure feature that if the last token of a
+% <parameter list> is #, then the preceding argument is delimited by
+% an opening brace, and that opening brace is not consumed.
+\def\getargs#1{\getargsxxx#1{}}
+\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs}
+\def\getmacname #1 #2\relax{\macname={#1}}
+\def\getmacargs#1{\def\argl{#1}}
+
+% Parse the optional {params} list. Set up \paramno and \paramlist
+% so \defmacro knows what to do. Define \macarg.blah for each blah
+% in the params list, to be ##N where N is the position in that list.
+% That gets used by \mbodybackslash (above).
+
+% We need to get `macro parameter char #' into several definitions.
+% The technique used is stolen from LaTeX: let \hash be something
+% unexpandable, insert that wherever you need a #, and then redefine
+% it to # just before using the token list produced.
+%
+% The same technique is used to protect \eatspaces till just before
+% the macro is used.
+
+\def\parsemargdef#1;{\paramno=0\def\paramlist{}%
+ \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,}
+\def\parsemargdefxxx#1,{%
+ \if#1;\let\next=\relax
+ \else \let\next=\parsemargdefxxx
+ \advance\paramno by 1%
+ \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname
+ {\xeatspaces{\hash\the\paramno}}%
+ \edef\paramlist{\paramlist\hash\the\paramno,}%
+ \fi\next}
+
+% These two commands read recursive and nonrecursive macro bodies.
+% (They're different since rec and nonrec macros end differently.)
+
+\long\def\parsemacbody#1@end macro%
+{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}%
+\long\def\parsermacbody#1@end rmacro%
+{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}%
+
+% This defines the macro itself. There are six cases: recursive and
+% nonrecursive macros of zero, one, and many arguments.
+% Much magic with \expandafter here.
+% \xdef is used so that macro definitions will survive the file
+% they're defined in; @include reads the file inside a group.
+\def\defmacro{%
+ \let\hash=##% convert placeholders to macro parameter chars
+ \ifrecursive
+ \ifcase\paramno
+ % 0
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \noexpand\scanmacro{\temp}}%
+ \or % 1
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \bgroup\noexpand\macroargctxt
+ \noexpand\braceorline
+ \expandafter\noexpand\csname\the\macname xxx\endcsname}%
+ \expandafter\xdef\csname\the\macname xxx\endcsname##1{%
+ \egroup\noexpand\scanmacro{\temp}}%
+ \else % many
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \bgroup\noexpand\macroargctxt
+ \noexpand\csname\the\macname xx\endcsname}%
+ \expandafter\xdef\csname\the\macname xx\endcsname##1{%
+ \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}%
+ \expandafter\expandafter
+ \expandafter\xdef
+ \expandafter\expandafter
+ \csname\the\macname xxx\endcsname
+ \paramlist{\egroup\noexpand\scanmacro{\temp}}%
+ \fi
+ \else
+ \ifcase\paramno
+ % 0
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \noexpand\norecurse{\the\macname}%
+ \noexpand\scanmacro{\temp}\egroup}%
+ \or % 1
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \bgroup\noexpand\macroargctxt
+ \noexpand\braceorline
+ \expandafter\noexpand\csname\the\macname xxx\endcsname}%
+ \expandafter\xdef\csname\the\macname xxx\endcsname##1{%
+ \egroup
+ \noexpand\norecurse{\the\macname}%
+ \noexpand\scanmacro{\temp}\egroup}%
+ \else % many
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \bgroup\noexpand\macroargctxt
+ \expandafter\noexpand\csname\the\macname xx\endcsname}%
+ \expandafter\xdef\csname\the\macname xx\endcsname##1{%
+ \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}%
+ \expandafter\expandafter
+ \expandafter\xdef
+ \expandafter\expandafter
+ \csname\the\macname xxx\endcsname
+ \paramlist{%
+ \egroup
+ \noexpand\norecurse{\the\macname}%
+ \noexpand\scanmacro{\temp}\egroup}%
+ \fi
+ \fi}
+
+\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}}
+
+% \braceorline decides whether the next nonwhitespace character is a
+% {. If so it reads up to the closing }, if not, it reads the whole
+% line. Whatever was read is then fed to the next control sequence
+% as an argument (by \parsebrace or \parsearg)
+\def\braceorline#1{\let\next=#1\futurelet\nchar\braceorlinexxx}
+\def\braceorlinexxx{%
+ \ifx\nchar\bgroup\else
+ \expandafter\parsearg
+ \fi \next}
+
+% We mant to disable all macros during \shipout so that they are not
+% expanded by \write.
+\def\turnoffmacros{\begingroup \def\do##1{\let\noexpand##1=\relax}%
+ \edef\next{\macrolist}\expandafter\endgroup\next}
+
+
+% @alias.
+\def\alias#1=#2{\gdef#1{#2}}
+
+
+\message{cross references,}
+\newwrite\auxfile
+
+\newif\ifhavexrefs % True if xref values are known.
+\newif\ifwarnedxrefs % True if we warned once that they aren't known.
+
+% @inforef is relatively simple.
+\def\inforef #1{\inforefzzz #1,,,,**}
+\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}},
+ node \samp{\ignorespaces#1{}}}
+
+% @node's job is to define \lastnode.
+\def\node{\ENVcheck\parsearg\nodezzz}
+\def\nodezzz#1{\nodexxx [#1,]}
+\def\nodexxx[#1,#2]{\gdef\lastnode{#1}}
+\let\nwnode=\node
+\let\lastnode=\relax
+
+% The sectioning commands (@chapter, etc.) call these.
+\def\donoderef{%
+ \ifx\lastnode\relax\else
+ \expandafter\expandafter\expandafter\setref{\lastnode}%
+ {Ysectionnumberandtype}%
+ \global\let\lastnode=\relax
+ \fi
+}
+\def\unnumbnoderef{%
+ \ifx\lastnode\relax\else
+ \expandafter\expandafter\expandafter\setref{\lastnode}{Ynothing}%
+ \global\let\lastnode=\relax
+ \fi
+}
+\def\appendixnoderef{%
+ \ifx\lastnode\relax\else
+ \expandafter\expandafter\expandafter\setref{\lastnode}%
+ {Yappendixletterandtype}%
+ \global\let\lastnode=\relax
+ \fi
+}
+
+
+% @anchor{NAME} -- define xref target at arbitrary point.
+%
+\def\anchor#1{\setref{#1}{Ynothing}}
+
+
+% \setref{NAME}{SNT} defines a cross-reference point NAME, namely
+% NAME-title, NAME-pg, and NAME-SNT. Called from \foonoderef. We have
+% to set \indexdummies so commands such as @code in a section title
+% aren't expanded. It would be nicer not to expand the titles in the
+% first place, but there's so many layers that that is hard to do.
+%
+\def\setref#1#2{{%
+ \indexdummies
+ \dosetq{#1-title}{Ytitle}%
+ \dosetq{#1-pg}{Ypagenumber}%
+ \dosetq{#1-snt}{#2}%
+}}
+
+% @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is
+% the node name, #2 the name of the Info cross-reference, #3 the printed
+% node name, #4 the name of the Info file, #5 the name of the printed
+% manual. All but the node name can be omitted.
+%
+\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]}
+\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]}
+\def\ref#1{\xrefX[#1,,,,,,,]}
+\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup
+ \def\printedmanual{\ignorespaces #5}%
+ \def\printednodename{\ignorespaces #3}%
+ \setbox1=\hbox{\printedmanual}%
+ \setbox0=\hbox{\printednodename}%
+ \ifdim \wd0 = 0pt
+ % No printed node name was explicitly given.
+ \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax
+ % Use the node name inside the square brackets.
+ \def\printednodename{\ignorespaces #1}%
+ \else
+ % Use the actual chapter/section title appear inside
+ % the square brackets. Use the real section title if we have it.
+ \ifdim \wd1 > 0pt
+ % It is in another manual, so we don't have it.
+ \def\printednodename{\ignorespaces #1}%
+ \else
+ \ifhavexrefs
+ % We know the real title if we have the xref values.
+ \def\printednodename{\refx{#1-title}{}}%
+ \else
+ % Otherwise just copy the Info node name.
+ \def\printednodename{\ignorespaces #1}%
+ \fi%
+ \fi
+ \fi
+ \fi
+ %
+ % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not
+ % insert empty discretionaries after hyphens, which means that it will
+ % not find a line break at a hyphen in a node names. Since some manuals
+ % are best written with fairly long node names, containing hyphens, this
+ % is a loss. Therefore, we give the text of the node name again, so it
+ % is as if TeX is seeing it for the first time.
+ \ifdim \wd1 > 0pt
+ \putwordsection{} ``\printednodename'' in \cite{\printedmanual}%
+ \else
+ % _ (for example) has to be the character _ for the purposes of the
+ % control sequence corresponding to the node, but it has to expand
+ % into the usual \leavevmode...\vrule stuff for purposes of
+ % printing. So we \turnoffactive for the \refx-snt, back on for the
+ % printing, back off for the \refx-pg.
+ {\normalturnoffactive
+ % Only output a following space if the -snt ref is nonempty; for
+ % @unnumbered and @anchor, it won't be.
+ \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}%
+ \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi
+ }%
+ % [mynode],
+ [\printednodename],\space
+ % page 3
+ \turnoffactive \putwordpage\tie\refx{#1-pg}{}%
+ \fi
+\endgroup}
+
+% \dosetq is the interface for calls from other macros
+
+% Use \normalturnoffactive so that punctuation chars such as underscore
+% and backslash work in node names. (\turnoffactive doesn't do \.)
+\def\dosetq#1#2{%
+ {\let\folio=0
+ \normalturnoffactive
+ \edef\next{\write\auxfile{\internalsetq{#1}{#2}}}%
+ \iflinks
+ \next
+ \fi
+ }%
+}
+
+% \internalsetq {foo}{page} expands into
+% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...}
+% When the aux file is read, ' is the escape character
+
+\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}}
+
+% Things to be expanded by \internalsetq
+
+\def\Ypagenumber{\folio}
+
+\def\Ytitle{\thissection}
+
+\def\Ynothing{}
+
+\def\Ysectionnumberandtype{%
+\ifnum\secno=0 \putwordChapter\xreftie\the\chapno %
+\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno %
+\else %
+\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\def\Yappendixletterandtype{%
+\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}%
+\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno %
+\else %
+\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\gdef\xreftie{'tie}
+
+% Use TeX 3.0's \inputlineno to get the line number, for better error
+% messages, but if we're using an old version of TeX, don't do anything.
+%
+\ifx\inputlineno\thisisundefined
+ \let\linenumber = \empty % Non-3.0.
+\else
+ \def\linenumber{\the\inputlineno:\space}
+\fi
+
+% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME.
+% If its value is nonempty, SUFFIX is output afterward.
+
+\def\refx#1#2{%
+ \expandafter\ifx\csname X#1\endcsname\relax
+ % If not defined, say something at least.
+ \angleleft un\-de\-fined\angleright
+ \iflinks
+ \ifhavexrefs
+ \message{\linenumber Undefined cross reference `#1'.}%
+ \else
+ \ifwarnedxrefs\else
+ \global\warnedxrefstrue
+ \message{Cross reference values unknown; you must run TeX again.}%
+ \fi
+ \fi
+ \fi
+ \else
+ % It's defined, so just use it.
+ \csname X#1\endcsname
+ \fi
+ #2% Output the suffix in any case.
+}
+
+% This is the macro invoked by entries in the aux file.
+%
+\def\xrdef#1{\begingroup
+ % Reenable \ as an escape while reading the second argument.
+ \catcode`\\ = 0
+ \afterassignment\endgroup
+ \expandafter\gdef\csname X#1\endcsname
+}
+
+% Read the last existing aux file, if any. No error if none exists.
+\def\readauxfile{\begingroup
+ \catcode`\^^@=\other
+ \catcode`\^^A=\other
+ \catcode`\^^B=\other
+ \catcode`\^^C=\other
+ \catcode`\^^D=\other
+ \catcode`\^^E=\other
+ \catcode`\^^F=\other
+ \catcode`\^^G=\other
+ \catcode`\^^H=\other
+ \catcode`\^^K=\other
+ \catcode`\^^L=\other
+ \catcode`\^^N=\other
+ \catcode`\^^P=\other
+ \catcode`\^^Q=\other
+ \catcode`\^^R=\other
+ \catcode`\^^S=\other
+ \catcode`\^^T=\other
+ \catcode`\^^U=\other
+ \catcode`\^^V=\other
+ \catcode`\^^W=\other
+ \catcode`\^^X=\other
+ \catcode`\^^Z=\other
+ \catcode`\^^[=\other
+ \catcode`\^^\=\other
+ \catcode`\^^]=\other
+ \catcode`\^^^=\other
+ \catcode`\^^_=\other
+ \catcode`\@=\other
+ \catcode`\^=\other
+ % It was suggested to define this as 7, which would allow ^^e4 etc.
+ % in xref tags, i.e., node names. But since ^^e4 notation isn't
+ % supported in the main text, it doesn't seem desirable. Furthermore,
+ % that is not enough: for node names that actually contain a ^
+ % character, we would end up writing a line like this: 'xrdef {'hat
+ % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first
+ % argument, and \hat is not an expandable control sequence. It could
+ % all be worked out, but why? Either we support ^^ or we don't.
+ %
+ % The other change necessary for this was to define \auxhat:
+ % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter
+ % and then to call \auxhat in \setq.
+ %
+ \catcode`\~=\other
+ \catcode`\[=\other
+ \catcode`\]=\other
+ \catcode`\"=\other
+ \catcode`\_=\other
+ \catcode`\|=\other
+ \catcode`\<=\other
+ \catcode`\>=\other
+ \catcode`\$=\other
+ \catcode`\#=\other
+ \catcode`\&=\other
+ \catcode`+=\other % avoid \+ for paranoia even though we've turned it off
+ % Make the characters 128-255 be printing characters
+ {%
+ \count 1=128
+ \def\loop{%
+ \catcode\count 1=\other
+ \advance\count 1 by 1
+ \ifnum \count 1<256 \loop \fi
+ }%
+ }%
+ % The aux file uses ' as the escape (for now).
+ % Turn off \ as an escape so we do not lose on
+ % entries which were dumped with control sequences in their names.
+ % For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^
+ % Reference to such entries still does not work the way one would wish,
+ % but at least they do not bomb out when the aux file is read in.
+ \catcode`\{=1
+ \catcode`\}=2
+ \catcode`\%=\other
+ \catcode`\'=0
+ \catcode`\\=\other
+ %
+ \openin 1 \jobname.aux
+ \ifeof 1 \else
+ \closein 1
+ \input \jobname.aux
+ \global\havexrefstrue
+ \global\warnedobstrue
+ \fi
+ % Open the new aux file. TeX will close it automatically at exit.
+ \openout\auxfile=\jobname.aux
+\endgroup}
+
+
+% Footnotes.
+
+\newcount \footnoteno
+
+% The trailing space in the following definition for supereject is
+% vital for proper filling; pages come out unaligned when you do a
+% pagealignmacro call if that space before the closing brace is
+% removed. (Generally, numeric constants should always be followed by a
+% space to prevent strange expansion errors.)
+\def\supereject{\par\penalty -20000\footnoteno =0 }
+
+% @footnotestyle is meaningful for info output only.
+\let\footnotestyle=\comment
+
+\let\ptexfootnote=\footnote
+
+{\catcode `\@=11
+%
+% Auto-number footnotes. Otherwise like plain.
+\gdef\footnote{%
+ \global\advance\footnoteno by \@ne
+ \edef\thisfootno{$^{\the\footnoteno}$}%
+ %
+ % In case the footnote comes at the end of a sentence, preserve the
+ % extra spacing after we do the footnote number.
+ \let\@sf\empty
+ \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi
+ %
+ % Remove inadvertent blank space before typesetting the footnote number.
+ \unskip
+ \thisfootno\@sf
+ \footnotezzz
+}%
+
+% Don't bother with the trickery in plain.tex to not require the
+% footnote text as a parameter. Our footnotes don't need to be so general.
+%
+% Oh yes, they do; otherwise, @ifset and anything else that uses
+% \parseargline fail inside footnotes because the tokens are fixed when
+% the footnote is read. --karl, 16nov96.
+%
+\long\gdef\footnotezzz{\insert\footins\bgroup
+ % We want to typeset this text as a normal paragraph, even if the
+ % footnote reference occurs in (for example) a display environment.
+ % So reset some parameters.
+ \interlinepenalty\interfootnotelinepenalty
+ \splittopskip\ht\strutbox % top baseline for broken footnotes
+ \splitmaxdepth\dp\strutbox
+ \floatingpenalty\@MM
+ \leftskip\z@skip
+ \rightskip\z@skip
+ \spaceskip\z@skip
+ \xspaceskip\z@skip
+ \parindent\defaultparindent
+ %
+ % Hang the footnote text off the number.
+ \hang
+ \textindent{\thisfootno}%
+ %
+ % Don't crash into the line above the footnote text. Since this
+ % expands into a box, it must come within the paragraph, lest it
+ % provide a place where TeX can split the footnote.
+ \footstrut
+ \futurelet\next\fo@t
+}
+\def\fo@t{\ifcat\bgroup\noexpand\next \let\next\f@@t
+ \else\let\next\f@t\fi \next}
+\def\f@@t{\bgroup\aftergroup\@foot\let\next}
+\def\f@t#1{#1\@foot}
+\def\@foot{\strut\egroup}
+
+}%end \catcode `\@=11
+
+% Set the baselineskip to #1, and the lineskip and strut size
+% correspondingly. There is no deep meaning behind these magic numbers
+% used as factors; they just match (closely enough) what Knuth defined.
+%
+\def\lineskipfactor{.08333}
+\def\strutheightpercent{.70833}
+\def\strutdepthpercent {.29167}
+%
+\def\setleading#1{%
+ \normalbaselineskip = #1\relax
+ \normallineskip = \lineskipfactor\normalbaselineskip
+ \normalbaselines
+ \setbox\strutbox =\hbox{%
+ \vrule width0pt height\strutheightpercent\baselineskip
+ depth \strutdepthpercent \baselineskip
+ }%
+}
+
+% @| inserts a changebar to the left of the current line. It should
+% surround any changed text. This approach does *not* work if the
+% change spans more than two lines of output. To handle that, we would
+% have adopt a much more difficult approach (putting marks into the main
+% vertical list for the beginning and end of each change).
+%
+\def\|{%
+ % \vadjust can only be used in horizontal mode.
+ \leavevmode
+ %
+ % Append this vertical mode material after the current line in the output.
+ \vadjust{%
+ % We want to insert a rule with the height and depth of the current
+ % leading; that is exactly what \strutbox is supposed to record.
+ \vskip-\baselineskip
+ %
+ % \vadjust-items are inserted at the left edge of the type. So
+ % the \llap here moves out into the left-hand margin.
+ \llap{%
+ %
+ % For a thicker or thinner bar, change the `1pt'.
+ \vrule height\baselineskip width1pt
+ %
+ % This is the space between the bar and the text.
+ \hskip 12pt
+ }%
+ }%
+}
+
+% For a final copy, take out the rectangles
+% that mark overfull boxes (in case you have decided
+% that the text looks ok even though it passes the margin).
+%
+\def\finalout{\overfullrule=0pt}
+
+% @image. We use the macros from epsf.tex to support this.
+% If epsf.tex is not installed and @image is used, we complain.
+%
+% Check for and read epsf.tex up front. If we read it only at @image
+% time, we might be inside a group, and then its definitions would get
+% undone and the next image would fail.
+\openin 1 = epsf.tex
+\ifeof 1 \else
+ \closein 1
+ % Do not bother showing banner with post-v2.7 epsf.tex (available in
+ % doc/epsf.tex until it shows up on ctan).
+ \def\epsfannounce{\toks0 = }%
+ \input epsf.tex
+\fi
+%
+\newif\ifwarnednoepsf
+\newhelp\noepsfhelp{epsf.tex must be installed for images to
+ work. It is also included in the Texinfo distribution, or you can get
+ it from ftp://tug.org/tex/epsf.tex.}
+%
+% Only complain once about lack of epsf.tex.
+\def\image#1{%
+ \ifx\pdfoutput\undefined
+ \ifx\epsfbox\undefined
+ \ifwarnednoepsf \else
+ \errhelp = \noepsfhelp
+ \errmessage{epsf.tex not found, images will be ignored}%
+ \global\warnednoepsftrue
+ \fi
+ \else
+ \imagexxx #1,,,\finish
+ \fi
+ \else
+ \centerline{\pdfimage #1.pdf}%
+ \fi
+}
+%
+% Arguments to @image:
+% #1 is (mandatory) image filename; we tack on .eps extension.
+% #2 is (optional) width, #3 is (optional) height.
+% #4 is just the usual extra ignored arg for parsing this stuff.
+\def\imagexxx#1,#2,#3,#4\finish{%
+ % \epsfbox itself resets \epsf?size at each figure.
+ \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi
+ \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi
+ % If the image is by itself, center it.
+ \ifvmode
+ \nobreak\medskip
+ \nobreak
+ \centerline{\epsfbox{#1.eps}}%
+ \bigbreak
+ \else
+ % In the middle of a paragraph, no extra space.
+ \epsfbox{#1.eps}%
+ \fi
+}
+
+
+\message{localization,}
+
+% @documentlanguage is usually given very early, just after
+% @setfilename. If done too late, it may not override everything
+% properly. Single argument is the language abbreviation.
+% It would be nice if we could set up a hyphenation file here.
+%
+\def\documentlanguage{\parsearg\dodocumentlanguage}
+\def\dodocumentlanguage#1{%
+ \tex % read txi-??.tex file in plain TeX.
+ % Read the file if it exists.
+ \openin 1 txi-#1.tex
+ \ifeof1
+ \errhelp = \nolanghelp
+ \errmessage{Cannot read language file txi-#1.tex}%
+ \let\temp = \relax
+ \else
+ \def\temp{\input txi-#1.tex }%
+ \fi
+ \temp
+ \endgroup
+}
+\newhelp\nolanghelp{The given language definition file cannot be found or
+is empty. Maybe you need to install it? In the current directory
+should work if nowhere else does.}
+
+
+% @documentencoding should change something in TeX eventually, most
+% likely, but for now just recognize it.
+\let\documentencoding = \comment
+
+
+% Page size parameters.
+%
+\newdimen\defaultparindent \defaultparindent = 15pt
+
+\chapheadingskip = 15pt plus 4pt minus 2pt
+\secheadingskip = 12pt plus 3pt minus 2pt
+\subsecheadingskip = 9pt plus 2pt minus 2pt
+
+% Prevent underfull vbox error messages.
+\vbadness = 10000
+
+% Don't be so finicky about underfull hboxes, either.
+\hbadness = 2000
+
+% Following George Bush, just get rid of widows and orphans.
+\widowpenalty=10000
+\clubpenalty=10000
+
+% Use TeX 3.0's \emergencystretch to help line breaking, but if we're
+% using an old version of TeX, don't do anything. We want the amount of
+% stretch added to depend on the line length, hence the dependence on
+% \hsize. We call this whenever the paper size is set.
+%
+\def\setemergencystretch{%
+ \ifx\emergencystretch\thisisundefined
+ % Allow us to assign to \emergencystretch anyway.
+ \def\emergencystretch{\dimen0}%
+ \else
+ \emergencystretch = \hsize
+ \divide\emergencystretch by 40
+ \fi
+}
+
+% Parameters in order: 1) textheight; 2) textwidth; 3) voffset;
+% 4) hoffset; 5) binding offset; 6) topskip. Then whoever calls us can
+% set \parskip and call \setleading for \baselineskip.
+%
+\def\internalpagesizes#1#2#3#4#5#6{%
+ \voffset = #3\relax
+ \topskip = #6\relax
+ \splittopskip = \topskip
+ %
+ \vsize = #1\relax
+ \advance\vsize by \topskip
+ \outervsize = \vsize
+ \advance\outervsize by 2\topandbottommargin
+ \pageheight = \vsize
+ %
+ \hsize = #2\relax
+ \outerhsize = \hsize
+ \advance\outerhsize by 0.5in
+ \pagewidth = \hsize
+ %
+ \normaloffset = #4\relax
+ \bindingoffset = #5\relax
+ %
+ \parindent = \defaultparindent
+ \setemergencystretch
+}
+
+% @letterpaper (the default).
+\def\letterpaper{{\globaldefs = 1
+ \parskip = 3pt plus 2pt minus 1pt
+ \setleading{13.2pt}%
+ %
+ % If page is nothing but text, make it come out even.
+ \internalpagesizes{46\baselineskip}{6in}{\voffset}{.25in}{\bindingoffset}{36pt}%
+}}
+
+% Use @smallbook to reset parameters for 7x9.5 (or so) format.
+\def\smallbook{{\globaldefs = 1
+ \parskip = 2pt plus 1pt
+ \setleading{12pt}%
+ %
+ \internalpagesizes{7.5in}{5.in}{\voffset}{.25in}{\bindingoffset}{16pt}%
+ %
+ \lispnarrowing = 0.3in
+ \tolerance = 700
+ \hfuzz = 1pt
+ \contentsrightmargin = 0pt
+ \deftypemargin = 0pt
+ \defbodyindent = .5cm
+ %
+ \let\smalldisplay = \smalldisplayx
+ \let\smallexample = \smalllispx
+ \let\smallformat = \smallformatx
+ \let\smalllisp = \smalllispx
+}}
+
+% Use @afourpaper to print on European A4 paper.
+\def\afourpaper{{\globaldefs = 1
+ \setleading{12pt}%
+ \parskip = 3pt plus 2pt minus 1pt
+ %
+ \internalpagesizes{53\baselineskip}{160mm}{\voffset}{4mm}{\bindingoffset}{44pt}%
+ %
+ \tolerance = 700
+ \hfuzz = 1pt
+}}
+
+% A specific text layout, 24x15cm overall, intended for A4 paper. Top margin
+% 29mm, hence bottom margin 28mm, nominal side margin 3cm.
+\def\afourlatex{{\globaldefs = 1
+ \setleading{13.6pt}%
+ %
+ \afourpaper
+ \internalpagesizes{237mm}{150mm}{3.6mm}{3.6mm}{3mm}{7mm}%
+ %
+ \globaldefs = 0
+}}
+
+% Use @afourwide to print on European A4 paper in wide format.
+\def\afourwide{%
+ \afourpaper
+ \internalpagesizes{9.5in}{6.5in}{\hoffset}{\normaloffset}{\bindingoffset}{7mm}%
+ %
+ \globaldefs = 0
+}
+
+% @pagesizes TEXTHEIGHT[,TEXTWIDTH]
+% Perhaps we should allow setting the margins, \topskip, \parskip,
+% and/or leading, also. Or perhaps we should compute them somehow.
+%
+\def\pagesizes{\parsearg\pagesizesxxx}
+\def\pagesizesxxx#1{\pagesizesyyy #1,,\finish}
+\def\pagesizesyyy#1,#2,#3\finish{{%
+ \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi
+ \globaldefs = 1
+ %
+ \parskip = 3pt plus 2pt minus 1pt
+ \setleading{13.2pt}%
+ %
+ \internalpagesizes{#1}{\hsize}{\voffset}{\normaloffset}{\bindingoffset}{44pt}%
+}}
+
+% Set default to letter.
+%
+\letterpaper
+
+\message{and turning on texinfo input format.}
+
+% Define macros to output various characters with catcode for normal text.
+\catcode`\"=\other
+\catcode`\~=\other
+\catcode`\^=\other
+\catcode`\_=\other
+\catcode`\|=\other
+\catcode`\<=\other
+\catcode`\>=\other
+\catcode`\+=\other
+\def\normaldoublequote{"}
+\def\normaltilde{~}
+\def\normalcaret{^}
+\def\normalunderscore{_}
+\def\normalverticalbar{|}
+\def\normalless{<}
+\def\normalgreater{>}
+\def\normalplus{+}
+
+% This macro is used to make a character print one way in ttfont
+% where it can probably just be output, and another way in other fonts,
+% where something hairier probably needs to be done.
+%
+% #1 is what to print if we are indeed using \tt; #2 is what to print
+% otherwise. Since all the Computer Modern typewriter fonts have zero
+% interword stretch (and shrink), and it is reasonable to expect all
+% typewriter fonts to have this, we can check that font parameter.
+%
+\def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi}
+
+% Turn off all special characters except @
+% (and those which the user can use as if they were ordinary).
+% Most of these we simply print from the \tt font, but for some, we can
+% use math or other variants that look better in normal text.
+
+\catcode`\"=\active
+\def\activedoublequote{{\tt\char34}}
+\let"=\activedoublequote
+\catcode`\~=\active
+\def~{{\tt\char126}}
+\chardef\hat=`\^
+\catcode`\^=\active
+\def^{{\tt \hat}}
+
+\catcode`\_=\active
+\def_{\ifusingtt\normalunderscore\_}
+% Subroutine for the previous macro.
+\def\_{\leavevmode \kern.06em \vbox{\hrule width.3em height.1ex}}
+
+\catcode`\|=\active
+\def|{{\tt\char124}}
+\chardef \less=`\<
+\catcode`\<=\active
+\def<{{\tt \less}}
+\chardef \gtr=`\>
+\catcode`\>=\active
+\def>{{\tt \gtr}}
+\catcode`\+=\active
+\def+{{\tt \char 43}}
+%\catcode 27=\active
+%\def^^[{$\diamondsuit$}
+
+% Set up an active definition for =, but don't enable it most of the time.
+{\catcode`\==\active
+\global\def={{\tt \char 61}}}
+
+\catcode`+=\active
+\catcode`\_=\active
+
+% If a .fmt file is being used, characters that might appear in a file
+% name cannot be active until we have parsed the command line.
+% So turn them off again, and have \everyjob (or @setfilename) turn them on.
+% \otherifyactive is called near the end of this file.
+\def\otherifyactive{\catcode`+=\other \catcode`\_=\other}
+
+\catcode`\@=0
+
+% \rawbackslashxx output one backslash character in current font
+\global\chardef\rawbackslashxx=`\\
+%{\catcode`\\=\other
+%@gdef@rawbackslashxx{\}}
+
+% \rawbackslash redefines \ as input to do \rawbackslashxx.
+{\catcode`\\=\active
+@gdef@rawbackslash{@let\=@rawbackslashxx }}
+
+% \normalbackslash outputs one backslash in fixed width font.
+\def\normalbackslash{{\tt\rawbackslashxx}}
+
+% Say @foo, not \foo, in error messages.
+\escapechar=`\@
+
+% \catcode 17=0 % Define control-q
+\catcode`\\=\active
+
+% Used sometimes to turn off (effectively) the active characters
+% even after parsing them.
+@def@turnoffactive{@let"=@normaldoublequote
+@let\=@realbackslash
+@let~=@normaltilde
+@let^=@normalcaret
+@let_=@normalunderscore
+@let|=@normalverticalbar
+@let<=@normalless
+@let>=@normalgreater
+@let+=@normalplus}
+
+@def@normalturnoffactive{@let"=@normaldoublequote
+@let\=@normalbackslash
+@let~=@normaltilde
+@let^=@normalcaret
+@let_=@normalunderscore
+@let|=@normalverticalbar
+@let<=@normalless
+@let>=@normalgreater
+@let+=@normalplus}
+
+% Make _ and + \other characters, temporarily.
+% This is canceled by @fixbackslash.
+@otherifyactive
+
+% If a .fmt file is being used, we don't want the `\input texinfo' to show up.
+% That is what \eatinput is for; after that, the `\' should revert to printing
+% a backslash.
+%
+@gdef@eatinput input texinfo{@fixbackslash}
+@global@let\ = @eatinput
+
+% On the other hand, perhaps the file did not have a `\input texinfo'. Then
+% the first `\{ in the file would cause an error. This macro tries to fix
+% that, assuming it is called before the first `\' could plausibly occur.
+% Also back turn on active characters that might appear in the input
+% file name, in case not using a pre-dumped format.
+%
+@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi
+ @catcode`+=@active @catcode`@_=@active}
+
+% These look ok in all fonts, so just make them not special. The @rm below
+% makes sure that the current font starts out as the newly loaded cmr10
+@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other
+
+@textfonts
+@rm
+
+@c Local variables:
+@c eval: (add-hook 'write-file-hooks 'time-stamp)
+@c page-delimiter: "^\\\\message"
+@c time-stamp-start: "def\\\\texinfoversion{"
+@c time-stamp-format: "%:y-%02m-%02d.%H"
+@c time-stamp-end: "}"
+@c End:
diff --git a/doc/vtysh.1 b/doc/vtysh.1
new file mode 100644
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 <bug-zebra@gnu.org>
+
+
+.SH AUTHOR[S]
+See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors.
+
diff --git a/doc/vtysh.texi b/doc/vtysh.texi
new file mode 100644
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 <bug-zebra@gnu.org>
+
+
+.SH AUTHOR[S]
+See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors.
+
diff --git a/doc/zebra.info b/doc/zebra.info
new file mode 100644
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 <kunihiro@zebra.org>
+
+ * zebra-0.89 is released.
+
+2000-08-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.88 is released.
+
+1999-04-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * guile-bgp.c (scm_router_bgp): Allocate real struct bgp object.
+
+ * Makefile.am: Delete -DPACKAGE and -DVERSION.
+
+ * zebra-guile.h: File added.
+ * zebra-support.c: File added.
+ * guile-bgp.c: File added.
+
+1999-04-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * guile/Makefile.am (INCLUDES): Use @GUILE_CFLAGS@ and
+ @GUILE_LDFLAGS@
+
+1999-04-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-guile work restarted.
diff --git a/guile/Makefile.am b/guile/Makefile.am
new file mode 100644
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 <zebra.h>
+#include <guile/gh.h>
+
+#include "log.h"
+#include "bgpd/bgpd.h"
+
+/* static SCM scm_mark_bgp (SCM obj); */
+static size_t scm_free_bgp (SCM vect);
+static int scm_print_bgp (SCM vect, SCM port, scm_print_state *pstate);
+static SCM scm_equalp_bgp (SCM a, SCM b);
+
+/* Tag of scheme type of bgp. */
+long scm_tag_bgp;
+
+static scm_smobfuns bgp_funs =
+{
+ scm_mark0, scm_free_bgp, scm_print_bgp, scm_equalp_bgp
+};
+
+static int
+scm_print_bgp (SCM vect, SCM port, scm_print_state *pstate)
+{
+ unsigned short num;
+ struct bgp *bgp;
+
+ num = 0;
+ bgp = (struct bgp *) SCM_CDR (vect);
+ num = bgp->as;
+ scm_puts ("#<bgp ", port);
+ scm_intprint (num, 10, port);
+ scm_putc ('>', port);
+ return 1;
+}
+
+static size_t
+scm_free_bgp (SCM obj)
+{
+ /* dummy function. */
+ return 10;
+}
+
+static SCM
+scm_equalp_bgp (SCM a, SCM b)
+{
+
+ return SCM_BOOL_F;
+}
+
+/* Make bgp instance. */
+SCM
+scm_router_bgp (SCM as_number)
+{
+ SCM cell;
+ long num;
+ struct bgp *bgp;
+ struct bgp *bgp_create ();
+
+ SCM_ASSERT (SCM_INUMP (as_number), as_number, SCM_ARG1, "router-bgp");
+
+ SCM_DEFER_INTS;
+
+ num = gh_scm2long (as_number);
+
+ /* Make new bgp object. */
+ bgp = bgp_create ();
+ bgp->as = num;
+
+ SCM_NEWCELL (cell);
+ SCM_SETCAR (cell, scm_tag_bgp);
+ SCM_SETCDR (cell, bgp);
+
+ SCM_ALLOW_INTS;
+
+ return cell;
+}
+
+#if 0
+SCM
+scm_router_bgp_list ()
+{
+ return NULL;
+}
+#endif
+
+void
+init_bgp ()
+{
+ void bgp_init ();
+
+ bgp_init ();
+
+ /* Initi types. */
+ scm_tag_bgp = scm_newsmob (&bgp_funs);
+
+ gh_new_procedure ("router-bgp", scm_router_bgp, 1, 0, 0);
+ /* gh_new_procedure ("router-bgp-list", scm_router_bgp_list, 0, 0, 0); */
+}
diff --git a/guile/zebra-guile.c b/guile/zebra-guile.c
new file mode 100644
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 <libguile.h>
+#include "zebra-guile.h"
+
+#include "zebra.h"
+#include "thread.h"
+
+struct thread *master;
+
+static void
+init_libzebra ()
+{
+ void cmd_init();
+ void vty_init();
+ void memory_init();
+
+ cmd_init (1);
+ vty_init ();
+ memory_init ();
+}
+
+/* Install scheme procudures. */
+void
+init_zebra_guile ()
+{
+ init_libzebra ();
+
+ init_bgp ();
+
+#if 0
+ init_zebra ();
+ init_rip ();
+ init_ospf ();
+#endif /* 0 */
+}
+
+static void
+inner_main (void *closure, int argc, char **argv)
+{
+ /* Install zebra related scheme procedures. */
+ init_zebra_guile ();
+
+ /* Invoke interpreter. */
+ scm_shell (argc, argv);
+}
+
+int
+main (int argc, char **argv)
+{
+ scm_boot_guile (argc, argv, inner_main, 0);
+ return 0; /* Not reached */
+}
diff --git a/guile/zebra-guile.h b/guile/zebra-guile.h
new file mode 100644
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 <kunihiro@ipinfusion.com>
+
+ * zebra-0.92a released
+
+2001-08-15 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92 released.
+
+2001-02-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.91 is released.
+
+2001-01-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.90 is released.
+
+2000-11-06 Lennert Buytenhek <buytenh@gnu.org>
+
+ * redhat/zebra.spec.in: Don't include ospf6d and ripngd in
+ package.
+
+ * redhat/zebra.logrotate: Fix logrotate file (add ospf.log).
+
+2000-10-02 Horms <horms@vergenet.net>
+
+ * redhat/zebra.spec.in: Moved chkconfig --del operations from
+ %postun to %preun, as chkconfig needs to run while the init files
+ are still present on the system.
+
+ * redhat/zebra.logrotate: New file is added.
+
+2000-09-18 Lennert Buytenhek <buytenh@gnu.org>
+
+ * redhat/zebra.spec.in: New file is added.
+ redhat/ripd.init: Likewise.
+ redhat/ripngd.init: Likewise.
+ redhat/ospfd.init: Likewise.
+ redhat/ospf6d.init: Likewise.
+ redhat/bgpd.init: Likewise.
diff --git a/init/redhat/bgpd.init b/init/redhat/bgpd.init
new file mode 100644
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 <sercice name> <port/proto> <comment>
+# e.g. zebra_spec_add_service zebrasrv 2600/tcp "zebra service"
+
+zebra_spec_add_service ()
+{
+ # Add port /etc/services entry if it isn't already there
+ if [ -f /etc/services ] && ! grep -q "^$1[^a-zA-Z0-9]" /etc/services ; then
+ echo "$1 $2 # $3" >> /etc/services
+ fi
+}
+
+zebra_spec_add_service zebrasrv 2600/tcp "zebra service"
+zebra_spec_add_service zebra 2601/tcp "zebra vty"
+zebra_spec_add_service ripd 2602/tcp "RIPd vty"
+zebra_spec_add_service ripngd 2603/tcp "RIPngd vty"
+zebra_spec_add_service ospfd 2604/tcp "OSPFd vty"
+zebra_spec_add_service bgpd 2605/tcp "BGPd vty"
+zebra_spec_add_service ospf6d 2606/tcp "OSPF6d vty"
+
+#Install info
+/sbin/install-info /usr/info/zebra.info /usr/info/dir
+
+if [ -x /sbin/chkconfig ]; then
+ chkconfig --add bgpd
+# chkconfig --add ospf6d
+ chkconfig --add ospfd
+ chkconfig --add ripd
+# chkconfig --add ripngd
+ chkconfig --add zebra
+fi
+
+
+%preun
+if [ "$1" = 0 ] ; then
+ /sbin/install-info --delete /usr/info/zebra.info /usr/info/dir
+
+ if [ -x /sbin/chkconfig ]; then
+ chkconfig --del bgpd
+# chkconfig --del ospf6d
+ chkconfig --del ospfd
+ chkconfig --del ripd
+# chkconfig --del ripngd
+ chkconfig --del zebra
+ fi
+fi
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+rm -rf $RPM_BUILD_DIR/%{name}-%{version}
+
+%files
+%attr(-,root,root) %doc AUTHORS COPYING ChangeLog INSTALL NEWS README SERVICES TODO bgpd/bgpd.conf.sample ospfd/ospfd.conf.sample ripd/ripd.conf.sample zebra/zebra.conf.sample
+%attr(-,root,root) %config /etc/rc.d/init.d/*
+%attr(-,root,root) %config /etc/logrotate.d/*
+%attr(-,root,root) /usr/info/*
+#%attr(-,root,root) /usr/man/* # Not man1 to exclude vtysh man page as
+ # it is not build by default (for now)
+%attr(-,root,root) /usr/man/man8/*
+%attr(-,root,root) /usr/sbin/*
+
+%changelog
+* Mon Nov 6 2000 Lennert Buytenhek <buytenh@gnu.org>
+- Don't include ospf6d and ripngd in package.
+- Fix logrotate file (add ospf.log).
+* Mon Oct 2 2000 Horms <horms@valinux.com>
+- Install and uninstall info in %post and %preun respectively
+- Moved chkconfig --del operations from %postun to %preun, as
+ chkconfig needs to run while the init files are still present on
+ the system.
+- Don't install vtysh man page as vtysh is not build by default
+- Added logrotate script so logs won't grow without bound
+* Wed Sep 27 2000 Horms <horms@vergenet.net>
+- Add ports to /etc/services if they aren't there
+- forcibly remove $RPM_BUILD_ROOT/usr/info/dir and friends so
+ there is no error if it does not exist when rm is run.
+- Clean up the zebra build dir
diff --git a/install-sh b/install-sh
new file mode 100755
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 <yasu@sfc.wide.ad.jp>
+
+ * vty.c (vty_flush): One line more on vty.
+
+2002-09-27 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * vector.c (vector_lookup): Add new function.
+
+2002-08-19 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * thread.c (timeval_adjust): Fix unconditional crush due to
+ FreeBSD's select() system call timeval value check.
+
+2002-07-07 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.93 released.
+
+2002-06-21 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * if.c (ifc_pointopoint): Add ifc_pointopoint() accoding to Frank
+ van Maarseveen's suggestion.
+
+2002-06-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c: Change bcopy() to memcpy().
+
+2001-12-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (config_password): Fix host.password clear bug.
+ Reported by Wang Jian <lark@linux.net.cn>.
+
+2001-08-29 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * thread.c (thread_should_yield): New function to check thread
+ should yeild it's execution to other thread. Suggested by: Rick
+ Payne <rickp@ayrnetworks.com>
+
+2001-08-20 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * thread.c (thread_timer_cmp): Rewrite function.
+
+ * hash.c: Add hash_get(). Change hash_pull() to hash_release().
+
+2001-08-19 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92a released.
+
+2001-08-15 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92 released.
+
+2001-08-12 Akihiro Mizutani <mizutani@dml.com>
+
+ * prefix.c (netmask_str2prefix_str): Convert "1.1.0.0 255.255.0.0"
+ string to "1.1.0.0/16".
+
+2001-08-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * filter.c (access_list_lookup): access_list_lookup's first
+ argument is changed from address family to AFI.
+
+ * plist.c: (prefix_list_lookup): Likewise.
+
+2001-07-27 Akihiro Mizutani <mizutani@dml.com>
+
+ * plist.c: ge and le display order is changed. Old compatible
+ rule (len <= ge-value <= le-value) is removed.
+
+2001-07-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * prefix.h: Temporary fix for alignment of prefix problem.
+
+2001-06-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * prefix.h (struct prefix): Remove safi and padding field.
+ (struct prefix_ipv4): Likewise.
+ (struct prefix_ipv6): Likewise.
+ (struct prefix_ls): Likewise.
+ (struct prefix_rd): Likewise.
+
+ * command.h (enum node_type): Preparation for BGP new config.
+
+ * vty.c (vty_end_config): Likewise.
+
+2001-06-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * routemap.c (route_map_rule_delete): Call func_free when
+ route-map rule is deleted.
+
+2001-06-14 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * routemap.c (route_map_index_lookup): Prevent to use deny and
+ permit for same route-map sequence.
+
+2001-04-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_read_config): Fix warning.
+
+2001-03-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (IPV6_PREFIX_STR): Add '.' and '%' for IPv6 address
+ strings.
+
+2001-03-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra.h (_XPG4_2): Define _XPG4_2 and __EXTENSIONS__ for
+ CMSG_FIRSTHDR.
+
+2001-03-07 Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+ * zebra.h (struct in_pktinfo): structure in_pktinfo declaration.
+
+2001-02-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * memory.c (memory_list_lib): Add MTYPE_NEXTHOP for "show memory
+ lib" member.
+
+2001-02-13 Matthew Grant <grantma@anathoth.gen.nz>
+
+ * vty.c (vty_read_config): Revert check of integrate_default when
+ VTYSH is defined.
+
+2001-02-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_read_config): Do not check integrate_default. That
+ should be used only by vtysh.
+
+2001-02-08 Matthew Grant <grantma@anathoth.gen.nz>
+
+ * vty.c (vty_serv_un): Set umask 0077.
+ (vty_read_config): Stat for vtysh Zebra.conf, if found startup and
+ wait for boot configuration.
+
+ * if.c (if_lookup_address): Make it smart implementation.
+
+ * sockopt.c (setsockopt_multicast_ipv4): Set up a multicast socket
+ options for IPv4 This is here so that people only have to do their
+ OS multicast mess in one place rather than all through zebra,
+ ospfd, and ripd .
+
+2001-02-04 Akihiro Mizutani <mizutani@dml.com>
+
+ * plist.c (vty_prefix_list_install): Even when argument is
+ invalid, new memory is allocated. Now memory allocation is done
+ after argument check.
+
+2001-02-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.91 is released.
+
+2001-01-31 Akihiro Mizutani <mizutani@dml.com>
+
+ * vty.c (vty_login): Add vty login command.
+
+2001-01-31 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_reset): Close accept socket.
+
+2001-01-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * memory.h (enum): MTYPE_ATTR_TRANSIT is added for unknown transit
+ attribute.
+
+2001-01-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zclient.c (zebra_interface_address_add_read): Fetch interface
+ address flag.
+ (zebra_interface_address_delete_read): Likewise.
+
+2001-01-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * table.c (route_node_match_ipv4): Utility function for IPv4
+ address lookup.
+ (route_node_match_ipv6): Utility function for IPv4 address lookup.
+
+2001-01-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if.c: Delete RIP_API part until new implementation comes out.
+
+2001-01-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * hash.h (struct Hash): Rename alloc to count. Change type to
+ unsigned long.
+
+ * stream.c (stream_getc_from): New function.
+ (stream_getw_from): Likewise.
+
+ * zebra.h (ZEBRA_FLAG_STATIC): Add new flag for persistent route.
+
+2001-01-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * flap.c: File is removed.
+
+ * flap.c: Likewise.
+
+ * roken.h: Likewise.
+
+ * buffer.c (buffer_new): Remove type option to buffer_new().
+
+2001-01-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zclient.c (zapi_ipv4_delete): Remove OLD_RIB part.
+
+2001-01-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.90 is released.
+
+ * command.c: Update Copyright year.
+
+2001-01-09 Matthew Grant <grantma@anathoth.gen.nz>
+
+ * if.c (if_create): Register connected_free() function for
+ deletion.
+ (if_delete): Free connected information when the interface is
+ deleted.
+ (if_lookup_by_index): Fix argument type from int to unsigned int.
+ (connected_add): Keep list in order if old info found, essential
+ for repeatable operation in some daemons.
+
+2001-01-09 endo@suri.co.jp (Masahiko Endo)
+
+ * vty.c (vty_flush): When vty->statis is VTY_CLOSE do not add vty
+ read thread.
+
+2001-01-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * filter.c (access_list_delete): Access-list name is not freed.
+
+ * plist.c (prefix_list_delete): Prefix-list name is not freed.
+
+2000-12-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zclient.c (zclient_start): Change to use UNIX domain
+ socket for zebra communication.
+
+ * vector.c (vector_init): vector_alloc and vector_data_alloc is
+ removed. All memory allocation count should be maintained by
+ XMALLOC and XFREE macros.
+
+2000-12-28 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra.h (ZEBRA_NEXTHOP_IFINDEX): Define ZEBRA_NEXTHOP_* values.
+
+2000-12-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra.h (ZEBRA_ERR_RTEXIST): Make zebra error code to negative
+ value.
+
+2000-12-25 "Wataru Uno" <wataru@po.ntts.co.jp>
+
+ * vty.c (vtysh_read): Don't allocate new buffer because buffer is
+ allocated in vty_new ().
+
+2000-12-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * memory.h (enum): Add MTYPE_AS_FILTER_STR.
+
+ * command.c (config_write_terminal): Display "end" at the end of
+ configuration.
+
+ * plist.c (vty_prefix_list_install): Use AF_INET to determine
+ lenum length.
+
+2000-12-13 "Wataru Uno" <wataru@po.ntts.co.jp>
+
+ * buffer.c (buffer_flush_vty): If IOV_MAX defined in the System,
+ then all lines write by IOV_MAX.
+
+2000-12-12 Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+ * command.c (config_write_file): Robust method for writing
+ configuration file and recover from backing up config file.
+
+2000-11-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * smux.c (smux_connect): More fail check.
+ (smux_trap): When SMUX connection is not established, do nothing.
+
+2000-11-28 Gleb Natapov <gleb@nbase.co.il>
+
+ * thread.c (thread_fetch): Execut event list first. Old event
+ list is renamed to ready list. With this change, event thread is
+ executed before any other thread.
+
+ * thread.h (struct thread_master): Add ready list.
+
+2000-11-28 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * linklist.c (listnode_add_after): Add node right after the
+ listnode pointer.
+
+2000-11-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * smux.h: Pass struct variable to WriteMethod.
+
+2000-11-25 Frank van Maarseveen <F.vanMaarseveen@inter.NL.net>
+
+ * if.c (if_lookup_address): When looking up interface with IP
+ address, Sometimes multiple interfaces will match. Now PtP
+ interfaces prevail in such a case which seem the right thing to
+ do: There will probably also be host routes which usually prevail
+ over network routes.
+
+2000-11-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * smux.c (smux_trap): SMUX trap implementation.
+
+2000-11-19 Akihiro Mizutani <mizutani@dml.com>
+
+ * plist.c: Add automatic conversion function of an old rule.
+ ex.) 10.0.0.0/8 ge 8 -> 10.0.0.0/8 le 32
+
+2000-11-16 Yon Uriarte <ukl2@rz.uni-karlsruhe.de>
+
+ * zclient.c (zebra_interface_add_read): Read hardware address when
+ hw_addr_len is greater than 0.
+
+2000-11-15 Akihiro Mizutani <mizutani@dml.com>
+
+ * plist.c: The rule of "len <= ge-value <= le-value"
+ was changed to "len < ge-value <= le-value".
+
+2000-11-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * memory.[ch]: Added #define and functions for ospf6d.
+
+ * log.[ch]: some platform says that the data of used va_list
+ is undefined. Changed to hold list of va_list for each
+ vsnprintf.
+
+2000-11-07 Rick Payne <rickp@rossfell.co.uk>
+
+ * memory.h (enum): Add MTYPE_COMMUNITY_REGEXP.
+
+2000-11-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (config_exit): Fix bug of missing break after case
+ BGP_VPNV4_NODE.
+
+2000-10-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vector.c (vector_unset): Check i is not nevative.
+
+2000-10-24 Arkadiusz Miskiewicz <misiek@pld.org.pl>
+
+ * smux.c (smux_sock): Set terminating '\0'. Check address family.
+
+ * vty.c (vty_serv_sock_addrinfo): Set terminating '\0'. Use
+ gai_strerror. Check address family.
+
+2000-10-23 Jochen Friedrich <jochen@scram.de>
+
+ * smux.c: Use linklist rather than vector.
+ (smux_getnext): A SMUX subagent has to behave as if it manages the
+ whole SNMP MIB tree itself. It's the duty of the master agent to
+ collect the best answer and return it to the manager. See RFC 1227
+ chapter 3.1.6 for the glory details :-). ucd-snmp really behaves
+ bad here as it actually might ask multiple times for the same
+ GETNEXT request as it throws away the answer when it expects it in
+ a different subtree and might come back later with the very same
+ request.
+
+2000-10-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (cmd_init): Log related command are only installed for
+ terminal mode.
+
+2000-10-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am (libzebra_a_SOURCES): Remove duplicated buffer.c.
+
+ * zebra.h: Remove #warn directive.
+
+2000-10-20 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * keychain.c (keychain_init): Register "key chain" command to
+ KEYCHAIN_NODE and KEYCHAIN_KEY_NODE.
+
+ * vty.c (vty_end_config): Fix missing vty_cinfig_unlock for other
+ CONFIG_NODE.
+
+ * command.c (config_end): Likewise.
+
+ * keychain.c (keychain_get): Key is sorted by it's identifier
+ value.
+
+2000-10-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * linklist.c (list_delete_all_node): Call delete function if it is
+ defined.
+
+ * command.c (cmd_execute_command_strict): Add modification for
+ vtysh.
+ (cmd_execute_command_strict): Remove first argument cmdvec because
+ it is global varibale in command.c.
+
+2000-10-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (cmd_init): Install
+ copy_runningconfig_startupconfig_cmd only in terminal mode.
+
+ * linklist.c (list_delete_node): Simplify the function.
+ (listnode_lookup): Renamed from list_lookup_node.
+
+2000-10-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * stream.h: Undef stream_read and stream_write without
+ parenthesis.
+
+ * newlist.c: File removed.
+
+ * newlist.h: Likewise.
+
+ * linklist.c (list_new): Remove list_init(). To allocate new
+ linked list, please use list_new().
+ (listnode_add): Remove list_add_node(). To add new node to linked
+ list, please use listnode_add().
+ (list_delete_by_val): Revemove fucntion.
+
+2000-10-16 Nobuaki Tanaka <nobby@po.ntts.co.jp>
+
+ * table.c (route_table_free): Reimplement route_table_free().
+
+2000-10-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * keychain.c (keychain_get): Register key_delete_func to key
+ list's delete function. Use linklist.c instead of newlist.c.
+
+2000-10-04 Akihiro Mizutani <mizutani@dml.com>
+
+ * filter.c (access_list_remark): Add access-list's remark command.
+ (no_access_list): "no access-list 100 permit any" error message
+ bug is fixed.
+
+2000-10-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * memory.h (enum): Add MTYPE_SOCKUNION.
+
+2000-10-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.89 is released.
+
+2000-10-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * linklist.c (list_add_node_head): Delete unused function.
+ (list_add_node_tail): Likewise.
+
+2000-09-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * stream.c (stream_read_unblock): Add new function for unblocking
+ read.
+
+2000-09-26 Jochen Friedrich <jochen@nwe.de>
+
+ * smux.c (smux_register): Fix bug of can't register more than one
+ MIB with SMUX.
+
+2000-09-26 Makoto Otsuka <otsuka@inl.ntts.co.jp>
+
+ * vty.c (vty_close): Fix memory leak of sb_buffer.
+ (vty_new): Likewise.
+
+2000-09-21 steve@Watt.COM (Steve Watt)
+
+ * log.h: Do not declare zlog_priority[0] variable.
+
+2000-09-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * linklist.h (struct _list ): Add member cmp for compare function.
+ (struct _list ): Member up is deleted
+
+2000-09-12 David Lipovkov <dlipovkov@OpticalAccess.com>
+
+ * if.c: Include RIP_API header when RIP API is enabled.
+
+2000-09-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * prefix.c (prefix_free): Siplify prefix_free().
+
+ * keychain.c (key_match_for_accept): strncmp check bug is fixed.
+
+2000-09-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra.h: Merge roken.h into zebra.h.
+
+2000-09-05 Akihiro Mizutani <mizutani@dml.com>
+
+ * routemap.c (route_map_init_vty): Install route-map command to
+ RMAP_NODE.
+
+2000-08-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * thread.c (thread_get_id): Remove pthread related garbage.
+
+ * command.h (struct host): Likewise.
+
+ * zebra.h: Likewise.
+
+2000-08-20 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.h (node_type ): Add AAA node for authentication.
+
+ * vty.c (vty_close): Do not close stdout.
+
+2000-08-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_init_vtysh): Added for vtysh.
+
+ * distribute.c (districute_list_prefix_all): Interface independent
+ filter can be set.
+ (distribute_list_all): Likewise.
+ (config_show_distribute): Display current distribute-list status
+ for "show ip protocols".
+
+2000-08-18 Akihiro Mizutani <mizutani@dml.com>
+
+ * command.c (config_terminal_no_length): no terminal monitor ->
+ terminal no monitor
+ (cmd_init): Do not install service_terminal_length_cmd into
+ ENABLE_NODE.
+
+ * vty.c (terminal_no_monitor): no terminal length -> terminal no
+ length.
+
+2000-08-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.88 is released.
+
+2000-08-17 Magnus Ahltorp <ahltorp@nada.kth.se>
+
+ * vty.h (struct vty ): Add iac_sb_in_progress and sb_buffer for
+ better IAC handling.
+
+ * vty.c (vty_telnet_option): Change telnet option handling.
+
+2000-08-15 Gleb Natapov <gleb@nbase.co.il>
+
+ * zclient.c (zclient_redistribute_unset): New function added.
+
+2000-08-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zclient.c (zebra_interface_add_read): Change ifindex restore
+ size from two octet to four.
+ (zebra_interface_state_read): Likewise.
+ (zebra_interface_address_add_read): Likewise.
+
+2000-08-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_event): Use vector_set_index() instead of
+ vector_set().
+
+2000-08-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra.h (ZEBRA_XXX_DISTANCE_DEFAULT): Define Default
+ Administrative Distance of each protocol.
+
+2000-08-07 Matthew Grant <grantma@anathoth.gen.nz>
+
+ * if.h (struct interface ): Add new member bandwidth to struct
+ interface.
+
+ * zclient.c (zebra_interface_add_read): Fetch bandwidth value.
+ (zebra_interface_state_read): Likewise.
+
+2000-08-07 Gleb Natapov <gleb@nbase.co.il>
+
+ * routemap.c (route_map_event_hook): New hook route_map_event_hook
+ is added. This hook is called when route-map is changed. The
+ parameters passed to the hook are 'event' and 'route-map name'
+
+ * routemap.h: Add prototype for route_map_event_hook().
+
+2000-08-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zclient.c (zebra_ipv4_route): zebra_ipv4_route(),
+ zebra_ipv4_add(), zebra_ipv4_delete() are removed.
+
+ * routemap.c (route_map_empty): Add new function.
+ (route_map_delete): Use route_map_index_delete() instead of
+ route_map_index_free().
+ (route_map_index_free): Function removed.
+
+2000-08-06 Gleb Natapov <gleb@nbase.co.il>
+
+ * routemap.c (route_map_index_delete): Add check for route-map is
+ empty or not.
+
+2000-08-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zclient.c (zebra_ipv4_add): Change socket arguemnt with struct
+ zclient.
+
+2000-08-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zclient.h (struct zebra): Add obuf for output buffer.
+
+ * if.c: Remove #ifdef NRL enclosing if_nametoindex() and
+ if_indextoname().
+
+2000-08-02 David Lipovkov <davidl@nbase.co.il>
+
+ * if.h (IF_PSEUDO_UNSET): IF_PSEUDO related macro added.
+ (IF_UNKNOWN_SET): IF_UNKNOWN related macro deleted.
+
+ * if.c (interface_pseudo): Add "pseudo" command to interface node.
+ (no_interface_pseudo): Add "no pseudo" command to interface node.
+
+ * zclient.c (zebra_interface_add_read): Set pseudo flag when it is
+ send from zebra.
+
+2000-08-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra.h (ZEBRA_IPV4_NEXTHOP_LOOKUP): Add new message.
+ (ZEBRA_IPV6_NEXTHOP_LOOKUP): Likewise.
+
+ * vty.c (vty_serv_un): Use AF_UNIX for backward compatibility.
+
+2000-07-31 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c: Use vector for VTY server thread listing instead of
+ single value.
+
+2000-07-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * keychain.c (no_key_chain): "no key chain WORD" command is added.
+
+2000-07-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (config_from_file): If command fail in
+ KEYCHAIN_KEY_NODE, down to KEYCHAIN_NODE.
+
+ * vty.h (struct vty ): Add index_sub member.
+
+2000-07-27 Akihiro Mizutani <mizutani@dml.com>
+
+ * if.c: Help strings updates.
+
+2000-07-11 Akihiro Mizutani <mizutani@dml.com>
+
+ * command.c (no_config_enable_password): Add "no enable password"
+ command.
+ (config_write_host): Display password string.
+
+ * routemap.c (route_map_delete_match): Add support for delete
+ match without argument.
+ (route_map_delete_set): Likewise.
+
+2000-07-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.h (node_type ): Change KEYCHAIN_NODE and
+ KEYCHAIN_KEY_NODE place just before INTERFACE_NODE.
+
+2000-07-09 Jochen Friedrich <jochen@scram.de>
+
+ * smux.c (config_write_smux): Fixes the option to override OID and
+ password for SMUX.
+
+2000-07-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.h (node_type ): Add SMUX_NODE for SMUX configuration.
+
+2000-07-09 Toshiaki Takada <takada@zebra.org>
+
+ * command.c: Sort descvec command's help.
+
+ * vty.c (vty_describe_command): Display '<cr>' at the end of
+ descriptions.
+
+2000-07-05 Toshiaki Takada <takada@zebra.org>
+
+ * command.c (cmd_ipv6_match), (cmd_ipv6_prefix_match): Fix bug
+ treatment of double colon.
+
+2000-07-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zclient.h: Add zclient_redistribute_default_{set,unset}().
+
+ * keychain.c: New file for authentication key management.
+ * keychain.h: Likewise.
+
+ * tcpfilter.c: New file for TCP/UDP base filtering using ipfw or
+ ipchains.
+ * tcpfilter.h: Likewise.
+
+ * flap.h: New file for route flap dampening.
+ * flap.c: Likewise.
+
+2000-07-04 Toshiaki Takada <takada@zebra.org>
+
+ * filter.c (struct filter): Add exact flag.
+ (access_list): Add exact-match command.
+ (ipv6_access_list): Add exact-match command.
+
+2000-07-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra.h (ZEBRA_REDISTRIBUTE_DEFAULT_ADD): New message for
+ request default route.
+
+2000-07-01 Hideaki YOSHIFUJI ($B5HF#1QL@(B) <yoshfuji@ecei.tohoku.ac.jp>
+
+ * smux.c: Add IPv6 smux connection code.
+
+2000-06-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_complete_command): To cooperate readline library,
+ returned string is newly allocated. So some match function case
+ need, free of memory.
+
+2000-06-12 Akihiro Mizutani <mizutani@dml.com>
+
+ * distribute.c: Fix help strings.
+
+2000-06-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (cmd_complete_command): Add check for vector_slot
+ (vline, index) is not NULL when calculating lcd.
+ (cmd_entry_function): First check variable arguemnt to prevent it
+ from completion.
+
+2000-06-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.h (struct vty ): Add output_count member for displaying
+ output route count. Remove arugment arg from output_func because
+ the value is passed by vty argument. Change output to output_rn.
+ Add output_clean function pointer member. Add output_type member.
+
+2000-06-10 Toshiaki Takada <takada@zebra.org>
+
+ * command.c (show_startup_config): Add "show startup-config"
+ command.
+
+2000-06-06 Akihiro Mizutani <mizutani@dml.com>
+
+ * filter.c: Fix help strings.
+
+2000-06-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * prefix.h (struct prefix_rd): New prefix structure for routing
+ distinguisher.
+ (struct prefix): Add padding to every prefix structure.
+
+
+ * routemap.c (route_map_add_match): When completely same match
+ statement exists, don't duplicate it.
+
+2000-06-05 Akihiro Mizutani <mizutani@dml.com>
+
+ * routemap.c: Change NAME to WORD.
+
+ * plist.c: Fix help strings.
+
+2000-06-02 Akihiro Mizutani <mizutani@dml.com>
+
+ * routemap.c: Fix route-map help strings.
+
+2000-06-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (cmd_filter_by_completion): Fix CMD_VARARG treatment
+ to filter other non vararg commands.
+
+ * routemap.c (route_map_init_vty): Use install_default() for
+ install common commands into route-map node..
+
+2000-06-01 Akihiro Mizutani <mizutani@dml.com>
+
+ * command.h (OSPF_STR): Macro added.
+
+2000-05-31 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (cmd_complete_command): LCD completion must not modify
+ installed command string.
+
+ * plist.c (ipv6_prefix_list): Fix wrong syntax definition. Change
+ X:X::X:X to X:X::X:X/M.
+
+2000-05-31 Toshiaki Takada <takada@zebra.org>
+
+ * vty.c (show_history): New defun added.
+
+2000-05-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.h (CMD_COMPLETE_LIST_MATCH): New define for completion
+ list. CMD_COMPLETE_MATCH is used for LCD completion.
+
+ * vty.c (vty_complete_command): Matched string's LCD is completed.
+
+ * command.c (cmd_lcd): New function for calculate LCD of matched
+ strings.
+
+2000-05-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (install_default): config_write_terminal_cmd,
+ config_write_file_cmd, config_write_memory_cmd are added to
+ default node.
+
+ * memory.c (memory_init): Divide show memory command into each
+ sort.
+
+ * command.c (cmd_init): config_write_terminal_cmd,
+ config_write_file_cmd, config_write_memory_cmd are added to
+ CONFIG_NODE.
+
+ * routemap.c (route_map_index_free): New function.
+ (no_route_map_all): New DEFUN for "no route-map NAME".
+
+ * filter.c (no_access_list_all): New DEFUN for delete access-list
+ with NAME.
+ (no_ipv6_access_list_all): Likewise.
+
+2000-05-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * plist.c: Change IPV6_PREFIX to X:X::X:X. When "any" is
+ specified, user can not use "ge" and "le" statement.
+
+2000-05-22 Thomas Molkenbur <tmo@datus.datus.com>
+
+ * routemap.c (route_map_add_set): Fix bug of next pointer missing.
+
+ * table.c (route_table_free): Like wise.
+
+2000-05-22 Toshiaki Takada <takada@zebra.org>
+
+ * vty.c (vty_stop_input): Set history pointer to the latest one.
+
+ * vty.c (vty_hist_add): Do not add command line history when input
+ is as same as previous one.
+
+2000-05-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * memory.h (enum): Add MTYPE_ECOMMUNITY and MTYPE_ECOMMUNITY_VAL.
+
+2000-05-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.h (node_type ): Add BGP_VPNV4_NODE.
+
+2000-05-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vtysh_accept): Add cast of struct sockaddr * to bind
+ argument. Reported by: Vesselin Mladenov <mladenov@netbg.com>.
+
+ * filter.c (ipv6_access_list): Add IPv6 prefix example instead of
+ IPv4 example. Reported by: Love <lha@s3.kth.se>.
+
+ * command.c (cmd_complete_command): Make it sure last element of
+ matchvec is NULL. This fix problem which cause crush in
+ vty_complete_command(). Reported by: JINMEI Tatuya
+ <jinmei@isl.rdc.toshiba.co.jp>.
+
+2000-04-28 Love <lha@s3.kth.se>
+
+ * prefix.h (struct prefix): Add padding.
+
+2000-04-28 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (show_version): Update copyright year.
+
+2000-04-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * routemap.c (route_map_apply): When map is NULL, return deny.
+
+2000-04-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * filter.c (access_list_apply): When access is NULL, return deny.
+
+ * plist.c (prefix_list_apply): When plist is NULL, return deny.
+
+2000-04-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.h (node_type ): Change RDISC_NODE to IRDP_NODE.
+
+2000-04-18 Toshiaki Takada <takada@zebra.org>
+
+ * filter.[ch] (access_list_add_hook), (access_list_delete_hook):
+ Add argument for hook function to give struct access_list *.
+
+2000-04-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * plist.c (prefix_list_entry_match): In case of le nor ge is
+ specified, exact match is performed.
+ (prefix_list_entry_match): Add any entry matching check.
+
+2000-04-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (exec_timeout): Separate timeout setting to minutes and
+ seconds.
+ (no_exec_timeout): Add "no exec-timeout" command.
+
+ * vty.h (VTY_TIMEOUT_DEFAULT): Change default value from 300 to
+ 600.
+
+2000-03-31 Jochen Friedrich <jochen@scram.de>
+
+ * smux.h (SMUX_CLOSE): The SMUX_CLOSE PDU is implicit integer, so
+ it is a primitive encoding and not constructed.
+
+2000-03-28 Toshiaki Takada <takada@zebra.org>
+
+ * memory.[ch] (enum): Add MTYPE_OSPF_EXTERNAL_INFO.
+
+2000-03-26 Love <lha@s3.kth.se>
+
+ * zclient.c (zclient_read): Add nbytes size check for
+ ZEBRA_HEADER_SIZE. Check return value of steam_read ().
+
+2000-03-26 Rick Payne <rickp@rossfell.co.uk>
+
+ * routemap.c: Add flexible route-map commands such as on-match
+ next, on-match goto N.
+
+ * routemap.h: Likewise
+
+2000-03-23 Adrian Bool <aid@u.net.uk>
+
+ * command.c (config_log_trap): Add new command "log trap
+ PRIORITY".
+
+2000-03-14 Toshiaki Takada <takada@zebra.org>
+
+ * memory.c (struct memory_list): Add Link List and Link Node
+ to view.
+
+ * memory.h (enum): Remove MTYPE_OSPF_EXTERNAL_ROUTE.
+
+2000-01-20 Hideto Yamakawa <hideto.yamakawa@soliton.co.jp>
+
+ * str.c (snprintf): Fix bug of calling sprintf instead of
+ vsprintf.
+
+2000-01-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * memory.h (enum): Add MTYPE_RIP_PEER.
+
+2000-01-15 Toshiaki Takada <takada@zebra.org>
+
+ * memory.h (enum): Add MTYPE_OSPF_CRYPT_KEY.
+
+2000-01-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.h (node_type ): Add MASC_NODE for masc.
+
+2000-01-09 Wang Jianliang <wangjl@soim.net>
+
+ * routemap.c (route_map_index_add): When route_map_index is not
+ empty and insert new item at the head, it can cause core dump.
+ Fix "if (index == map->head)" to "if (point == map->head).
+ (route_map_add_set): If there is an old set command, override old
+ set command with new one.
+ (route_map_index_delete): Use while() instead of for for() for
+ logical correctness.
+
+1999-12-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * memory.h (enum): Add MTYPE_BGP_STATIC.
+
+1999-12-23 Alex Zinin <zinin@amt.ru>
+ * zebra.h, zclient.*: dynamic int up/down message
+ support
+
+1999-12-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * thread.c (thread_cancel_event): Add a function for clean up
+ events.
+
+1999-12-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * dropline.c: Delete file.
+ dropline.h: Linewise.
+
+1999-12-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * filter.c (access_list_filter_delete): Wrong pointer
+ access->master was pointed out after access is freed. I store
+ master value at the beginning of the function.
+
+1999-12-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (exec_timeout): Change of VTY timeout affect to current
+ VTY connection.
+ (vty_accept): Instead of immediate exit() return -1.
+
+1999-12-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_configure_lock): Configuration lock function added.
+ Only one VTY can use CONFI_NODE at the same time.
+
+ * log.c: Delete zvlog_* functions. Now zlog_* does the same
+ thing.
+
+ * log.c (log_init): Function removed.
+ (log_close): Likewise.
+ (log_flush): Likewise.
+ (log_open): Likewise.
+
+ * vty.c (terminal_monitor): Add new command.
+ (no_terminal_monitor): Likewise.
+
+ * log.c (old_log): Function removed.
+ (old_log2): Likewise.
+ (old_log_warn): Likewise.
+
+1999-12-04 Toshiaki Takada <takada@zebra.org>
+
+ * command.c (cmd_ipv6_match): New function added.
+ (cmd_ipv6_prefix_match): Likewise.
+
+1999-12-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (cmd_ipv6_match):
+
+ * table.c: Delete #ifdef HAVE_MBGPV4.
+
+ * prefix.h (struct prefix): Add safi member.
+ (struct prefix_ipv4): Likewise.
+ (struct prefix_ipv6): Likewise.
+
+1999-12-04 Rumen Svobodnikov <rumen@linux.tu-varna.acad.bg>
+
+ * memory.c (struct mstat): Revert to support MEMORY_LOG.
+
+1999-11-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: Bump up to 0.81c for testing new kernel codes.
+
+1999-11-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * thread.h (struct thread): Pthread support is disabled all
+ platform.
+
+1999-11-21 Michael Handler <handler@sub-rosa.com>
+
+ * Include <limits.h> and <strings.h> under SUNOS_5.
+
+1999-11-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * sockunion.c (in6addr_cmp): Enclosed by #define HAVE_IPV6
+1999-11-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.h (node_type ): Add BGP_IPV4_NODE and BGP_IPV6_NODE.
+
+1999-11-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (disable): Add `disable' command.
+
+1999-11-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * plist.c (vty_prefix_list_install): Add any check.
+
+1999-11-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.h (node_type ): Add DUMP_NODE.
+
+1999-11-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * smux.c: Change default SMUX oid to compatible with gated.
+
+1999-10-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if_rmap.c: New file added.
+
+ * if_rmap.h: New file added.
+
+1999-10-29 Alex Zinin <zinin@amt.ru>
+
+ * hash.c: add hash_free() function
+
+1999-10-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * hash.c (hash_clean): Add clean function.
+
+ * plist.c (prefix_list_reset): Add reset function.
+
+ * filter.c (access_list_reset): Add reset function.
+
+1999-10-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * client.c: Merged with zclient.c.
+ * client.h: Merged with zclient.h.
+
+1999-10-15 Jordan Mendelson <jordy@wserv.com>
+
+ * md5.c: Imported from GNU C Library.
+ * md5-gnu.h: Likewise.
+
+1999-10-15 Jochen Friedrich <jochen@scram.de>
+
+ * smux.c (smux_getresp_send): SMUX_GETRSP codes improvement.
+
+1999-10-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * smux.h: New file added.
+
+ * snmp.c: Rename to smux.c.
+
+1999-10-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (cmd_execute_command_strict): Filter ambious commands.
+ (cmd_filter_by_string): Change to return enum match_type.
+
+1999-10-01 Toshiaki Takada <takada@zebra.org>
+
+ * vty.c (vty_describe_fold): New function which does VTY
+ description line fold.
+ * vty.c (vty_describe_command): Set description column.
+
+1999-09-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * plist.c (prefix_list_init_ipv4): VTY user interface is improved.
+
+1999-09-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (cmd_filter_by_string): Fix bug of CMD_IPV4 and
+ CMD_IPV4_PREFIX check. Both return type must be exact_match.
+
+1999-09-24 Toshiaki Takada <takada@zebra.org>
+
+ * command.c (cmd_filter_by_completion),
+ (is_cmd_ambiguous): Check IPv4 address, IPv4 prefix and range
+ parameter matches range.
+
+1999-09-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * routemap.c (route_map_apply): Returm RM_DENYMATCH when no match
+ is performed.
+
+1999-09-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_read): Control-C stop VTY_MORE mode.
+
+1999-09-20 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.h (node_type ): Add ACCESS_IPV6_NODE and
+ PREFIX_IPV6_NODE.
+
+ * distribute.h: New file added.
+
+ * command.h (node_type ): Delete DISTRIBUTE_NODE.
+
+1999-09-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_terminate_all): New function added for reload
+ support.
+
+1999-09-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * memory.h (enum): Add new type MTYPE_OSPF_EXTERNAL_ROUTE.
+
+1999-08-31 Janos Farkas <chexum@shadow.banki.hu>
+
+ * vty.c (vty_read): Handle also 0x7f (alt-backspace), just like
+ esc-ctrl-h (delete word backwards).
+
+1999-08-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if.h: Add if_nametoindex for NRL.
+
+1999-08-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if.c (if_create): New function.
+
+1999-08-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * snmp.c: New file.
+
+1999-08-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * stream.c (stream_put): stream_memcpy () is changed to stream_put
+ (). stream_get () is added.
+
+1999-08-18 Toshiaki Takada <takada@zebra.org>
+
+ * memory.h (enum): Add MTYPE_OSPF_LSA_DATA.
+
+1999-08-18 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * table.c (route_table_finish): add function frees table.
+
+1999-08-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * memory.h (enum): Add MTYPE_RTADV_PREFIX.
+
+1999-08-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if.h (struct interface ): hw_address, hw_address_len added.
+
+1999-08-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if.h (struct interface ): Change structure member if_data to
+ info, index to ifindex.
+
+1999-08-08 Rick Payne <rickp@rossfell.co.uk>
+
+ * routemap.c: Multi protocol route-map modification.
+
+ * routemap.c (route_map_apply): Route match process bug is fixed.
+
+1999-08-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * thread.c (thread_fetch): When signal comes, goto retry point.
+
+1999-08-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am: Add sockopt.c and sockopt.h
+ * sockopt.c: New file.
+ * sockopt.h: New file.
+
+1999-08-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h (ZEBRA_VERSION): Release zebra-0.75
+
+1999-08-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * memory.h (enum): Add MTYPE_RIPNG_AGGREGATE.
+
+1999-07-31 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * sockunion.h: Add sockunion_getpeername ().
+
+1999-07-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: Release zebra-0.74
+
+1999-07-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.h (struct host): Delete lines from struct host. Add
+ lines to struct vty.
+
+ * command.c: Delete `lines LINES'. Terminal display line settings
+ should be done by `terminal length' command.
+
+1999-07-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * memory.h (enum): MTYPE_OSPF_PATH are added.
+
+1999-07-22 Toshiaki Takada <takada@zebra.org>
+
+ * memory.h (enum): MTYPE_OSPF_NEXTHOP is added.
+
+1999-07-21 Toshiaki Takada <takada@zebra.org>
+
+ * linklist.c (list_add_node_prev), (list_add_node_next),
+ (list_add_list): New function added.
+
+ * table.c (route_table_free): New function added.
+
+1999-07-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * plist.c (config_write_prefix): Set write flag when configuration
+ is written.
+
+1999-07-15 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * prefix.c : prefix_cmp() added. change apply_mask() to
+ apply_mask_ipv4(), and new apply_mask() added.
+
+1999-07-14 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * prefix.c (prefix2str): append prefixlen.
+
+1999-07-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (config_terminal): Change "config terminal" to
+ "configure terminal". Reported by Georg Hitsch
+ <georg@atnet.at>.
+ (config_terminal_length): `terminal length <0-512>' is added. At
+ this moment this command is only usef for vty interface.
+ Suggested by Georg Hitsch <georg@atnet.at>.
+
+1999-07-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * routemap.c (rulecmp): Add wrapper function of strcmp.
+
+1999-07-08 Rick Payne <rickp@rossfell.co.uk>
+
+ * sockunion.c (inet_aton): Fix bug of inet_aton.
+
+1999-07-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h (ZEBRA_VERSION): Start zebra-0.73
+
+1999-07-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: Bump up to 0.72.
+
+1999-07-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (install_default): New function for install default
+ commands to the node.
+
+ * memory.h (enum): MTYPE_NEXTHOP is added.
+
+1999-07-01 <kunihiro@zebra.org>
+
+ * command.c (no_banner_motd): `no banner motd' command added.
+
+1999-06-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * regex.c: Update to glibc-2.1.1's posix/regex.c
+
+ * regex-gnu.h: Update to glibc-2.1.1's posix/regex.h
+
+ * prefix.h (IPV4_ADDR_SAME): Macro added.
+ (IPV6_ADDR_SAME): Likewise.
+
+1999-06-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * memory.h (enum): Add MTYPE_OSPF_VERTEX
+
+ * version.h: Bump up to 0.71.
+
+ * vty.c (vty_serv_sock_addrinfo): Use addrinfo function to bind
+ VTY socket when IPv6 is enabled.
+
+1999-06-28 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_serv_sock): Change vty_serv_sock determine which
+ address family to bind.
+
+ * command.c: Add quit command.
+
+1999-06-26 NOGUCHI kay <kay@dti.ad.jp>
+
+ * vty.c (vty_read_config): Fix bug of configuration file path
+ detection.
+
+1999-06-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: Bump up to 0.70.
+
+1999-06-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * buffer.h (GETL): Remove GETL macro.
+
+ * version.h: Bump up to 0.69.
+
+1999-06-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if.c (connected_add): Commented out connected_log.
+
+1999-06-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.h (struct cmd_element ): strvec and descvec is combined
+ into newstrvec.
+
+ * command.c (desc_make): Function removed.
+ (desc_next): Function removed.
+
+ * command.h (struct cmd_element ): docvec is removed from struct
+ cmd_element.
+
+1999-06-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (cmd_execute_command): Remove command NULL check.
+
+ * command.h (struct cmd_element ): Add newstrvec entry to struct
+ cmd_element.
+ (DEFUN2): DEFUN2 macro is removed. DEFUN is extended to support
+ (a|b|c) statement.
+ (DESC): DESC macro is removed.
+
+ * vty.c (vty_complete_command): When return value is
+ CMD_ERR_NO_MATCH, don't display error message.
+
+1999-06-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * table.c (route_next_until): New function.
+
+ * version.h: Bump up to 0.68.
+
+1999-06-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_close): Free vty->buf when vty is closed.
+
+ * memory.h (enum): Add MTYPE_COMMUNITY_ENTRY and
+ MTYPE_COMMUNITY_LIST.
+
+ * vty.h (struct vty ): Change buf from static length buffer to
+ variable length buffer.
+
+ * vty.c (vty_ensure): New function added.
+
+1999-06-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.h (node_type ): Add COMMUNITY_LIST_NODE.
+
+ * command.c (config_enable_password): Freeing host.enable bug is
+ fixed.
+ (config_enable_password): Add argc count check.
+
+1999-05-31 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h: Bump up to 0.67.
+
+1999-05-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (zencrypt): New function for encrypt password.
+
+ * command.h (struct host): Add password_encrypt and
+ enable_encrypt.
+
+1999-05-30 Jochen Friedrich <jochen@scram.de>
+
+ * command.h (struct host): New member encrypt is added for
+ encrypted password.
+
+1999-05-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c: Remove all_digit_check function. Instead use all_digit.
+
+ * prefix.c (all_digit): New function for checking string is made
+ from digit character.
+
+1999-05-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am (libzebra_a_SOURCES): Add zclient.c.
+ (noinst_HEADERS): Add zclient.h
+
+ * zclient.[ch]: New file for zebra client routine.
+
+ * memory.h (enum): Add MTYPE_ZEBRA.
+
+1999-05-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h (ZEBRA_VERSION): Update to 0.66.
+
+1999-05-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * buffer.h (GETC,GETW): Macro deleted.
+
+1999-05-15 Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+ * prefix.h (IPV4_NET0, IPV4_NET127): Macro added.
+
+1999-05-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (service_advanced_vty): New command added.
+ (no_service_advanced_vty): Likewise.
+
+1999-05-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_auth): If advanced flag is set and enable password is
+ not set, directly login to the ENABLE_NODE. This feature is
+ originally designed and implemented by Stephen R. van den Berg
+ <srb@cuci.nl>.
+
+ * command.h (host): Add advanced flag to struct host for advanced
+ vty terminal interface.
+
+ * version.h (ZEBRA_VERSION): Update to 0.65 for next beta release.
+
+1999-05-14 Stephen R. van den Berg <srb@cuci.nl>
+
+ * command.h (node_type ): Add TABLE_NODE.
+
+ * vty.c (vty_telnet_option): Check host.lines value.
+
+ * command.c (config_lines): DEFUN for 'lines LINES' command.
+
+ * zebra.h: Include <sys/utsname.h> for uname().
+ (RT_TABLE_MAIN): Defined as 0 if OS does not support multiple
+ routing table.
+
+ * vty.c (vty_auth): Directly login to the ENABLE_NODE when enable
+ password is not set.
+ (vty_prompt): Get machine's hostname when hostname is not set.
+
+1999-05-11 James Willard <james@whispering.org>
+
+ * command.c (config_exit): Close connection when `exit' command is
+ executed at ENABLE_NODE.
+
+1999-05-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_stop_input): `C-c' key change node to ENABLE_NODE.
+
+ * command.c (cmd_execute_command_strict): Matched command size
+ check added.
+ (cmd_make_desc_line): New function for DEFUN2.
+
+ * command.h (struct cmd_element ): Add descsize.
+
+1999-05-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.h (struct cmd_element ): Remame descvec to docvec.
+ (struct cmd_element ): Add descvec for new description system.
+
+ * command.c (desc_make): Check cmd->descvec.
+
+1999-05-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * memory.h (enum): Add MTYPE_CLUSTER, MTYPE_CLUSTER_VAL.
+
+1999-05-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h (ZEBRA_VERSION): Bump up to 0.64 for next beta
+ release.
+
+1999-05-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * linklist.c (list_delete_all_node): bug fix.
+ previous code loses current position when node
+ is deleted.
+
+1999-05-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.h (DESC): Macro added.
+ (struct cmd_element2): Delete struct cmd_element2.
+
+ * plist.c (prefix_list): Sequential number option check is added.
+
+1999-05-02 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * log.c (zvlog_{debug,info,notice,warn,err}): have been
+ added. now we can log both console and file, but still
+ need some fix about config write.
+
+1999-05-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * log.c (zvlog_debug): Fix yasu's change.
+
+1999-05-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * plist.c (prefix_list): Fix typo.
+
+1999-04-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Set version to 0.63 for first beta package.
+
+1999-04-27 Carlos Barcenilla <barce@frlp.utn.edu.ar>
+
+ * prefix.c (str2prefix_ipv4): Fix prefix length check.
+ (str2prefix_ipv6): Likewise.
+
+1999-04-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * memory.h (enum): Add MTPYE_PREFIX_LIST and
+ MTYPE_PREFIX_LIST_ENTRY.
+
+ * command.h (node_type ): Add PREFIX_NODE.
+
+1999-04-25 Carlos Barcenilla <barce@frlp.utn.edu.ar>
+
+ * command.c: ALIAS (config_write_memory_cmd) and ALIAS
+ (copy_runningconfig_startupconfig_cmd) is added.
+
+ * table.c (route_node_lookup): Unused match variable deletion.
+
+1999-04-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am (libzebra_a_SOURCES): plist.c added.
+ (noinst_HEADERS): plist.h added.
+
+ * plist.c, plist.h: New file added.
+
+ * memory.h (enum): Rename MTYPE_AS_PASN to MTYPE_AS_STR.
+ * memory.c: Likewise.
+
+1999-04-19 Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+ * command.c (show_version): `show version' command added.
+
+1999-04-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * prefix.c (str2prefix_ipv6): Prefix length overflow check.
+
+1999-04-19 Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+ * prefix.c (str2prefix_ipv4): Prefix length overflow check.
+
+1999-04-19 Alex Bligh <amb@gxn.net>
+
+ * prefix.c (sockunion2hostprefix): Function added.
+ (sockunion2prefix): Address family was not set. Now it is set.
+
+ * vty.c: VTY access-class command is added.
+
+1999-04-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * memory.c: Change xmalloc to zmalloc. xcalloc, xrealloc, xfree,
+ xstrdup are likewise.
+
+1999-04-18 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * thread.c: Add thread_execute for other routing daemon.
+ OSPF tasks need to be generated by "sheduled" and "executed".
+
+1999-04-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * buffer.c: Rewrite buffer_write and buffer_flush related
+ functions for fixing bugs. Reason of the problem and fix is
+ suggested by Alex Bligh <amb@gxn.net>.
+
+1999-04-12 Alex Bligh <amb@gxn.net>
+
+ * command.c (cmd_entry_function_descr): Added for variable
+ argument help display.
+
+1999-04-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * regex.c, regex-gnu.h: Imported from GNU sed-3.02 distribution.
+
+1999-03-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * stream.c: stream_fifo_free bug is fixed.
+
+1999-03-19 Toshiaki Takada <takada@zebra.org>
+
+ * stream.c (stream_strncpy): Added for getting any length bytes
+ from stream.
+
+1999-03-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * version.h (ZEBRA_BUG_ADDRESS): New macro added.
+
+1999-03-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * buffer.c (buffer_flush_window): If ep is same as buffer's size
+ length and lp is overrun one octet.
+
+1999-03-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.h: add VTY's timeout function.
+
+1999-03-05 <kunihiro@zebra.org>
+
+ * command.h (node_type ): Add OSPF6_node.
+
+1999-03-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra.h: Check HAVE_SYS_SELECT_H when include <sys/select.h>
+
+1999-03-03 Jeroen Ruigrok/Asmodai <asmodai@wxs.nl>
+
+ * zebra.h: Include <net/if_var.h> if it exists.
+
+1999-03-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * getopt.[ch],getopt1.c: Sync with glibc-2.1.
+
+ * log.c (zlog): Tempolary ZLOG_STDOUT feature added.
+
+ * command.h: Include vector.h and vty.h
+
+1999-02-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * routemap.h (struct route_map_rule_cmd): Add prefix arguemnt.
+
+ * routemap.c (route_map_apply_index): Add prefix argument.
+ (route_map_apply): Likewise.
+
+ * memory.h (enum): Add MTYPE_ROUTE_MAP_COMPILED.
+
+ * stream.c: Add stream_fifo related functions.
+
+1999-02-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * daemon.c: Return integer value. File descriptor close is added.
+
+ * memory.h (enum): add MTYPE_OSPF_LSA.
+
+1999-02-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rsh.c: Remove empty file.
+
+1999-02-22 <kunihiro@zebra.org>
+
+ * routemap.c: Add add/delete hook to route_map_master.
+
+1999-02-19 Peter Galbavy <Peter.Galbavy@knowledge.com>
+
+ * str.[ch] added to supply wrappers for snprintf(), strlcat() and
+ strlcpy on system without these.
+
+1999-02-18 Peter Galbavy <Peter.Galbavy@knowledge.com>
+
+ * syslog support added
+
+1999-02-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * filter.c (access_list_add_hook): added for hook function management.
+ * filter.c (access_list_delete_hook): Likewise.
+
+1999-01-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * stream.c: New file.
+ * stream.h: New file.
+ * Divide stream related fucntions from buffer.[ch] into stream.[ch].
+
+1999-01-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * memory.h (enum): add MTYPE_STREAM, MTYPE_STREAM_DATA
+
+ * buffer.c (stream_new): Set MTYPE_STREAM to XMALLOC argument.
+
+1998-12-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * routemap.c: route_map_index_delete() added.
+
+1998-12-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * buffer.c (buffer_empty): check cp instead of sp.
+
+1998-12-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * radix.[ch]: Deleted.
+
+1998-12-15 Magnus Ahltorp <map@stacken.kth.se>
+
+ * buffer.c: Prototype fixes.
+ * prefix.c: Likewise.
+ * sockunion.c: Likewise.
+ * sockunion.h: Likewise.
+
+1998-12-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_read): DELETE key works as vty_delete_char.
+
+1998-12-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * log.c (time_print): chane %y to %Y.
+
+1998-12-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * distribute.c: new file.
+
+1998-12-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * filter.c: Remove all of struct prefix_{ipv4,ipv6} and add
+ complete support of IPv6 access list.
+
+ * command.c (config_write_element): function delete.
+ (config_write_host): function add. password and enable password
+ isn't printed to vty interface.
+
+1998-12-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * filter.c: Change prefix_ipv4 to prefix and add support of
+ prefix_ipv6 filtering.
+
+1998-12-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am (INCLUDES): add @INCLUDES@ for Linux IPv6 inet6-apps
+ header includes.
+
+1998-12-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * log.c (log_flush): fix function name typo.
+
+1998-12-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * memory.h: OSPF memory type is added.
+
+1998-11-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (sort_node): add sort_node() for pretty printing of
+ command on vty interface.
+ (config_password): delete the restriction of charaster of password
+ string.
+
+1998-09-05 Kunihiro Ishiguro <kunihiro@debian.zebra.org>
+
+ * prefix.c (prefix_ipv4_any): add prefix_ipv4_any().
+
+1998-08-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * network.h: New file.
+
+1998-08-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_will_echo): function name change from vty_off_echo.
+
+1998-08-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * buffer.h: add PUTC,PUTW,PUTL macros.
+
+1998-07-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * route.[ch]: renamed to prefix.[ch]
+
+1998-06-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * prefix_in, prefix_in6 is replaced by prefix_ipv4, prefix_ipv6.
+
+ * Makefile.am: @INCLUDES@ is deleted from INCLUDES.
+
+1998-06-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * host.[ch]: merged with command.[ch]
+
+1998-05-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am (libzebra_a_SOURCES): add route.c to libzebra_a_SOURCES.
+
+1998-05-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * route.c (str2prefix): str2prefix () is gone.
+
+1998-05-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_read_config): change CONDIR to SYSCONFDIR.
+
+ * .cvsignore: add file.
+
+ * memory.c (xerror): add arguent `type' and `size'.
+
+ * socket.c: deleted.
+
+1998-05-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vector.c: malloc,free,realloc -> XMALLOC,XFREE,XREALLOC.
+ * linklist.c: same as above.
+
+1998-04-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * filter.[ch]: added.
+
+1998-04-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (config_who): return CMD_SUCCESS
+
+1998-04-01 Jochen Friedrich <jochen@scram.de>
+
+ * table.c (route_dump_node): route_dump_node is IPv6 specific
+ function so move #ifdef to the end of route_dump_node ().
+
+1998-03-05 "Hannes R. Boehm" <hannes@boehm.org>
+
+ * if.c: DEFUN(interface_desc) added.
+
+1998-03-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if.c: separated from ripd/rip_interface.c
+
+1998-03-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * thread.[ch] : added.
+
+1998-02-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_delete_char): fix size bug.
+ (vty_backward_pure_word): function added.
+ (vty_read): ESC + 'f' perform vty_forward_word.
+ (vty_read): ESC + 'b' perform vty_backward_word.
+
+1998-02-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * radix.c (radix_lookup_rt): add mask check.
+ (radix_delete_duproute): add mask check.
+
+1998-02-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (config_write_file): fix vty -> file_vty.
+
+1998-02-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (cmd_filter_ambiguous): add complex type treatment.
+
+1998-02-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_time_print): function added.
+ (vty_complete_command): now [...] element isn't shown by completion.
+
+1998-01-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c : change from cmd_install_node() to install_node().
+
+1998-01-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * route.[ch]: struct rt{} is replaced by struct prefix{}.
+
+1998-01-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c (cmd_execute_command): check command length.
+
+ * timer.c (zebra_timer_set): add zebra_timer_set.
+
+1998-01-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.h (node_type ): add ZEBRA_NODE.
+
+ * command.c (config_exit): add RIP_NODE.
+ (config_write_file): add RIP_NODE.
+
+1998-01-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * print_version.c (print_version): Now Copyright is 1996-1998.
+
+ * sockunion.c (sockunion_log): moved from ../zebra/route.c
+
+1997-12-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * host.c (config_logfile): change 'log PATH' to 'logfile PATH'.
+
+ * sockunion.c (sockunion_sameprefix): add same prefix for
+ sockunion.
+
+1997-12-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * radix.[ch] : are moved from ../zebra directroy.
+
+ * command.c (config_from_file): if command execution failed down
+ level to CONFIG_NODE.
+
+ * host.c: config_log function which enable 'log FILENAME' command.
+
+1997-12-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c: add vty_transpose_chars (). Now you can use '^T' to
+ transpose character.
+
+ * command.c: cmd_cmdsize add, this is useful to check incomplete
+ command.
+
+1997-12-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * fd.h: add family for address family
+
+1997-12-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.o
+ * vty.o
+ * host.o is moved from ../zebra
+
+1997-08-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * make library directory.
+
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
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 <zebra.h>
+
+#include "memory.h"
+#include "buffer.h"
+
+/* Make buffer data. */
+struct buffer_data *
+buffer_data_new (size_t size)
+{
+ struct buffer_data *d;
+
+ d = XMALLOC (MTYPE_BUFFER_DATA, sizeof (struct buffer_data));
+ memset (d, 0, sizeof (struct buffer_data));
+ d->data = XMALLOC (MTYPE_BUFFER_DATA, size);
+
+ return d;
+}
+
+void
+buffer_data_free (struct buffer_data *d)
+{
+ if (d->data)
+ XFREE (MTYPE_BUFFER_DATA, d->data);
+ XFREE (MTYPE_BUFFER_DATA, d);
+}
+
+/* Make new buffer. */
+struct buffer *
+buffer_new (size_t size)
+{
+ struct buffer *b;
+
+ b = XMALLOC (MTYPE_BUFFER, sizeof (struct buffer));
+ memset (b, 0, sizeof (struct buffer));
+
+ b->size = size;
+
+ return b;
+}
+
+/* Free buffer. */
+void
+buffer_free (struct buffer *b)
+{
+ struct buffer_data *d;
+ struct buffer_data *next;
+
+ d = b->head;
+ while (d)
+ {
+ next = d->next;
+ buffer_data_free (d);
+ d = next;
+ }
+
+ d = b->unused_head;
+ while (d)
+ {
+ next = d->next;
+ buffer_data_free (d);
+ d = next;
+ }
+
+ XFREE (MTYPE_BUFFER, b);
+}
+
+/* Make string clone. */
+char *
+buffer_getstr (struct buffer *b)
+{
+ return strdup ((char *)b->head->data);
+}
+
+/* Return 1 if buffer is empty. */
+int
+buffer_empty (struct buffer *b)
+{
+ if (b->tail == NULL || b->tail->cp == b->tail->sp)
+ return 1;
+ else
+ return 0;
+}
+
+/* Clear and free all allocated data. */
+void
+buffer_reset (struct buffer *b)
+{
+ struct buffer_data *data;
+ struct buffer_data *next;
+
+ for (data = b->head; data; data = next)
+ {
+ next = data->next;
+ buffer_data_free (data);
+ }
+ b->head = b->tail = NULL;
+ b->alloc = 0;
+ b->length = 0;
+}
+
+/* Add buffer_data to the end of buffer. */
+void
+buffer_add (struct buffer *b)
+{
+ struct buffer_data *d;
+
+ d = buffer_data_new (b->size);
+
+ if (b->tail == NULL)
+ {
+ d->prev = NULL;
+ d->next = NULL;
+ b->head = d;
+ b->tail = d;
+ }
+ else
+ {
+ d->prev = b->tail;
+ d->next = NULL;
+
+ b->tail->next = d;
+ b->tail = d;
+ }
+
+ b->alloc++;
+}
+
+/* Write data to buffer. */
+int
+buffer_write (struct buffer *b, u_char *ptr, size_t size)
+{
+ struct buffer_data *data;
+
+ data = b->tail;
+ b->length += size;
+
+ /* We use even last one byte of data buffer. */
+ while (size)
+ {
+ /* If there is no data buffer add it. */
+ if (data == NULL || data->cp == b->size)
+ {
+ buffer_add (b);
+ data = b->tail;
+ }
+
+ /* Last data. */
+ if (size <= (b->size - data->cp))
+ {
+ memcpy ((data->data + data->cp), ptr, size);
+
+ data->cp += size;
+ size = 0;
+ }
+ else
+ {
+ memcpy ((data->data + data->cp), ptr, (b->size - data->cp));
+
+ size -= (b->size - data->cp);
+ ptr += (b->size - data->cp);
+
+ data->cp = b->size;
+ }
+ }
+ return 1;
+}
+
+/* Insert character into the buffer. */
+int
+buffer_putc (struct buffer *b, u_char c)
+{
+ buffer_write (b, &c, 1);
+ return 1;
+}
+
+/* Insert word (2 octets) into ther buffer. */
+int
+buffer_putw (struct buffer *b, u_short c)
+{
+ buffer_write (b, (char *)&c, 2);
+ return 1;
+}
+
+/* Put string to the buffer. */
+int
+buffer_putstr (struct buffer *b, u_char *c)
+{
+ size_t size;
+
+ size = strlen ((char *)c);
+ buffer_write (b, c, size);
+ return 1;
+}
+
+/* Flush specified size to the fd. */
+void
+buffer_flush (struct buffer *b, int fd, size_t size)
+{
+ int iov_index;
+ struct iovec *iovec;
+ struct buffer_data *data;
+ struct buffer_data *out;
+ struct buffer_data *next;
+
+ iovec = malloc (sizeof (struct iovec) * b->alloc);
+ iov_index = 0;
+
+ for (data = b->head; data; data = data->next)
+ {
+ iovec[iov_index].iov_base = (char *)(data->data + data->sp);
+
+ if (size <= (data->cp - data->sp))
+ {
+ iovec[iov_index++].iov_len = size;
+ data->sp += size;
+ if (data->sp == data->cp)
+ data = data->next;
+ break;
+ }
+ else
+ {
+ iovec[iov_index++].iov_len = data->cp - data->sp;
+ size -= data->cp - data->sp;
+ data->sp = data->cp;
+ }
+ }
+
+ /* Write buffer to the fd. */
+ writev (fd, iovec, iov_index);
+
+ /* Free printed buffer data. */
+ for (out = b->head; out && out != data; out = next)
+ {
+ next = out->next;
+ if (next)
+ next->prev = NULL;
+ else
+ b->tail = next;
+ b->head = next;
+
+ buffer_data_free (out);
+ b->alloc--;
+ }
+
+ free (iovec);
+}
+
+/* Flush all buffer to the fd. */
+int
+buffer_flush_all (struct buffer *b, int fd)
+{
+ int ret;
+ struct buffer_data *d;
+ int iov_index;
+ struct iovec *iovec;
+
+ if (buffer_empty (b))
+ return 0;
+
+ iovec = malloc (sizeof (struct iovec) * b->alloc);
+ iov_index = 0;
+
+ for (d = b->head; d; d = d->next)
+ {
+ iovec[iov_index].iov_base = (char *)(d->data + d->sp);
+ iovec[iov_index].iov_len = d->cp - d->sp;
+ iov_index++;
+ }
+ ret = writev (fd, iovec, iov_index);
+
+ free (iovec);
+
+ buffer_reset (b);
+
+ return ret;
+}
+
+/* Flush all buffer to the fd. */
+int
+buffer_flush_vty_all (struct buffer *b, int fd, int erase_flag,
+ int no_more_flag)
+{
+ int nbytes;
+ int iov_index;
+ struct iovec *iov;
+ struct iovec small_iov[3];
+ char more[] = " --More-- ";
+ char erase[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
+ struct buffer_data *data;
+ struct buffer_data *out;
+ struct buffer_data *next;
+
+ /* For erase and more data add two to b's buffer_data count.*/
+ if (b->alloc == 1)
+ iov = small_iov;
+ else
+ iov = XCALLOC (MTYPE_TMP, sizeof (struct iovec) * (b->alloc + 2));
+
+ data = b->head;
+ iov_index = 0;
+
+ /* Previously print out is performed. */
+ if (erase_flag)
+ {
+ iov[iov_index].iov_base = erase;
+ iov[iov_index].iov_len = sizeof erase;
+ iov_index++;
+ }
+
+ /* Output data. */
+ for (data = b->head; data; data = data->next)
+ {
+ iov[iov_index].iov_base = (char *)(data->data + data->sp);
+ iov[iov_index].iov_len = data->cp - data->sp;
+ iov_index++;
+ }
+
+ /* In case of `more' display need. */
+ if (! buffer_empty (b) && !no_more_flag)
+ {
+ iov[iov_index].iov_base = more;
+ iov[iov_index].iov_len = sizeof more;
+ iov_index++;
+ }
+
+ /* We use write or writev*/
+ nbytes = writev (fd, iov, iov_index);
+
+ /* Error treatment. */
+ if (nbytes < 0)
+ {
+ if (errno == EINTR)
+ ;
+ if (errno == EWOULDBLOCK)
+ ;
+ }
+
+ /* Free printed buffer data. */
+ for (out = b->head; out && out != data; out = next)
+ {
+ next = out->next;
+ if (next)
+ next->prev = NULL;
+ else
+ b->tail = next;
+ b->head = next;
+
+ buffer_data_free (out);
+ b->alloc--;
+ }
+
+ if (iov != small_iov)
+ XFREE (MTYPE_TMP, iov);
+
+ return nbytes;
+}
+
+/* Flush buffer to the file descriptor. Mainly used from vty
+ interface. */
+int
+buffer_flush_vty (struct buffer *b, int fd, int size,
+ int erase_flag, int no_more_flag)
+{
+ int nbytes;
+ int iov_index;
+ struct iovec *iov;
+ struct iovec small_iov[3];
+ char more[] = " --More-- ";
+ char erase[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
+ struct buffer_data *data;
+ struct buffer_data *out;
+ struct buffer_data *next;
+
+#ifdef IOV_MAX
+ int iov_size;
+ int total_size;
+ struct iovec *c_iov;
+ int c_nbytes;
+#endif /* IOV_MAX */
+
+ /* For erase and more data add two to b's buffer_data count.*/
+ if (b->alloc == 1)
+ iov = small_iov;
+ else
+ iov = XCALLOC (MTYPE_TMP, sizeof (struct iovec) * (b->alloc + 2));
+
+ data = b->head;
+ iov_index = 0;
+
+ /* Previously print out is performed. */
+ if (erase_flag)
+ {
+ iov[iov_index].iov_base = erase;
+ iov[iov_index].iov_len = sizeof erase;
+ iov_index++;
+ }
+
+ /* Output data. */
+ for (data = b->head; data; data = data->next)
+ {
+ iov[iov_index].iov_base = (char *)(data->data + data->sp);
+
+ if (size <= (data->cp - data->sp))
+ {
+ iov[iov_index++].iov_len = size;
+ data->sp += size;
+ if (data->sp == data->cp)
+ data = data->next;
+ break;
+ }
+ else
+ {
+ iov[iov_index++].iov_len = data->cp - data->sp;
+ size -= (data->cp - data->sp);
+ data->sp = data->cp;
+ }
+ }
+
+ /* In case of `more' display need. */
+ if (!buffer_empty (b) && !no_more_flag)
+ {
+ iov[iov_index].iov_base = more;
+ iov[iov_index].iov_len = sizeof more;
+ iov_index++;
+ }
+
+ /* We use write or writev*/
+
+#ifdef IOV_MAX
+ /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
+ example: Solaris2.6 are defined IOV_MAX size at 16. */
+ c_iov = iov;
+ total_size = iov_index;
+ nbytes = 0;
+
+ while( total_size > 0 )
+ {
+ /* initialize write vector size at once */
+ iov_size = ( total_size > IOV_MAX ) ? IOV_MAX : total_size;
+
+ c_nbytes = writev (fd, c_iov, iov_size );
+
+ if( c_nbytes < 0 )
+ {
+ if(errno == EINTR)
+ ;
+ ;
+ if(errno == EWOULDBLOCK)
+ ;
+ ;
+ nbytes = c_nbytes;
+ break;
+
+ }
+
+ nbytes += c_nbytes;
+
+ /* move pointer io-vector */
+ c_iov += iov_size;
+ total_size -= iov_size;
+ }
+#else /* IOV_MAX */
+ nbytes = writev (fd, iov, iov_index);
+
+ /* Error treatment. */
+ if (nbytes < 0)
+ {
+ if (errno == EINTR)
+ ;
+ if (errno == EWOULDBLOCK)
+ ;
+ }
+#endif /* IOV_MAX */
+
+ /* Free printed buffer data. */
+ for (out = b->head; out && out != data; out = next)
+ {
+ next = out->next;
+ if (next)
+ next->prev = NULL;
+ else
+ b->tail = next;
+ b->head = next;
+
+ buffer_data_free (out);
+ b->alloc--;
+ }
+
+ if (iov != small_iov)
+ XFREE (MTYPE_TMP, iov);
+
+ return nbytes;
+}
+
+/* Calculate size of outputs then flush buffer to the file
+ descriptor. */
+int
+buffer_flush_window (struct buffer *b, int fd, int width, int height,
+ int erase, int no_more)
+{
+ unsigned long cp;
+ unsigned long size;
+ int lp;
+ int lineno;
+ struct buffer_data *data;
+
+ if (height >= 2)
+ height--;
+
+ /* We have to calculate how many bytes should be written. */
+ lp = 0;
+ lineno = 0;
+ size = 0;
+
+ for (data = b->head; data; data = data->next)
+ {
+ cp = data->sp;
+
+ while (cp < data->cp)
+ {
+ if (data->data[cp] == '\n' || lp == width)
+ {
+ lineno++;
+ if (lineno == height)
+ {
+ cp++;
+ size++;
+ goto flush;
+ }
+ lp = 0;
+ }
+ cp++;
+ lp++;
+ size++;
+ }
+ }
+
+ /* Write data to the file descriptor. */
+ flush:
+
+ return buffer_flush_vty (b, fd, size, erase, no_more);
+}
diff --git a/lib/buffer.h b/lib/buffer.h
new file mode 100644
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 <zebra.h>
+
+int /* return checksum in low-order 16 bits */
+in_cksum(ptr, nbytes)
+register u_short *ptr;
+register int nbytes;
+{
+ register long sum; /* assumes long == 32 bits */
+ u_short oddbyte;
+ register u_short answer; /* assumes u_short == 16 bits */
+
+ /*
+ * Our algorithm is simple, using a 32-bit accumulator (sum),
+ * we add sequential 16-bit words to it, and at the end, fold back
+ * all the carry bits from the top 16 bits into the lower 16 bits.
+ */
+
+ sum = 0;
+ while (nbytes > 1) {
+ sum += *ptr++;
+ nbytes -= 2;
+ }
+
+ /* mop up an odd byte, if necessary */
+ if (nbytes == 1) {
+ oddbyte = 0; /* make sure top half is zero */
+ *((u_char *) &oddbyte) = *(u_char *)ptr; /* one byte only */
+ sum += oddbyte;
+ }
+
+ /*
+ * Add back carry outs from top 16 bits to low 16 bits.
+ */
+
+ sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
+ sum += (sum >> 16); /* add carry */
+ answer = ~sum; /* ones-complement, then truncate to 16 bits */
+ return(answer);
+}
diff --git a/lib/command.c b/lib/command.c
new file mode 100644
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 <zebra.h>
+
+#include "command.h"
+#include "memory.h"
+#include "log.h"
+#include "version.h"
+
+/* Command vector which includes some level of command lists. Normally
+ each daemon maintains each own cmdvec. */
+vector cmdvec;
+
+/* Host information structure. */
+struct host host;
+
+/* Default motd string. */
+char *default_motd =
+"\r\n\
+Hello, this is zebra (version " ZEBRA_VERSION ").\r\n\
+Copyright 1996-2002 Kunihiro Ishiguro.\r\n\
+\r\n";
+
+/* Standard command node structures. */
+struct cmd_node auth_node =
+{
+ AUTH_NODE,
+ "Password: ",
+};
+
+struct cmd_node view_node =
+{
+ VIEW_NODE,
+ "%s> ",
+};
+
+struct cmd_node auth_enable_node =
+{
+ AUTH_ENABLE_NODE,
+ "Password: ",
+};
+
+struct cmd_node enable_node =
+{
+ ENABLE_NODE,
+ "%s# ",
+};
+
+struct cmd_node config_node =
+{
+ CONFIG_NODE,
+ "%s(config)# ",
+ 1
+};
+
+/* Utility function to concatenate argv argument into a single string
+ with inserting ' ' character between each argument. */
+char *
+argv_concat (char **argv, int argc, int shift)
+{
+ int i;
+ int len;
+ int index;
+ char *str;
+
+ str = NULL;
+ index = 0;
+
+ for (i = shift; i < argc; i++)
+ {
+ len = strlen (argv[i]);
+
+ if (i == shift)
+ {
+ str = XSTRDUP (MTYPE_TMP, argv[i]);
+ index = len;
+ }
+ else
+ {
+ str = XREALLOC (MTYPE_TMP, str, (index + len + 2));
+ str[index++] = ' ';
+ memcpy (str + index, argv[i], len);
+ index += len;
+ str[index] = '\0';
+ }
+ }
+ return str;
+}
+
+/* Install top node of command vector. */
+void
+install_node (struct cmd_node *node,
+ int (*func) (struct vty *))
+{
+ vector_set_index (cmdvec, node->node, node);
+ node->func = func;
+ node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
+}
+
+/* Compare two command's string. Used in sort_node (). */
+int
+cmp_node (const void *p, const void *q)
+{
+ struct cmd_element *a = *(struct cmd_element **)p;
+ struct cmd_element *b = *(struct cmd_element **)q;
+
+ return strcmp (a->string, b->string);
+}
+
+int
+cmp_desc (const void *p, const void *q)
+{
+ struct desc *a = *(struct desc **)p;
+ struct desc *b = *(struct desc **)q;
+
+ return strcmp (a->cmd, b->cmd);
+}
+
+/* Sort each node's command element according to command string. */
+void
+sort_node ()
+{
+ int i, j;
+ struct cmd_node *cnode;
+ vector descvec;
+ struct cmd_element *cmd_element;
+
+ for (i = 0; i < vector_max (cmdvec); i++)
+ if ((cnode = vector_slot (cmdvec, i)) != NULL)
+ {
+ vector cmd_vector = cnode->cmd_vector;
+ qsort (cmd_vector->index, cmd_vector->max, sizeof (void *), cmp_node);
+
+ for (j = 0; j < vector_max (cmd_vector); j++)
+ if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
+ {
+ descvec = vector_slot (cmd_element->strvec,
+ vector_max (cmd_element->strvec) - 1);
+ qsort (descvec->index, descvec->max, sizeof (void *), cmp_desc);
+ }
+ }
+}
+
+/* Breaking up string into each command piece. I assume given
+ character is separated by a space character. Return value is a
+ vector which includes char ** data element. */
+vector
+cmd_make_strvec (char *string)
+{
+ char *cp, *start, *token;
+ int strlen;
+ vector strvec;
+
+ if (string == NULL)
+ return NULL;
+
+ cp = string;
+
+ /* Skip white spaces. */
+ while (isspace ((int) *cp) && *cp != '\0')
+ cp++;
+
+ /* Return if there is only white spaces */
+ if (*cp == '\0')
+ return NULL;
+
+ if (*cp == '!' || *cp == '#')
+ return NULL;
+
+ /* Prepare return vector. */
+ strvec = vector_init (VECTOR_MIN_SIZE);
+
+ /* Copy each command piece and set into vector. */
+ while (1)
+ {
+ start = cp;
+ while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
+ *cp != '\0')
+ cp++;
+ strlen = cp - start;
+ token = XMALLOC (MTYPE_STRVEC, strlen + 1);
+ memcpy (token, start, strlen);
+ *(token + strlen) = '\0';
+ vector_set (strvec, token);
+
+ while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
+ *cp != '\0')
+ cp++;
+
+ if (*cp == '\0')
+ return strvec;
+ }
+}
+
+/* Free allocated string vector. */
+void
+cmd_free_strvec (vector v)
+{
+ int i;
+ char *cp;
+
+ if (!v)
+ return;
+
+ for (i = 0; i < vector_max (v); i++)
+ if ((cp = vector_slot (v, i)) != NULL)
+ XFREE (MTYPE_STRVEC, cp);
+
+ vector_free (v);
+}
+
+/* Fetch next description. Used in cmd_make_descvec(). */
+char *
+cmd_desc_str (char **string)
+{
+ char *cp, *start, *token;
+ int strlen;
+
+ cp = *string;
+
+ if (cp == NULL)
+ return NULL;
+
+ /* Skip white spaces. */
+ while (isspace ((int) *cp) && *cp != '\0')
+ cp++;
+
+ /* Return if there is only white spaces */
+ if (*cp == '\0')
+ return NULL;
+
+ start = cp;
+
+ while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
+ cp++;
+
+ strlen = cp - start;
+ token = XMALLOC (MTYPE_STRVEC, strlen + 1);
+ memcpy (token, start, strlen);
+ *(token + strlen) = '\0';
+
+ *string = cp;
+
+ return token;
+}
+
+/* New string vector. */
+vector
+cmd_make_descvec (char *string, char *descstr)
+{
+ int multiple = 0;
+ char *sp;
+ char *token;
+ int len;
+ char *cp;
+ char *dp;
+ vector allvec;
+ vector strvec = NULL;
+ struct desc *desc;
+
+ cp = string;
+ dp = descstr;
+
+ if (cp == NULL)
+ return NULL;
+
+ allvec = vector_init (VECTOR_MIN_SIZE);
+
+ while (1)
+ {
+ while (isspace ((int) *cp) && *cp != '\0')
+ cp++;
+
+ if (*cp == '(')
+ {
+ multiple = 1;
+ cp++;
+ }
+ if (*cp == ')')
+ {
+ multiple = 0;
+ cp++;
+ }
+ if (*cp == '|')
+ {
+ if (! multiple)
+ {
+ fprintf (stderr, "Command parse error!: %s\n", string);
+ exit (1);
+ }
+ cp++;
+ }
+
+ while (isspace ((int) *cp) && *cp != '\0')
+ cp++;
+
+ if (*cp == '(')
+ {
+ multiple = 1;
+ cp++;
+ }
+
+ if (*cp == '\0')
+ return allvec;
+
+ sp = cp;
+
+ while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
+ cp++;
+
+ len = cp - sp;
+
+ token = XMALLOC (MTYPE_STRVEC, len + 1);
+ memcpy (token, sp, len);
+ *(token + len) = '\0';
+
+ desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
+ desc->cmd = token;
+ desc->str = cmd_desc_str (&dp);
+
+ if (multiple)
+ {
+ if (multiple == 1)
+ {
+ strvec = vector_init (VECTOR_MIN_SIZE);
+ vector_set (allvec, strvec);
+ }
+ multiple++;
+ }
+ else
+ {
+ strvec = vector_init (VECTOR_MIN_SIZE);
+ vector_set (allvec, strvec);
+ }
+ vector_set (strvec, desc);
+ }
+}
+
+/* Count mandantory string vector size. This is to determine inputed
+ command has enough command length. */
+int
+cmd_cmdsize (vector strvec)
+{
+ int i;
+ char *str;
+ int size = 0;
+ vector descvec;
+
+ for (i = 0; i < vector_max (strvec); i++)
+ {
+ descvec = vector_slot (strvec, i);
+
+ if (vector_max (descvec) == 1)
+ {
+ struct desc *desc = vector_slot (descvec, 0);
+
+ str = desc->cmd;
+
+ if (str == NULL || CMD_OPTION (str))
+ return size;
+ else
+ size++;
+ }
+ else
+ size++;
+ }
+ return size;
+}
+
+/* Return prompt character of specified node. */
+char *
+cmd_prompt (enum node_type node)
+{
+ struct cmd_node *cnode;
+
+ cnode = vector_slot (cmdvec, node);
+ return cnode->prompt;
+}
+
+/* Install a command into a node. */
+void
+install_element (enum node_type ntype, struct cmd_element *cmd)
+{
+ struct cmd_node *cnode;
+
+ cnode = vector_slot (cmdvec, ntype);
+
+ if (cnode == NULL)
+ {
+ fprintf (stderr, "Command node %d doesn't exist, please check it\n",
+ ntype);
+ exit (1);
+ }
+
+ vector_set (cnode->cmd_vector, cmd);
+
+ cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
+ cmd->cmdsize = cmd_cmdsize (cmd->strvec);
+}
+
+static unsigned char itoa64[] =
+"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+void
+to64(char *s, long v, int n)
+{
+ while (--n >= 0)
+ {
+ *s++ = itoa64[v&0x3f];
+ v >>= 6;
+ }
+}
+
+char *zencrypt (char *passwd)
+{
+ char salt[6];
+ struct timeval tv;
+ char *crypt (const char *, const char *);
+
+ gettimeofday(&tv,0);
+
+ to64(&salt[0], random(), 3);
+ to64(&salt[3], tv.tv_usec, 3);
+ salt[5] = '\0';
+
+ return crypt (passwd, salt);
+}
+
+/* This function write configuration of this host. */
+int
+config_write_host (struct vty *vty)
+{
+ if (host.name)
+ vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
+
+ if (host.encrypt)
+ {
+ if (host.password_encrypt)
+ vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
+ if (host.enable_encrypt)
+ vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
+ }
+ else
+ {
+ if (host.password)
+ vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
+ if (host.enable)
+ vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
+ }
+
+ if (host.logfile)
+ vty_out (vty, "log file %s%s", host.logfile, VTY_NEWLINE);
+
+ if (host.log_stdout)
+ vty_out (vty, "log stdout%s", VTY_NEWLINE);
+
+ if (host.log_syslog)
+ vty_out (vty, "log syslog%s", VTY_NEWLINE);
+
+ if (zlog_default->maskpri != LOG_DEBUG)
+ vty_out (vty, "log trap %s%s", zlog_priority[zlog_default->maskpri], VTY_NEWLINE);
+
+ if (zlog_default->record_priority == 1)
+ vty_out (vty, "log record-priority%s", VTY_NEWLINE);
+
+ if (host.advanced)
+ vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
+
+ if (host.encrypt)
+ vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
+
+ if (host.lines >= 0)
+ vty_out (vty, "service terminal-length %d%s", host.lines,
+ VTY_NEWLINE);
+
+ if (! host.motd)
+ vty_out (vty, "no banner motd%s", VTY_NEWLINE);
+
+ return 1;
+}
+
+/* Utility function for getting command vector. */
+vector
+cmd_node_vector (vector v, enum node_type ntype)
+{
+ struct cmd_node *cnode = vector_slot (v, ntype);
+ return cnode->cmd_vector;
+}
+
+/* Filter command vector by symbol */
+int
+cmd_filter_by_symbol (char *command, char *symbol)
+{
+ int i, lim;
+
+ if (strcmp (symbol, "IPV4_ADDRESS") == 0)
+ {
+ i = 0;
+ lim = strlen (command);
+ while (i < lim)
+ {
+ if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
+ return 1;
+ i++;
+ }
+ return 0;
+ }
+ if (strcmp (symbol, "STRING") == 0)
+ {
+ i = 0;
+ lim = strlen (command);
+ while (i < lim)
+ {
+ if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
+ return 1;
+ i++;
+ }
+ return 0;
+ }
+ if (strcmp (symbol, "IFNAME") == 0)
+ {
+ i = 0;
+ lim = strlen (command);
+ while (i < lim)
+ {
+ if (! isalnum ((int) command[i]))
+ return 1;
+ i++;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+/* Completion match types. */
+enum match_type
+{
+ no_match,
+ extend_match,
+ ipv4_prefix_match,
+ ipv4_match,
+ ipv6_prefix_match,
+ ipv6_match,
+ range_match,
+ vararg_match,
+ partly_match,
+ exact_match
+};
+
+enum match_type
+cmd_ipv4_match (char *str)
+{
+ char *sp;
+ int dots = 0, nums = 0;
+ char buf[4];
+
+ if (str == NULL)
+ return partly_match;
+
+ for (;;)
+ {
+ memset (buf, 0, sizeof (buf));
+ sp = str;
+ while (*str != '\0')
+ {
+ if (*str == '.')
+ {
+ if (dots >= 3)
+ return no_match;
+
+ if (*(str + 1) == '.')
+ return no_match;
+
+ if (*(str + 1) == '\0')
+ return partly_match;
+
+ dots++;
+ break;
+ }
+ if (!isdigit ((int) *str))
+ return no_match;
+
+ str++;
+ }
+
+ if (str - sp > 3)
+ return no_match;
+
+ strncpy (buf, sp, str - sp);
+ if (atoi (buf) > 255)
+ return no_match;
+
+ nums++;
+
+ if (*str == '\0')
+ break;
+
+ str++;
+ }
+
+ if (nums < 4)
+ return partly_match;
+
+ return exact_match;
+}
+
+enum match_type
+cmd_ipv4_prefix_match (char *str)
+{
+ char *sp;
+ int dots = 0;
+ char buf[4];
+
+ if (str == NULL)
+ return partly_match;
+
+ for (;;)
+ {
+ memset (buf, 0, sizeof (buf));
+ sp = str;
+ while (*str != '\0' && *str != '/')
+ {
+ if (*str == '.')
+ {
+ if (dots == 3)
+ return no_match;
+
+ if (*(str + 1) == '.' || *(str + 1) == '/')
+ return no_match;
+
+ if (*(str + 1) == '\0')
+ return partly_match;
+
+ dots++;
+ break;
+ }
+
+ if (!isdigit ((int) *str))
+ return no_match;
+
+ str++;
+ }
+
+ if (str - sp > 3)
+ return no_match;
+
+ strncpy (buf, sp, str - sp);
+ if (atoi (buf) > 255)
+ return no_match;
+
+ if (dots == 3)
+ {
+ if (*str == '/')
+ {
+ if (*(str + 1) == '\0')
+ return partly_match;
+
+ str++;
+ break;
+ }
+ else if (*str == '\0')
+ return partly_match;
+ }
+
+ if (*str == '\0')
+ return partly_match;
+
+ str++;
+ }
+
+ sp = str;
+ while (*str != '\0')
+ {
+ if (!isdigit ((int) *str))
+ return no_match;
+
+ str++;
+ }
+
+ if (atoi (sp) > 32)
+ return no_match;
+
+ return exact_match;
+}
+
+#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
+#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
+#define STATE_START 1
+#define STATE_COLON 2
+#define STATE_DOUBLE 3
+#define STATE_ADDR 4
+#define STATE_DOT 5
+#define STATE_SLASH 6
+#define STATE_MASK 7
+
+enum match_type
+cmd_ipv6_match (char *str)
+{
+ int state = STATE_START;
+ int colons = 0, nums = 0, double_colon = 0;
+ char *sp = NULL;
+
+ if (str == NULL)
+ return partly_match;
+
+ if (strspn (str, IPV6_ADDR_STR) != strlen (str))
+ return no_match;
+
+ while (*str != '\0')
+ {
+ switch (state)
+ {
+ case STATE_START:
+ if (*str == ':')
+ {
+ if (*(str + 1) != ':' && *(str + 1) != '\0')
+ return no_match;
+ colons--;
+ state = STATE_COLON;
+ }
+ else
+ {
+ sp = str;
+ state = STATE_ADDR;
+ }
+
+ continue;
+ case STATE_COLON:
+ colons++;
+ if (*(str + 1) == ':')
+ state = STATE_DOUBLE;
+ else
+ {
+ sp = str + 1;
+ state = STATE_ADDR;
+ }
+ break;
+ case STATE_DOUBLE:
+ if (double_colon)
+ return no_match;
+
+ if (*(str + 1) == ':')
+ return no_match;
+ else
+ {
+ if (*(str + 1) != '\0')
+ colons++;
+ sp = str + 1;
+ state = STATE_ADDR;
+ }
+
+ double_colon++;
+ nums++;
+ break;
+ case STATE_ADDR:
+ if (*(str + 1) == ':' || *(str + 1) == '\0')
+ {
+ if (str - sp > 3)
+ return no_match;
+
+ nums++;
+ state = STATE_COLON;
+ }
+ if (*(str + 1) == '.')
+ state = STATE_DOT;
+ break;
+ case STATE_DOT:
+ state = STATE_ADDR;
+ break;
+ default:
+ break;
+ }
+
+ if (nums > 8)
+ return no_match;
+
+ if (colons > 7)
+ return no_match;
+
+ str++;
+ }
+
+#if 0
+ if (nums < 11)
+ return partly_match;
+#endif /* 0 */
+
+ return exact_match;
+}
+
+enum match_type
+cmd_ipv6_prefix_match (char *str)
+{
+ int state = STATE_START;
+ int colons = 0, nums = 0, double_colon = 0;
+ int mask;
+ char *sp = NULL;
+ char *endptr = NULL;
+
+ if (str == NULL)
+ return partly_match;
+
+ if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
+ return no_match;
+
+ while (*str != '\0' && state != STATE_MASK)
+ {
+ switch (state)
+ {
+ case STATE_START:
+ if (*str == ':')
+ {
+ if (*(str + 1) != ':' && *(str + 1) != '\0')
+ return no_match;
+ colons--;
+ state = STATE_COLON;
+ }
+ else
+ {
+ sp = str;
+ state = STATE_ADDR;
+ }
+
+ continue;
+ case STATE_COLON:
+ colons++;
+ if (*(str + 1) == '/')
+ return no_match;
+ else if (*(str + 1) == ':')
+ state = STATE_DOUBLE;
+ else
+ {
+ sp = str + 1;
+ state = STATE_ADDR;
+ }
+ break;
+ case STATE_DOUBLE:
+ if (double_colon)
+ return no_match;
+
+ if (*(str + 1) == ':')
+ return no_match;
+ else
+ {
+ if (*(str + 1) != '\0' && *(str + 1) != '/')
+ colons++;
+ sp = str + 1;
+
+ if (*(str + 1) == '/')
+ state = STATE_SLASH;
+ else
+ state = STATE_ADDR;
+ }
+
+ double_colon++;
+ nums += 1;
+ break;
+ case STATE_ADDR:
+ if (*(str + 1) == ':' || *(str + 1) == '.'
+ || *(str + 1) == '\0' || *(str + 1) == '/')
+ {
+ if (str - sp > 3)
+ return no_match;
+
+ for (; sp <= str; sp++)
+ if (*sp == '/')
+ return no_match;
+
+ nums++;
+
+ if (*(str + 1) == ':')
+ state = STATE_COLON;
+ else if (*(str + 1) == '.')
+ state = STATE_DOT;
+ else if (*(str + 1) == '/')
+ state = STATE_SLASH;
+ }
+ break;
+ case STATE_DOT:
+ state = STATE_ADDR;
+ break;
+ case STATE_SLASH:
+ if (*(str + 1) == '\0')
+ return partly_match;
+
+ state = STATE_MASK;
+ break;
+ default:
+ break;
+ }
+
+ if (nums > 11)
+ return no_match;
+
+ if (colons > 7)
+ return no_match;
+
+ str++;
+ }
+
+ if (state < STATE_MASK)
+ return partly_match;
+
+ mask = strtol (str, &endptr, 10);
+ if (*endptr != '\0')
+ return no_match;
+
+ if (mask < 0 || mask > 128)
+ return no_match;
+
+/* I don't know why mask < 13 makes command match partly.
+ Forgive me to make this comments. I Want to set static default route
+ because of lack of function to originate default in ospf6d; sorry
+ yasu
+ if (mask < 13)
+ return partly_match;
+*/
+
+ return exact_match;
+}
+
+#define DECIMAL_STRLEN_MAX 10
+
+int
+cmd_range_match (char *range, char *str)
+{
+ char *p;
+ char buf[DECIMAL_STRLEN_MAX + 1];
+ char *endptr = NULL;
+ unsigned long min, max, val;
+
+ if (str == NULL)
+ return 1;
+
+ val = strtoul (str, &endptr, 10);
+ if (*endptr != '\0')
+ return 0;
+
+ range++;
+ p = strchr (range, '-');
+ if (p == NULL)
+ return 0;
+ if (p - range > DECIMAL_STRLEN_MAX)
+ return 0;
+ strncpy (buf, range, p - range);
+ buf[p - range] = '\0';
+ min = strtoul (buf, &endptr, 10);
+ if (*endptr != '\0')
+ return 0;
+
+ range = p + 1;
+ p = strchr (range, '>');
+ if (p == NULL)
+ return 0;
+ if (p - range > DECIMAL_STRLEN_MAX)
+ return 0;
+ strncpy (buf, range, p - range);
+ buf[p - range] = '\0';
+ max = strtoul (buf, &endptr, 10);
+ if (*endptr != '\0')
+ return 0;
+
+ if (val < min || val > max)
+ return 0;
+
+ return 1;
+}
+
+/* Make completion match and return match type flag. */
+enum match_type
+cmd_filter_by_completion (char *command, vector v, int index)
+{
+ int i;
+ char *str;
+ struct cmd_element *cmd_element;
+ enum match_type match_type;
+ vector descvec;
+ struct desc *desc;
+
+ match_type = no_match;
+
+ /* If command and cmd_element string does not match set NULL to vector */
+ for (i = 0; i < vector_max (v); i++)
+ if ((cmd_element = vector_slot (v, i)) != NULL)
+ {
+ if (index >= vector_max (cmd_element->strvec))
+ vector_slot (v, i) = NULL;
+ else
+ {
+ int j;
+ int matched = 0;
+
+ descvec = vector_slot (cmd_element->strvec, index);
+
+ for (j = 0; j < vector_max (descvec); j++)
+ {
+ desc = vector_slot (descvec, j);
+ str = desc->cmd;
+
+ if (CMD_VARARG (str))
+ {
+ if (match_type < vararg_match)
+ match_type = vararg_match;
+ matched++;
+ }
+ else if (CMD_RANGE (str))
+ {
+ if (cmd_range_match (str, command))
+ {
+ if (match_type < range_match)
+ match_type = range_match;
+
+ matched++;
+ }
+ }
+ else if (CMD_IPV6 (str))
+ {
+ if (cmd_ipv6_match (command))
+ {
+ if (match_type < ipv6_match)
+ match_type = ipv6_match;
+
+ matched++;
+ }
+ }
+ else if (CMD_IPV6_PREFIX (str))
+ {
+ if (cmd_ipv6_prefix_match (command))
+ {
+ if (match_type < ipv6_prefix_match)
+ match_type = ipv6_prefix_match;
+
+ matched++;
+ }
+ }
+ else if (CMD_IPV4 (str))
+ {
+ if (cmd_ipv4_match (command))
+ {
+ if (match_type < ipv4_match)
+ match_type = ipv4_match;
+
+ matched++;
+ }
+ }
+ else if (CMD_IPV4_PREFIX (str))
+ {
+ if (cmd_ipv4_prefix_match (command))
+ {
+ if (match_type < ipv4_prefix_match)
+ match_type = ipv4_prefix_match;
+ matched++;
+ }
+ }
+ else
+ /* Check is this point's argument optional ? */
+ if (CMD_OPTION (str) || CMD_VARIABLE (str))
+ {
+ if (match_type < extend_match)
+ match_type = extend_match;
+ matched++;
+ }
+ else if (strncmp (command, str, strlen (command)) == 0)
+ {
+ if (strcmp (command, str) == 0)
+ match_type = exact_match;
+ else
+ {
+ if (match_type < partly_match)
+ match_type = partly_match;
+ }
+ matched++;
+ }
+ }
+ if (! matched)
+ vector_slot (v, i) = NULL;
+ }
+ }
+ return match_type;
+}
+
+/* Filter vector by command character with index. */
+enum match_type
+cmd_filter_by_string (char *command, vector v, int index)
+{
+ int i;
+ char *str;
+ struct cmd_element *cmd_element;
+ enum match_type match_type;
+ vector descvec;
+ struct desc *desc;
+
+ match_type = no_match;
+
+ /* If command and cmd_element string does not match set NULL to vector */
+ for (i = 0; i < vector_max (v); i++)
+ if ((cmd_element = vector_slot (v, i)) != NULL)
+ {
+ /* If given index is bigger than max string vector of command,
+ set NULL*/
+ if (index >= vector_max (cmd_element->strvec))
+ vector_slot (v, i) = NULL;
+ else
+ {
+ int j;
+ int matched = 0;
+
+ descvec = vector_slot (cmd_element->strvec, index);
+
+ for (j = 0; j < vector_max (descvec); j++)
+ {
+ desc = vector_slot (descvec, j);
+ str = desc->cmd;
+
+ if (CMD_VARARG (str))
+ {
+ if (match_type < vararg_match)
+ match_type = vararg_match;
+ matched++;
+ }
+ else if (CMD_RANGE (str))
+ {
+ if (cmd_range_match (str, command))
+ {
+ if (match_type < range_match)
+ match_type = range_match;
+ matched++;
+ }
+ }
+ else if (CMD_IPV6 (str))
+ {
+ if (cmd_ipv6_match (command) == exact_match)
+ {
+ if (match_type < ipv6_match)
+ match_type = ipv6_match;
+ matched++;
+ }
+ }
+ else if (CMD_IPV6_PREFIX (str))
+ {
+ if (cmd_ipv6_prefix_match (command) == exact_match)
+ {
+ if (match_type < ipv6_prefix_match)
+ match_type = ipv6_prefix_match;
+ matched++;
+ }
+ }
+ else if (CMD_IPV4 (str))
+ {
+ if (cmd_ipv4_match (command) == exact_match)
+ {
+ if (match_type < ipv4_match)
+ match_type = ipv4_match;
+ matched++;
+ }
+ }
+ else if (CMD_IPV4_PREFIX (str))
+ {
+ if (cmd_ipv4_prefix_match (command) == exact_match)
+ {
+ if (match_type < ipv4_prefix_match)
+ match_type = ipv4_prefix_match;
+ matched++;
+ }
+ }
+ else if (CMD_OPTION (str) || CMD_VARIABLE (str))
+ {
+ if (match_type < extend_match)
+ match_type = extend_match;
+ matched++;
+ }
+ else
+ {
+ if (strcmp (command, str) == 0)
+ {
+ match_type = exact_match;
+ matched++;
+ }
+ }
+ }
+ if (! matched)
+ vector_slot (v, i) = NULL;
+ }
+ }
+ return match_type;
+}
+
+/* Check ambiguous match */
+int
+is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
+{
+ int i;
+ int j;
+ char *str = NULL;
+ struct cmd_element *cmd_element;
+ char *matched = NULL;
+ vector descvec;
+ struct desc *desc;
+
+ for (i = 0; i < vector_max (v); i++)
+ if ((cmd_element = vector_slot (v, i)) != NULL)
+ {
+ int match = 0;
+
+ descvec = vector_slot (cmd_element->strvec, index);
+
+ for (j = 0; j < vector_max (descvec); j++)
+ {
+ enum match_type ret;
+
+ desc = vector_slot (descvec, j);
+ str = desc->cmd;
+
+ switch (type)
+ {
+ case exact_match:
+ if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
+ && strcmp (command, str) == 0)
+ match++;
+ break;
+ case partly_match:
+ if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
+ && strncmp (command, str, strlen (command)) == 0)
+ {
+ if (matched && strcmp (matched, str) != 0)
+ return 1; /* There is ambiguous match. */
+ else
+ matched = str;
+ match++;
+ }
+ break;
+ case range_match:
+ if (cmd_range_match (str, command))
+ {
+ if (matched && strcmp (matched, str) != 0)
+ return 1;
+ else
+ matched = str;
+ match++;
+ }
+ break;
+ case ipv6_match:
+ if (CMD_IPV6 (str))
+ match++;
+ break;
+ case ipv6_prefix_match:
+ if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
+ {
+ if (ret == partly_match)
+ return 2; /* There is incomplete match. */
+
+ match++;
+ }
+ break;
+ case ipv4_match:
+ if (CMD_IPV4 (str))
+ match++;
+ break;
+ case ipv4_prefix_match:
+ if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
+ {
+ if (ret == partly_match)
+ return 2; /* There is incomplete match. */
+
+ match++;
+ }
+ break;
+ case extend_match:
+ if (CMD_OPTION (str) || CMD_VARIABLE (str))
+ match++;
+ break;
+ case no_match:
+ default:
+ break;
+ }
+ }
+ if (! match)
+ vector_slot (v, i) = NULL;
+ }
+ return 0;
+}
+
+/* If src matches dst return dst string, otherwise return NULL */
+char *
+cmd_entry_function (char *src, char *dst)
+{
+ /* Skip variable arguments. */
+ if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
+ CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
+ return NULL;
+
+ /* In case of 'command \t', given src is NULL string. */
+ if (src == NULL)
+ return dst;
+
+ /* Matched with input string. */
+ if (strncmp (src, dst, strlen (src)) == 0)
+ return dst;
+
+ return NULL;
+}
+
+/* If src matches dst return dst string, otherwise return NULL */
+/* This version will return the dst string always if it is
+ CMD_VARIABLE for '?' key processing */
+char *
+cmd_entry_function_desc (char *src, char *dst)
+{
+ if (CMD_VARARG (dst))
+ return dst;
+
+ if (CMD_RANGE (dst))
+ {
+ if (cmd_range_match (dst, src))
+ return dst;
+ else
+ return NULL;
+ }
+
+ if (CMD_IPV6 (dst))
+ {
+ if (cmd_ipv6_match (src))
+ return dst;
+ else
+ return NULL;
+ }
+
+ if (CMD_IPV6_PREFIX (dst))
+ {
+ if (cmd_ipv6_prefix_match (src))
+ return dst;
+ else
+ return NULL;
+ }
+
+ if (CMD_IPV4 (dst))
+ {
+ if (cmd_ipv4_match (src))
+ return dst;
+ else
+ return NULL;
+ }
+
+ if (CMD_IPV4_PREFIX (dst))
+ {
+ if (cmd_ipv4_prefix_match (src))
+ return dst;
+ else
+ return NULL;
+ }
+
+ /* Optional or variable commands always match on '?' */
+ if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
+ return dst;
+
+ /* In case of 'command \t', given src is NULL string. */
+ if (src == NULL)
+ return dst;
+
+ if (strncmp (src, dst, strlen (src)) == 0)
+ return dst;
+ else
+ return NULL;
+}
+
+/* Check same string element existence. If it isn't there return
+ 1. */
+int
+cmd_unique_string (vector v, char *str)
+{
+ int i;
+ char *match;
+
+ for (i = 0; i < vector_max (v); i++)
+ if ((match = vector_slot (v, i)) != NULL)
+ if (strcmp (match, str) == 0)
+ return 0;
+ return 1;
+}
+
+/* Compare string to description vector. If there is same string
+ return 1 else return 0. */
+int
+desc_unique_string (vector v, char *str)
+{
+ int i;
+ struct desc *desc;
+
+ for (i = 0; i < vector_max (v); i++)
+ if ((desc = vector_slot (v, i)) != NULL)
+ if (strcmp (desc->cmd, str) == 0)
+ return 1;
+ return 0;
+}
+
+/* '?' describe command support. */
+vector
+cmd_describe_command (vector vline, struct vty *vty, int *status)
+{
+ int i;
+ vector cmd_vector;
+#define INIT_MATCHVEC_SIZE 10
+ vector matchvec;
+ struct cmd_element *cmd_element;
+ int index;
+ static struct desc desc_cr = { "<cr>", "" };
+
+ /* Set index. */
+ index = vector_max (vline) - 1;
+
+ /* Make copy vector of current node's command vector. */
+ cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+
+ /* Prepare match vector */
+ matchvec = vector_init (INIT_MATCHVEC_SIZE);
+
+ /* Filter commands. */
+ for (i = 0; i < index; i++)
+ {
+ enum match_type match;
+ char *command;
+ int ret;
+
+ command = vector_slot (vline, i);
+
+ match = cmd_filter_by_completion (command, cmd_vector, i);
+
+ if (match == vararg_match)
+ {
+ struct cmd_element *cmd_element;
+ vector descvec;
+ int j, k;
+
+ for (j = 0; j < vector_max (cmd_vector); j++)
+ if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
+ {
+ descvec = vector_slot (cmd_element->strvec,
+ vector_max (cmd_element->strvec) - 1);
+ for (k = 0; k < vector_max (descvec); k++)
+ {
+ struct desc *desc = vector_slot (descvec, k);
+ vector_set (matchvec, desc);
+ }
+ }
+
+ vector_set (matchvec, &desc_cr);
+
+ vector_free (cmd_vector);
+
+ return matchvec;
+ }
+
+ if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
+ {
+ vector_free (cmd_vector);
+ *status = CMD_ERR_AMBIGUOUS;
+ return NULL;
+ }
+ else if (ret == 2)
+ {
+ vector_free (cmd_vector);
+ *status = CMD_ERR_NO_MATCH;
+ return NULL;
+ }
+ }
+
+ /* Prepare match vector */
+ /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
+
+ /* Make description vector. */
+ for (i = 0; i < vector_max (cmd_vector); i++)
+ if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
+ {
+ char *string = NULL;
+ vector strvec = cmd_element->strvec;
+
+ if (index > vector_max (strvec))
+ vector_slot (cmd_vector, i) = NULL;
+ else
+ {
+ /* Check is command is completed. */
+ if (index == vector_max (strvec))
+ {
+ string = "<cr>";
+ if (! desc_unique_string (matchvec, string))
+ vector_set (matchvec, &desc_cr);
+ }
+ else
+ {
+ int j;
+ vector descvec = vector_slot (strvec, index);
+ struct desc *desc;
+
+ for (j = 0; j < vector_max (descvec); j++)
+ {
+ desc = vector_slot (descvec, j);
+ string = cmd_entry_function_desc (vector_slot (vline, index), desc->cmd);
+ if (string)
+ {
+ /* Uniqueness check */
+ if (! desc_unique_string (matchvec, string))
+ vector_set (matchvec, desc);
+ }
+ }
+ }
+ }
+ }
+ vector_free (cmd_vector);
+
+ if (vector_slot (matchvec, 0) == NULL)
+ {
+ vector_free (matchvec);
+ *status= CMD_ERR_NO_MATCH;
+ }
+ else
+ *status = CMD_SUCCESS;
+
+ return matchvec;
+}
+
+/* Check LCD of matched command. */
+int
+cmd_lcd (char **matched)
+{
+ int i;
+ int j;
+ int lcd = -1;
+ char *s1, *s2;
+ char c1, c2;
+
+ if (matched[0] == NULL || matched[1] == NULL)
+ return 0;
+
+ for (i = 1; matched[i] != NULL; i++)
+ {
+ s1 = matched[i - 1];
+ s2 = matched[i];
+
+ for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
+ if (c1 != c2)
+ break;
+
+ if (lcd < 0)
+ lcd = j;
+ else
+ {
+ if (lcd > j)
+ lcd = j;
+ }
+ }
+ return lcd;
+}
+
+/* Command line completion support. */
+char **
+cmd_complete_command (vector vline, struct vty *vty, int *status)
+{
+ int i;
+ vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+#define INIT_MATCHVEC_SIZE 10
+ vector matchvec;
+ struct cmd_element *cmd_element;
+ int index = vector_max (vline) - 1;
+ char **match_str;
+ struct desc *desc;
+ vector descvec;
+ char *command;
+ int lcd;
+
+ /* First, filter by preceeding command string */
+ for (i = 0; i < index; i++)
+ {
+ enum match_type match;
+ int ret;
+
+ command = vector_slot (vline, i);
+
+ /* First try completion match, if there is exactly match return 1 */
+ match = cmd_filter_by_completion (command, cmd_vector, i);
+
+ /* If there is exact match then filter ambiguous match else check
+ ambiguousness. */
+ if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
+ {
+ vector_free (cmd_vector);
+ *status = CMD_ERR_AMBIGUOUS;
+ return NULL;
+ }
+ /*
+ else if (ret == 2)
+ {
+ vector_free (cmd_vector);
+ *status = CMD_ERR_NO_MATCH;
+ return NULL;
+ }
+ */
+ }
+
+ /* Prepare match vector. */
+ matchvec = vector_init (INIT_MATCHVEC_SIZE);
+
+ /* Now we got into completion */
+ for (i = 0; i < vector_max (cmd_vector); i++)
+ if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
+ {
+ char *string;
+ vector strvec = cmd_element->strvec;
+
+ /* Check field length */
+ if (index >= vector_max (strvec))
+ vector_slot (cmd_vector, i) = NULL;
+ else
+ {
+ int j;
+
+ descvec = vector_slot (strvec, index);
+ for (j = 0; j < vector_max (descvec); j++)
+ {
+ desc = vector_slot (descvec, j);
+
+ if ((string = cmd_entry_function (vector_slot (vline, index),
+ desc->cmd)))
+ if (cmd_unique_string (matchvec, string))
+ vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
+ }
+ }
+ }
+
+ /* We don't need cmd_vector any more. */
+ vector_free (cmd_vector);
+
+ /* No matched command */
+ if (vector_slot (matchvec, 0) == NULL)
+ {
+ vector_free (matchvec);
+
+ /* In case of 'command \t' pattern. Do you need '?' command at
+ the end of the line. */
+ if (vector_slot (vline, index) == '\0')
+ *status = CMD_ERR_NOTHING_TODO;
+ else
+ *status = CMD_ERR_NO_MATCH;
+ return NULL;
+ }
+
+ /* Only one matched */
+ if (vector_slot (matchvec, 1) == NULL)
+ {
+ match_str = (char **) matchvec->index;
+ vector_only_wrapper_free (matchvec);
+ *status = CMD_COMPLETE_FULL_MATCH;
+ return match_str;
+ }
+ /* Make it sure last element is NULL. */
+ vector_set (matchvec, NULL);
+
+ /* Check LCD of matched strings. */
+ if (vector_slot (vline, index) != NULL)
+ {
+ lcd = cmd_lcd ((char **) matchvec->index);
+
+ if (lcd)
+ {
+ int len = strlen (vector_slot (vline, index));
+
+ if (len < lcd)
+ {
+ char *lcdstr;
+
+ lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
+ memcpy (lcdstr, matchvec->index[0], lcd);
+ lcdstr[lcd] = '\0';
+
+ /* match_str = (char **) &lcdstr; */
+
+ /* Free matchvec. */
+ for (i = 0; i < vector_max (matchvec); i++)
+ {
+ if (vector_slot (matchvec, i))
+ XFREE (MTYPE_TMP, vector_slot (matchvec, i));
+ }
+ vector_free (matchvec);
+
+ /* Make new matchvec. */
+ matchvec = vector_init (INIT_MATCHVEC_SIZE);
+ vector_set (matchvec, lcdstr);
+ match_str = (char **) matchvec->index;
+ vector_only_wrapper_free (matchvec);
+
+ *status = CMD_COMPLETE_MATCH;
+ return match_str;
+ }
+ }
+ }
+
+ match_str = (char **) matchvec->index;
+ vector_only_wrapper_free (matchvec);
+ *status = CMD_COMPLETE_LIST_MATCH;
+ return match_str;
+}
+
+/* Execute command by argument vline vector. */
+int
+cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd)
+{
+ int i;
+ int index;
+ vector cmd_vector;
+ struct cmd_element *cmd_element;
+ struct cmd_element *matched_element;
+ unsigned int matched_count, incomplete_count;
+ int argc;
+ char *argv[CMD_ARGC_MAX];
+ enum match_type match = 0;
+ int varflag;
+ char *command;
+
+ /* Make copy of command elements. */
+ cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+
+ for (index = 0; index < vector_max (vline); index++)
+ {
+ int ret;
+
+ command = vector_slot (vline, index);
+
+ match = cmd_filter_by_completion (command, cmd_vector, index);
+
+ if (match == vararg_match)
+ break;
+
+ ret = is_cmd_ambiguous (command, cmd_vector, index, match);
+
+ if (ret == 1)
+ {
+ vector_free (cmd_vector);
+ return CMD_ERR_AMBIGUOUS;
+ }
+ else if (ret == 2)
+ {
+ vector_free (cmd_vector);
+ return CMD_ERR_NO_MATCH;
+ }
+ }
+
+ /* Check matched count. */
+ matched_element = NULL;
+ matched_count = 0;
+ incomplete_count = 0;
+
+ for (i = 0; i < vector_max (cmd_vector); i++)
+ if (vector_slot (cmd_vector,i) != NULL)
+ {
+ cmd_element = vector_slot (cmd_vector,i);
+
+ if (match == vararg_match || index >= cmd_element->cmdsize)
+ {
+ matched_element = cmd_element;
+#if 0
+ printf ("DEBUG: %s\n", cmd_element->string);
+#endif
+ matched_count++;
+ }
+ else
+ {
+ incomplete_count++;
+ }
+ }
+
+ /* Finish of using cmd_vector. */
+ vector_free (cmd_vector);
+
+ /* To execute command, matched_count must be 1.*/
+ if (matched_count == 0)
+ {
+ if (incomplete_count)
+ return CMD_ERR_INCOMPLETE;
+ else
+ return CMD_ERR_NO_MATCH;
+ }
+
+ if (matched_count > 1)
+ return CMD_ERR_AMBIGUOUS;
+
+ /* Argument treatment */
+ varflag = 0;
+ argc = 0;
+
+ for (i = 0; i < vector_max (vline); i++)
+ {
+ if (varflag)
+ argv[argc++] = vector_slot (vline, i);
+ else
+ {
+ vector descvec = vector_slot (matched_element->strvec, i);
+
+ if (vector_max (descvec) == 1)
+ {
+ struct desc *desc = vector_slot (descvec, 0);
+ char *str = desc->cmd;
+
+ if (CMD_VARARG (str))
+ varflag = 1;
+
+ if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str))
+ argv[argc++] = vector_slot (vline, i);
+ }
+ else
+ argv[argc++] = vector_slot (vline, i);
+ }
+
+ if (argc >= CMD_ARGC_MAX)
+ return CMD_ERR_EXEED_ARGC_MAX;
+ }
+
+ /* For vtysh execution. */
+ if (cmd)
+ *cmd = matched_element;
+
+ if (matched_element->daemon)
+ return CMD_SUCCESS_DAEMON;
+
+ /* Execute matched command. */
+ return (*matched_element->func) (matched_element, vty, argc, argv);
+}
+
+/* Execute command by argument readline. */
+int
+cmd_execute_command_strict (vector vline, struct vty *vty,
+ struct cmd_element **cmd)
+{
+ int i;
+ int index;
+ vector cmd_vector;
+ struct cmd_element *cmd_element;
+ struct cmd_element *matched_element;
+ unsigned int matched_count, incomplete_count;
+ int argc;
+ char *argv[CMD_ARGC_MAX];
+ int varflag;
+ enum match_type match = 0;
+ char *command;
+
+ /* Make copy of command element */
+ cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+
+ for (index = 0; index < vector_max (vline); index++)
+ {
+ int ret;
+
+ command = vector_slot (vline, index);
+
+ match = cmd_filter_by_string (vector_slot (vline, index),
+ cmd_vector, index);
+
+ /* If command meets '.VARARG' then finish matching. */
+ if (match == vararg_match)
+ break;
+
+ ret = is_cmd_ambiguous (command, cmd_vector, index, match);
+ if (ret == 1)
+ {
+ vector_free (cmd_vector);
+ return CMD_ERR_AMBIGUOUS;
+ }
+ if (ret == 2)
+ {
+ vector_free (cmd_vector);
+ return CMD_ERR_NO_MATCH;
+ }
+ }
+
+ /* Check matched count. */
+ matched_element = NULL;
+ matched_count = 0;
+ incomplete_count = 0;
+ for (i = 0; i < vector_max (cmd_vector); i++)
+ if (vector_slot (cmd_vector,i) != NULL)
+ {
+ cmd_element = vector_slot (cmd_vector,i);
+
+ if (match == vararg_match || index >= cmd_element->cmdsize)
+ {
+ matched_element = cmd_element;
+ matched_count++;
+ }
+ else
+ incomplete_count++;
+ }
+
+ /* Finish of using cmd_vector. */
+ vector_free (cmd_vector);
+
+ /* To execute command, matched_count must be 1.*/
+ if (matched_count == 0)
+ {
+ if (incomplete_count)
+ return CMD_ERR_INCOMPLETE;
+ else
+ return CMD_ERR_NO_MATCH;
+ }
+
+ if (matched_count > 1)
+ return CMD_ERR_AMBIGUOUS;
+
+ /* Argument treatment */
+ varflag = 0;
+ argc = 0;
+
+ for (i = 0; i < vector_max (vline); i++)
+ {
+ if (varflag)
+ argv[argc++] = vector_slot (vline, i);
+ else
+ {
+ vector descvec = vector_slot (matched_element->strvec, i);
+
+ if (vector_max (descvec) == 1)
+ {
+ struct desc *desc = vector_slot (descvec, 0);
+ char *str = desc->cmd;
+
+ if (CMD_VARARG (str))
+ varflag = 1;
+
+ if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str))
+ argv[argc++] = vector_slot (vline, i);
+ }
+ else
+ argv[argc++] = vector_slot (vline, i);
+ }
+
+ if (argc >= CMD_ARGC_MAX)
+ return CMD_ERR_EXEED_ARGC_MAX;
+ }
+
+ /* For vtysh execution. */
+ if (cmd)
+ *cmd = matched_element;
+
+ if (matched_element->daemon)
+ return CMD_SUCCESS_DAEMON;
+
+ /* Now execute matched command */
+ return (*matched_element->func) (matched_element, vty, argc, argv);
+}
+
+/* Configration make from file. */
+int
+config_from_file (struct vty *vty, FILE *fp)
+{
+ int ret;
+ vector vline;
+
+ while (fgets (vty->buf, VTY_BUFSIZ, fp))
+ {
+ vline = cmd_make_strvec (vty->buf);
+
+ /* In case of comment line */
+ if (vline == NULL)
+ continue;
+ /* Execute configuration command : this is strict match */
+ ret = cmd_execute_command_strict (vline, vty, NULL);
+
+ /* Try again with setting node to CONFIG_NODE */
+ if (ret != CMD_SUCCESS && ret != CMD_WARNING)
+ {
+ if (vty->node == KEYCHAIN_KEY_NODE)
+ {
+ vty->node = KEYCHAIN_NODE;
+
+ ret = cmd_execute_command_strict (vline, vty, NULL);
+
+ if (ret != CMD_SUCCESS && ret != CMD_WARNING)
+ {
+ vty->node = CONFIG_NODE;
+ ret = cmd_execute_command_strict (vline, vty, NULL);
+ }
+ }
+ else
+ {
+ vty->node = CONFIG_NODE;
+ ret = cmd_execute_command_strict (vline, vty, NULL);
+ }
+ }
+
+ cmd_free_strvec (vline);
+
+ if (ret != CMD_SUCCESS && ret != CMD_WARNING)
+ return ret;
+ }
+ return CMD_SUCCESS;
+}
+
+/* Configration from terminal */
+DEFUN (config_terminal,
+ config_terminal_cmd,
+ "configure terminal",
+ "Configuration from vty interface\n"
+ "Configuration terminal\n")
+{
+ if (vty_config_lock (vty))
+ vty->node = CONFIG_NODE;
+ else
+ {
+ vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
+/* Enable command */
+DEFUN (enable,
+ config_enable_cmd,
+ "enable",
+ "Turn on privileged mode command\n")
+{
+ /* If enable password is NULL, change to ENABLE_NODE */
+ if ((host.enable == NULL && host.enable_encrypt == NULL) ||
+ vty->type == VTY_SHELL_SERV)
+ vty->node = ENABLE_NODE;
+ else
+ vty->node = AUTH_ENABLE_NODE;
+
+ return CMD_SUCCESS;
+}
+
+/* Disable command */
+DEFUN (disable,
+ config_disable_cmd,
+ "disable",
+ "Turn off privileged mode command\n")
+{
+ if (vty->node == ENABLE_NODE)
+ vty->node = VIEW_NODE;
+ return CMD_SUCCESS;
+}
+
+/* Down vty node level. */
+DEFUN (config_exit,
+ config_exit_cmd,
+ "exit",
+ "Exit current mode and down to previous mode\n")
+{
+ switch (vty->node)
+ {
+ case VIEW_NODE:
+ case ENABLE_NODE:
+ if (vty_shell (vty))
+ exit (0);
+ else
+ vty->status = VTY_CLOSE;
+ break;
+ case CONFIG_NODE:
+ vty->node = ENABLE_NODE;
+ vty_config_unlock (vty);
+ break;
+ case INTERFACE_NODE:
+ case ZEBRA_NODE:
+ case BGP_NODE:
+ case RIP_NODE:
+ case RIPNG_NODE:
+ case OSPF_NODE:
+ case OSPF6_NODE:
+ case KEYCHAIN_NODE:
+ case MASC_NODE:
+ case RMAP_NODE:
+ case VTY_NODE:
+ vty->node = CONFIG_NODE;
+ break;
+ case BGP_VPNV4_NODE:
+ case BGP_IPV4_NODE:
+ case BGP_IPV4M_NODE:
+ case BGP_IPV6_NODE:
+ vty->node = BGP_NODE;
+ break;
+ case KEYCHAIN_KEY_NODE:
+ vty->node = KEYCHAIN_NODE;
+ break;
+ default:
+ break;
+ }
+ return CMD_SUCCESS;
+}
+
+/* quit is alias of exit. */
+ALIAS (config_exit,
+ config_quit_cmd,
+ "quit",
+ "Exit current mode and down to previous mode\n")
+
+/* End of configuration. */
+DEFUN (config_end,
+ config_end_cmd,
+ "end",
+ "End current mode and change to enable mode.")
+{
+ switch (vty->node)
+ {
+ case VIEW_NODE:
+ case ENABLE_NODE:
+ /* Nothing to do. */
+ break;
+ case CONFIG_NODE:
+ case INTERFACE_NODE:
+ case ZEBRA_NODE:
+ case RIP_NODE:
+ case RIPNG_NODE:
+ case BGP_NODE:
+ case BGP_VPNV4_NODE:
+ case BGP_IPV4_NODE:
+ case BGP_IPV4M_NODE:
+ case BGP_IPV6_NODE:
+ case RMAP_NODE:
+ case OSPF_NODE:
+ case OSPF6_NODE:
+ case KEYCHAIN_NODE:
+ case KEYCHAIN_KEY_NODE:
+ case MASC_NODE:
+ case VTY_NODE:
+ vty_config_unlock (vty);
+ vty->node = ENABLE_NODE;
+ break;
+ default:
+ break;
+ }
+ return CMD_SUCCESS;
+}
+
+/* Show version. */
+DEFUN (show_version,
+ show_version_cmd,
+ "show version",
+ SHOW_STR
+ "Displays zebra version\n")
+{
+ vty_out (vty, "Zebra %s (%s).%s", ZEBRA_VERSION,
+ host_name,
+ VTY_NEWLINE);
+ vty_out (vty, "Copyright 1996-2002, Kunihiro Ishiguro.%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+/* Help display function for all node. */
+DEFUN (config_help,
+ config_help_cmd,
+ "help",
+ "Description of the interactive help system\n")
+{
+ vty_out (vty,
+ "Zebra VTY provides advanced help feature. When you need help,%s\
+anytime at the command line please press '?'.%s\
+%s\
+If nothing matches, the help list will be empty and you must backup%s\
+ until entering a '?' shows the available options.%s\
+Two styles of help are provided:%s\
+1. Full help is available when you are ready to enter a%s\
+command argument (e.g. 'show ?') and describes each possible%s\
+argument.%s\
+2. Partial help is provided when an abbreviated argument is entered%s\
+ and you want to know what arguments match the input%s\
+ (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
+ VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
+ VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+/* Help display function for all node. */
+DEFUN (config_list,
+ config_list_cmd,
+ "list",
+ "Print command list\n")
+{
+ int i;
+ struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
+ struct cmd_element *cmd;
+
+ for (i = 0; i < vector_max (cnode->cmd_vector); i++)
+ if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL)
+ vty_out (vty, " %s%s", cmd->string,
+ VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+/* Write current configuration into file. */
+DEFUN (config_write_file,
+ config_write_file_cmd,
+ "write file",
+ "Write running configuration to memory, network, or terminal\n"
+ "Write to configuration file\n")
+{
+ int i;
+ int fd;
+ struct cmd_node *node;
+ char *config_file;
+ char *config_file_tmp = NULL;
+ char *config_file_sav = NULL;
+ struct vty *file_vty;
+
+ /* Check and see if we are operating under vtysh configuration */
+ if (host.config == NULL)
+ {
+ vty_out (vty, "Can't save to configuration file, using vtysh.%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Get filename. */
+ config_file = host.config;
+
+ config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
+ strcpy (config_file_sav, config_file);
+ strcat (config_file_sav, CONF_BACKUP_EXT);
+
+
+ config_file_tmp = malloc (strlen (config_file) + 8);
+ sprintf (config_file_tmp, "%s.XXXXXX", config_file);
+
+ /* Open file to configuration write. */
+ fd = mkstemp (config_file_tmp);
+ if (fd < 0)
+ {
+ vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
+ VTY_NEWLINE);
+ free (config_file_tmp);
+ free (config_file_sav);
+ return CMD_WARNING;
+ }
+
+ /* Make vty for configuration file. */
+ file_vty = vty_new ();
+ file_vty->fd = fd;
+ file_vty->type = VTY_FILE;
+
+ /* Config file header print. */
+ vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
+ vty_time_print (file_vty, 1);
+ vty_out (file_vty, "!\n");
+
+ for (i = 0; i < vector_max (cmdvec); i++)
+ if ((node = vector_slot (cmdvec, i)) && node->func)
+ {
+ if ((*node->func) (file_vty))
+ vty_out (file_vty, "!\n");
+ }
+ vty_close (file_vty);
+
+ if (unlink (config_file_sav) != 0)
+ if (errno != ENOENT)
+ {
+ vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
+ VTY_NEWLINE);
+ free (config_file_sav);
+ free (config_file_tmp);
+ unlink (config_file_tmp);
+ return CMD_WARNING;
+ }
+ if (link (config_file, config_file_sav) != 0)
+ {
+ vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
+ VTY_NEWLINE);
+ free (config_file_sav);
+ free (config_file_tmp);
+ unlink (config_file_tmp);
+ return CMD_WARNING;
+ }
+ sync ();
+ if (unlink (config_file) != 0)
+ {
+ vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
+ VTY_NEWLINE);
+ free (config_file_sav);
+ free (config_file_tmp);
+ unlink (config_file_tmp);
+ return CMD_WARNING;
+ }
+ if (link (config_file_tmp, config_file) != 0)
+ {
+ vty_out (vty, "Can't save configuration file %s.%s", config_file,
+ VTY_NEWLINE);
+ free (config_file_sav);
+ free (config_file_tmp);
+ unlink (config_file_tmp);
+ return CMD_WARNING;
+ }
+ unlink (config_file_tmp);
+ sync ();
+
+ free (config_file_sav);
+ free (config_file_tmp);
+ vty_out (vty, "Configuration saved to %s%s", config_file,
+ VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+ALIAS (config_write_file,
+ config_write_cmd,
+ "write",
+ "Write running configuration to memory, network, or terminal\n")
+
+ALIAS (config_write_file,
+ config_write_memory_cmd,
+ "write memory",
+ "Write running configuration to memory, network, or terminal\n"
+ "Write configuration to the file (same as write file)\n")
+
+ALIAS (config_write_file,
+ copy_runningconfig_startupconfig_cmd,
+ "copy running-config startup-config",
+ "Copy configuration\n"
+ "Copy running config to... \n"
+ "Copy running config to startup config (same as write file)\n")
+
+/* Write current configuration into the terminal. */
+DEFUN (config_write_terminal,
+ config_write_terminal_cmd,
+ "write terminal",
+ "Write running configuration to memory, network, or terminal\n"
+ "Write to terminal\n")
+{
+ int i;
+ struct cmd_node *node;
+
+ if (vty->type == VTY_SHELL_SERV)
+ {
+ for (i = 0; i < vector_max (cmdvec); i++)
+ if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
+ {
+ if ((*node->func) (vty))
+ vty_out (vty, "!%s", VTY_NEWLINE);
+ }
+ }
+ else
+ {
+ vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
+ VTY_NEWLINE);
+ vty_out (vty, "!%s", VTY_NEWLINE);
+
+ for (i = 0; i < vector_max (cmdvec); i++)
+ if ((node = vector_slot (cmdvec, i)) && node->func)
+ {
+ if ((*node->func) (vty))
+ vty_out (vty, "!%s", VTY_NEWLINE);
+ }
+ vty_out (vty, "end%s",VTY_NEWLINE);
+ }
+ return CMD_SUCCESS;
+}
+
+/* Write current configuration into the terminal. */
+ALIAS (config_write_terminal,
+ show_running_config_cmd,
+ "show running-config",
+ SHOW_STR
+ "running configuration\n")
+
+/* Write startup configuration into the terminal. */
+DEFUN (show_startup_config,
+ show_startup_config_cmd,
+ "show startup-config",
+ SHOW_STR
+ "Contentes of startup configuration\n")
+{
+ char buf[BUFSIZ];
+ FILE *confp;
+
+ confp = fopen (host.config, "r");
+ if (confp == NULL)
+ {
+ vty_out (vty, "Can't open configuration file [%s]%s",
+ host.config, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ while (fgets (buf, BUFSIZ, confp))
+ {
+ char *cp = buf;
+
+ while (*cp != '\r' && *cp != '\n' && *cp != '\0')
+ cp++;
+ *cp = '\0';
+
+ vty_out (vty, "%s%s", buf, VTY_NEWLINE);
+ }
+
+ fclose (confp);
+
+ return CMD_SUCCESS;
+}
+
+/* Hostname configuration */
+DEFUN (config_hostname,
+ hostname_cmd,
+ "hostname WORD",
+ "Set system's network name\n"
+ "This system's network name\n")
+{
+ if (!isalpha((int) *argv[0]))
+ {
+ vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (host.name)
+ XFREE (0, host.name);
+
+ host.name = strdup (argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_no_hostname,
+ no_hostname_cmd,
+ "no hostname [HOSTNAME]",
+ NO_STR
+ "Reset system's network name\n"
+ "Host name of this router\n")
+{
+ if (host.name)
+ XFREE (0, host.name);
+ host.name = NULL;
+ return CMD_SUCCESS;
+}
+
+/* VTY interface password set. */
+DEFUN (config_password, password_cmd,
+ "password (8|) WORD",
+ "Assign the terminal connection password\n"
+ "Specifies a HIDDEN password will follow\n"
+ "dummy string \n"
+ "The HIDDEN line password string\n")
+{
+ /* Argument check. */
+ if (argc == 0)
+ {
+ vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (argc == 2)
+ {
+ if (*argv[0] == '8')
+ {
+ if (host.password)
+ XFREE (0, host.password);
+ host.password = NULL;
+ if (host.password_encrypt)
+ XFREE (0, host.password_encrypt);
+ host.password_encrypt = XSTRDUP (0, strdup (argv[1]));
+ return CMD_SUCCESS;
+ }
+ else
+ {
+ vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ if (!isalnum ((int) *argv[0]))
+ {
+ vty_out (vty,
+ "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (host.password)
+ XFREE (0, host.password);
+ host.password = NULL;
+
+ if (host.encrypt)
+ {
+ if (host.password_encrypt)
+ XFREE (0, host.password_encrypt);
+ host.password_encrypt = XSTRDUP (0, zencrypt (argv[0]));
+ }
+ else
+ host.password = XSTRDUP (0, argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (config_password, password_text_cmd,
+ "password LINE",
+ "Assign the terminal connection password\n"
+ "The UNENCRYPTED (cleartext) line password\n")
+
+/* VTY enable password set. */
+DEFUN (config_enable_password, enable_password_cmd,
+ "enable password (8|) WORD",
+ "Modify enable password parameters\n"
+ "Assign the privileged level password\n"
+ "Specifies a HIDDEN password will follow\n"
+ "dummy string \n"
+ "The HIDDEN 'enable' password string\n")
+{
+ /* Argument check. */
+ if (argc == 0)
+ {
+ vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Crypt type is specified. */
+ if (argc == 2)
+ {
+ if (*argv[0] == '8')
+ {
+ if (host.enable)
+ XFREE (0, host.enable);
+ host.enable = NULL;
+
+ if (host.enable_encrypt)
+ XFREE (0, host.enable_encrypt);
+ host.enable_encrypt = XSTRDUP (0, argv[1]);
+
+ return CMD_SUCCESS;
+ }
+ else
+ {
+ vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ if (!isalnum ((int) *argv[0]))
+ {
+ vty_out (vty,
+ "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (host.enable)
+ XFREE (0, host.enable);
+ host.enable = NULL;
+
+ /* Plain password input. */
+ if (host.encrypt)
+ {
+ if (host.enable_encrypt)
+ XFREE (0, host.enable_encrypt);
+ host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0]));
+ }
+ else
+ host.enable = XSTRDUP (0, argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (config_enable_password,
+ enable_password_text_cmd,
+ "enable password LINE",
+ "Modify enable password parameters\n"
+ "Assign the privileged level password\n"
+ "The UNENCRYPTED (cleartext) 'enable' password\n")
+
+/* VTY enable password delete. */
+DEFUN (no_config_enable_password, no_enable_password_cmd,
+ "no enable password",
+ NO_STR
+ "Modify enable password parameters\n"
+ "Assign the privileged level password\n")
+{
+ if (host.enable)
+ XFREE (0, host.enable);
+ host.enable = NULL;
+
+ if (host.enable_encrypt)
+ XFREE (0, host.enable_encrypt);
+ host.enable_encrypt = NULL;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (service_password_encrypt,
+ service_password_encrypt_cmd,
+ "service password-encryption",
+ "Set up miscellaneous service\n"
+ "Enable encrypted passwords\n")
+{
+ if (host.encrypt)
+ return CMD_SUCCESS;
+
+ host.encrypt = 1;
+
+ if (host.password)
+ {
+ if (host.password_encrypt)
+ XFREE (0, host.password_encrypt);
+ host.password_encrypt = XSTRDUP (0, zencrypt (host.password));
+ }
+ if (host.enable)
+ {
+ if (host.enable_encrypt)
+ XFREE (0, host.enable_encrypt);
+ host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable));
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_service_password_encrypt,
+ no_service_password_encrypt_cmd,
+ "no service password-encryption",
+ NO_STR
+ "Set up miscellaneous service\n"
+ "Enable encrypted passwords\n")
+{
+ if (! host.encrypt)
+ return CMD_SUCCESS;
+
+ host.encrypt = 0;
+
+ if (host.password_encrypt)
+ XFREE (0, host.password_encrypt);
+ host.password_encrypt = NULL;
+
+ if (host.enable_encrypt)
+ XFREE (0, host.enable_encrypt);
+ host.enable_encrypt = NULL;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_terminal_length, config_terminal_length_cmd,
+ "terminal length <0-512>",
+ "Set terminal line parameters\n"
+ "Set number of lines on a screen\n"
+ "Number of lines on screen (0 for no pausing)\n")
+{
+ int lines;
+ char *endptr = NULL;
+
+ lines = strtol (argv[0], &endptr, 10);
+ if (lines < 0 || lines > 512 || *endptr != '\0')
+ {
+ vty_out (vty, "length is malformed%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ vty->lines = lines;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
+ "terminal no length",
+ "Set terminal line parameters\n"
+ NO_STR
+ "Set number of lines on a screen\n")
+{
+ vty->lines = -1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (service_terminal_length, service_terminal_length_cmd,
+ "service terminal-length <0-512>",
+ "Set up miscellaneous service\n"
+ "System wide terminal length configuration\n"
+ "Number of lines of VTY (0 means no line control)\n")
+{
+ int lines;
+ char *endptr = NULL;
+
+ lines = strtol (argv[0], &endptr, 10);
+ if (lines < 0 || lines > 512 || *endptr != '\0')
+ {
+ vty_out (vty, "length is malformed%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ host.lines = lines;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
+ "no service terminal-length [<0-512>]",
+ NO_STR
+ "Set up miscellaneous service\n"
+ "System wide terminal length configuration\n"
+ "Number of lines of VTY (0 means no line control)\n")
+{
+ host.lines = -1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_log_stdout,
+ config_log_stdout_cmd,
+ "log stdout",
+ "Logging control\n"
+ "Logging goes to stdout\n")
+{
+ zlog_set_flag (NULL, ZLOG_STDOUT);
+ host.log_stdout = 1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_config_log_stdout,
+ no_config_log_stdout_cmd,
+ "no log stdout",
+ NO_STR
+ "Logging control\n"
+ "Cancel logging to stdout\n")
+{
+ zlog_reset_flag (NULL, ZLOG_STDOUT);
+ host.log_stdout = 0;
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_log_file,
+ config_log_file_cmd,
+ "log file FILENAME",
+ "Logging control\n"
+ "Logging to file\n"
+ "Logging filename\n")
+{
+ int ret;
+ char *cwd;
+ char *fullpath;
+
+ /* Path detection. */
+ if (! IS_DIRECTORY_SEP (*argv[0]))
+ {
+ cwd = getcwd (NULL, MAXPATHLEN);
+ fullpath = XMALLOC (MTYPE_TMP,
+ strlen (cwd) + strlen (argv[0]) + 2);
+ sprintf (fullpath, "%s/%s", cwd, argv[0]);
+ }
+ else
+ fullpath = argv[0];
+
+ ret = zlog_set_file (NULL, ZLOG_FILE, fullpath);
+
+ if (!ret)
+ {
+ vty_out (vty, "can't open logfile %s\n", argv[0]);
+ return CMD_WARNING;
+ }
+
+ if (host.logfile)
+ XFREE (MTYPE_TMP, host.logfile);
+
+ host.logfile = strdup (argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_config_log_file,
+ no_config_log_file_cmd,
+ "no log file [FILENAME]",
+ NO_STR
+ "Logging control\n"
+ "Cancel logging to file\n"
+ "Logging file name\n")
+{
+ zlog_reset_file (NULL);
+
+ if (host.logfile)
+ XFREE (MTYPE_TMP, host.logfile);
+
+ host.logfile = NULL;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_log_syslog,
+ config_log_syslog_cmd,
+ "log syslog",
+ "Logging control\n"
+ "Logging goes to syslog\n")
+{
+ zlog_set_flag (NULL, ZLOG_SYSLOG);
+ host.log_syslog = 1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_config_log_syslog,
+ no_config_log_syslog_cmd,
+ "no log syslog",
+ NO_STR
+ "Logging control\n"
+ "Cancel logging to syslog\n")
+{
+ zlog_reset_flag (NULL, ZLOG_SYSLOG);
+ host.log_syslog = 0;
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_log_trap,
+ config_log_trap_cmd,
+ "log trap (emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)",
+ "Logging control\n"
+ "Limit logging to specifed level\n")
+{
+ int new_level ;
+
+ for ( new_level = 0 ; zlog_priority [new_level] != NULL ; new_level ++ )
+ {
+ if ( strcmp ( argv[0], zlog_priority [new_level] ) == 0 )
+ /* found new logging level */
+ {
+ zlog_default->maskpri = new_level;
+ return CMD_SUCCESS;
+ }
+ }
+ return CMD_ERR_NO_MATCH;
+}
+
+DEFUN (no_config_log_trap,
+ no_config_log_trap_cmd,
+ "no log trap",
+ NO_STR
+ "Logging control\n"
+ "Permit all logging information\n")
+{
+ zlog_default->maskpri = LOG_DEBUG;
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_log_record_priority,
+ config_log_record_priority_cmd,
+ "log record-priority",
+ "Logging control\n"
+ "Log the priority of the message within the message\n")
+{
+ zlog_default->record_priority = 1 ;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_config_log_record_priority,
+ no_config_log_record_priority_cmd,
+ "no log record-priority",
+ NO_STR
+ "Logging control\n"
+ "Do not log the priority of the message within the message\n")
+{
+ zlog_default->record_priority = 0 ;
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (banner_motd_default,
+ banner_motd_default_cmd,
+ "banner motd default",
+ "Set banner string\n"
+ "Strings for motd\n"
+ "Default string\n")
+{
+ host.motd = default_motd;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_banner_motd,
+ no_banner_motd_cmd,
+ "no banner motd",
+ NO_STR
+ "Set banner string\n"
+ "Strings for motd\n")
+{
+ host.motd = NULL;
+ return CMD_SUCCESS;
+}
+
+/* Set config filename. Called from vty.c */
+void
+host_config_set (char *filename)
+{
+ host.config = strdup (filename);
+}
+
+void
+install_default (enum node_type node)
+{
+ install_element (node, &config_exit_cmd);
+ install_element (node, &config_quit_cmd);
+ install_element (node, &config_end_cmd);
+ install_element (node, &config_help_cmd);
+ install_element (node, &config_list_cmd);
+
+ install_element (node, &config_write_terminal_cmd);
+ install_element (node, &config_write_file_cmd);
+ install_element (node, &config_write_memory_cmd);
+ install_element (node, &config_write_cmd);
+ install_element (node, &show_running_config_cmd);
+}
+
+/* Initialize command interface. Install basic nodes and commands. */
+void
+cmd_init (int terminal)
+{
+ /* Allocate initial top vector of commands. */
+ cmdvec = vector_init (VECTOR_MIN_SIZE);
+
+ /* Default host value settings. */
+ host.name = NULL;
+ host.password = NULL;
+ host.enable = NULL;
+ host.logfile = NULL;
+ host.config = NULL;
+ host.lines = -1;
+ host.motd = default_motd;
+
+ /* Install top nodes. */
+ install_node (&view_node, NULL);
+ install_node (&enable_node, NULL);
+ install_node (&auth_node, NULL);
+ install_node (&auth_enable_node, NULL);
+ install_node (&config_node, config_write_host);
+
+ /* Each node's basic commands. */
+ install_element (VIEW_NODE, &show_version_cmd);
+ if (terminal)
+ {
+ install_element (VIEW_NODE, &config_list_cmd);
+ install_element (VIEW_NODE, &config_exit_cmd);
+ install_element (VIEW_NODE, &config_quit_cmd);
+ install_element (VIEW_NODE, &config_help_cmd);
+ install_element (VIEW_NODE, &config_enable_cmd);
+ install_element (VIEW_NODE, &config_terminal_length_cmd);
+ install_element (VIEW_NODE, &config_terminal_no_length_cmd);
+ }
+
+ if (terminal)
+ {
+ install_default (ENABLE_NODE);
+ install_element (ENABLE_NODE, &config_disable_cmd);
+ install_element (ENABLE_NODE, &config_terminal_cmd);
+ install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
+ }
+ install_element (ENABLE_NODE, &show_startup_config_cmd);
+ install_element (ENABLE_NODE, &show_version_cmd);
+ install_element (ENABLE_NODE, &config_terminal_length_cmd);
+ install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
+
+ if (terminal)
+ install_default (CONFIG_NODE);
+ install_element (CONFIG_NODE, &hostname_cmd);
+ install_element (CONFIG_NODE, &no_hostname_cmd);
+ install_element (CONFIG_NODE, &password_cmd);
+ install_element (CONFIG_NODE, &password_text_cmd);
+ install_element (CONFIG_NODE, &enable_password_cmd);
+ install_element (CONFIG_NODE, &enable_password_text_cmd);
+ install_element (CONFIG_NODE, &no_enable_password_cmd);
+ if (terminal)
+ {
+ install_element (CONFIG_NODE, &config_log_stdout_cmd);
+ install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
+ install_element (CONFIG_NODE, &config_log_file_cmd);
+ install_element (CONFIG_NODE, &no_config_log_file_cmd);
+ install_element (CONFIG_NODE, &config_log_syslog_cmd);
+ install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
+ install_element (CONFIG_NODE, &config_log_trap_cmd);
+ install_element (CONFIG_NODE, &no_config_log_trap_cmd);
+ install_element (CONFIG_NODE, &config_log_record_priority_cmd);
+ install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
+ install_element (CONFIG_NODE, &service_password_encrypt_cmd);
+ install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
+ install_element (CONFIG_NODE, &banner_motd_default_cmd);
+ install_element (CONFIG_NODE, &no_banner_motd_cmd);
+ install_element (CONFIG_NODE, &service_terminal_length_cmd);
+ install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
+ }
+
+ srand(time(NULL));
+}
diff --git a/lib/command.h b/lib/command.h
new file mode 100644
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 <zebra.h>
+
+#ifndef HAVE_DAEMON
+
+/* Daemonize myself. */
+int
+daemon (int nochdir, int noclose)
+{
+ pid_t pid;
+
+ pid = fork ();
+
+ /* In case of fork is error. */
+ if (pid < 0)
+ {
+ perror ("fork");
+ return -1;
+ }
+
+ /* In case of this is parent process. */
+ if (pid != 0)
+ exit (0);
+
+ /* Become session leader and get pid. */
+ pid = setsid();
+
+ if (pid < -1)
+ {
+ perror ("setsid");
+ return -1;
+ }
+
+ /* Change directory to root. */
+ if (! nochdir)
+ chdir ("/");
+
+ /* File descriptor close. */
+ if (! noclose)
+ {
+ int fd;
+
+ fd = open ("/dev/null", O_RDWR, 0);
+ if (fd != -1)
+ {
+ dup2 (fd, STDIN_FILENO);
+ dup2 (fd, STDOUT_FILENO);
+ dup2 (fd, STDERR_FILENO);
+ if (fd > 2)
+ close (fd);
+ }
+ }
+
+ umask (0027);
+
+ return 0;
+}
+
+#endif /* HAVE_DAEMON */
diff --git a/lib/distribute.c b/lib/distribute.c
new file mode 100644
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 <zebra.h>
+
+#include "hash.h"
+#include "if.h"
+#include "filter.h"
+#include "command.h"
+#include "distribute.h"
+#include "memory.h"
+
+/* Hash of distribute list. */
+struct hash *disthash;
+
+/* Hook functions. */
+void (*distribute_add_hook) (struct distribute *);
+void (*distribute_delete_hook) (struct distribute *);
+
+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 <zebra.h>
+
+#include "prefix.h"
+#include "filter.h"
+#include "memory.h"
+#include "command.h"
+#include "sockunion.h"
+#include "buffer.h"
+
+struct filter_cisco
+{
+ /* Cisco access-list */
+ int extended;
+ struct in_addr addr;
+ struct in_addr addr_mask;
+ struct in_addr mask;
+ struct in_addr mask_mask;
+};
+
+struct filter_zebra
+{
+ /* If this filter is "exact" match then this flag is set. */
+ int exact;
+
+ /* Prefix information. */
+ struct prefix prefix;
+};
+
+/* Filter element of access list */
+struct filter
+{
+ /* For doubly linked list. */
+ struct filter *next;
+ struct filter *prev;
+
+ /* Filter type information. */
+ enum filter_type type;
+
+ /* Cisco access-list */
+ int cisco;
+
+ union
+ {
+ struct filter_cisco cfilter;
+ struct filter_zebra zfilter;
+ } u;
+};
+
+/* List of access_list. */
+struct access_list_list
+{
+ struct access_list *head;
+ struct access_list *tail;
+};
+
+/* Master structure of access_list. */
+struct access_master
+{
+ /* List of access_list which name is number. */
+ struct access_list_list num;
+
+ /* List of access_list which name is string. */
+ struct access_list_list str;
+
+ /* Hook function which is executed when new access_list is added. */
+ void (*add_hook) ();
+
+ /* Hook function which is executed when access_list is deleted. */
+ void (*delete_hook) ();
+};
+
+/* Static structure for IPv4 access_list's master. */
+static struct access_master access_master_ipv4 =
+{
+ {NULL, NULL},
+ {NULL, NULL},
+ NULL,
+ NULL,
+};
+
+#ifdef HAVE_IPV6
+/* Static structure for IPv6 access_list's master. */
+static struct access_master access_master_ipv6 =
+{
+ {NULL, NULL},
+ {NULL, NULL},
+ NULL,
+ NULL,
+};
+#endif /* HAVE_IPV6 */
+
+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 <stdio.h>.
+ Ditto for AIX 3.2 and <stdlib.h>. */
+#ifndef _NO_PROTO
+# define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+# ifndef const
+# define const
+# endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+# include <gnu-versions.h>
+# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+# define ELIDE_CODE
+# endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+# include <stdlib.h>
+# include <unistd.h>
+#endif /* GNU C library. */
+
+#ifdef VMS
+# include <unixlib.h>
+# if HAVE_STRING_H - 0
+# include <string.h>
+# endif
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.
+ When compiling libc, the _ macro is predefined. */
+# ifdef HAVE_LIBINTL_H
+# include <libintl.h>
+# define _(msgid) gettext (msgid)
+# else
+# define _(msgid) (msgid)
+# endif
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* 1003.2 says this must be 1 before any call. */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+ causes problems with re-calling getopt as programs generally don't
+ know that. */
+
+int __getopt_initialized = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return -1 with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable. */
+static char *posixly_correct;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+# include <string.h>
+# define my_index strchr
+#else
+
+# if HAVE_STRING_H
+# include <string.h>
+# else
+# include <strings.h>
+# endif
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+#ifndef getenv
+extern char *getenv ();
+#endif
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it. */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+ That was relevant to code that was here before. */
+# if (!defined __STDC__ || !__STDC__) && !defined strlen
+/* gcc with -traditional declares the built-in strlen to return int,
+ and has done so at least since version 2.4.5. -- rms. */
+extern int strlen (const char *);
+# endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* 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 <config.h>
+#endif
+
+#include "getopt.h"
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* Not ELIDE_CODE. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case 'd':
+ printf ("option d with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/lib/hash.c b/lib/hash.c
new file mode 100644
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 <zebra.h>
+
+#include "hash.h"
+#include "memory.h"
+
+/* Allocate a new hash. */
+struct hash *
+hash_create_size (unsigned int size,
+ unsigned int (*hash_key) (), int (*hash_cmp) ())
+{
+ struct hash *hash;
+
+ hash = XMALLOC (MTYPE_HASH, sizeof (struct hash));
+ hash->index = XMALLOC (MTYPE_HASH_INDEX,
+ sizeof (struct hash_backet *) * size);
+ memset (hash->index, 0, sizeof (struct hash_backet *) * size);
+ hash->size = size;
+ hash->hash_key = hash_key;
+ hash->hash_cmp = hash_cmp;
+ hash->count = 0;
+
+ return hash;
+}
+
+/* Allocate a new hash with default hash size. */
+struct hash *
+hash_create (unsigned int (*hash_key) (), int (*hash_cmp) ())
+{
+ return hash_create_size (HASHTABSIZE, hash_key, hash_cmp);
+}
+
+/* Utility function for hash_get(). When this function is specified
+ as alloc_func, return arugment as it is. This function is used for
+ intern already allocated value. */
+void *
+hash_alloc_intern (void *arg)
+{
+ return arg;
+}
+
+/* Lookup and return hash backet in hash. If there is no
+ corresponding hash backet and alloc_func is specified, create new
+ hash backet. */
+void *
+hash_get (struct hash *hash, void *data, void * (*alloc_func) ())
+{
+ unsigned int key;
+ unsigned int index;
+ void *newdata;
+ struct hash_backet *backet;
+
+ key = (*hash->hash_key) (data);
+ index = key % hash->size;
+
+ for (backet = hash->index[index]; backet != NULL; backet = backet->next)
+ if (backet->key == key && (*hash->hash_cmp) (backet->data, data))
+ return backet->data;
+
+ if (alloc_func)
+ {
+ newdata = (*alloc_func) (data);
+ if (newdata == NULL)
+ return NULL;
+
+ backet = XMALLOC (MTYPE_HASH_BACKET, sizeof (struct hash_backet));
+ backet->data = newdata;
+ backet->key = key;
+ backet->next = hash->index[index];
+ hash->index[index] = backet;
+ hash->count++;
+ return backet->data;
+ }
+ return NULL;
+}
+
+/* Hash lookup. */
+void *
+hash_lookup (struct hash *hash, void *data)
+{
+ return hash_get (hash, data, NULL);
+}
+
+/* This function release registered value from specified hash. When
+ release is successfully finished, return the data pointer in the
+ hash backet. */
+void *
+hash_release (struct hash *hash, void *data)
+{
+ void *ret;
+ unsigned int key;
+ unsigned int index;
+ struct hash_backet *backet;
+ struct hash_backet *pp;
+
+ key = (*hash->hash_key) (data);
+ index = key % hash->size;
+
+ for (backet = pp = hash->index[index]; backet; backet = backet->next)
+ {
+ if (backet->key == key && (*hash->hash_cmp) (backet->data, data))
+ {
+ if (backet == pp)
+ hash->index[index] = backet->next;
+ else
+ pp->next = backet->next;
+
+ ret = backet->data;
+ XFREE (MTYPE_HASH_BACKET, backet);
+ hash->count--;
+ return ret;
+ }
+ pp = backet;
+ }
+ return NULL;
+}
+
+/* Iterator function for hash. */
+void
+hash_iterate (struct hash *hash,
+ void (*func) (struct hash_backet *, void *), void *arg)
+{
+ int i;
+ struct hash_backet *hb;
+
+ for (i = 0; i < hash->size; i++)
+ for (hb = hash->index[i]; hb; hb = hb->next)
+ (*func) (hb, arg);
+}
+
+/* Clean up hash. */
+void
+hash_clean (struct hash *hash, void (*free_func) (void *))
+{
+ int i;
+ struct hash_backet *hb;
+ struct hash_backet *next;
+
+ for (i = 0; i < hash->size; i++)
+ {
+ for (hb = hash->index[i]; hb; hb = next)
+ {
+ next = hb->next;
+
+ if (free_func)
+ (*free_func) (hb->data);
+
+ XFREE (MTYPE_HASH_BACKET, hb);
+ hash->count--;
+ }
+ hash->index[i] = NULL;
+ }
+}
+
+/* Free hash memory. You may call hash_clean before call this
+ function. */
+void
+hash_free (struct hash *hash)
+{
+ XFREE (MTYPE_HASH_INDEX, hash->index);
+ XFREE (MTYPE_HASH, hash);
+}
diff --git a/lib/hash.h b/lib/hash.h
new file mode 100644
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 <zebra.h>
+
+#include "linklist.h"
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+#include "if.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "zebra/connected.h"
+#include "memory.h"
+#include "table.h"
+#include "buffer.h"
+#include "str.h"
+#include "log.h"
+
+/* 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 <zebra.h>
+
+#include "hash.h"
+#include "command.h"
+#include "memory.h"
+#include "if.h"
+#include "if_rmap.h"
+
+struct hash *ifrmaphash;
+
+/* Hook functions. */
+void (*if_rmap_add_hook) (struct if_rmap *) = NULL;
+void (*if_rmap_delete_hook) (struct if_rmap *) = NULL;
+
+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 <zebra.h>
+
+#include "command.h"
+#include "memory.h"
+#include "linklist.h"
+#include "keychain.h"
+
+/* Master list of key chain. */
+struct list *keychain_list;
+
+struct keychain *
+keychain_new ()
+{
+ struct keychain *new;
+ new = XMALLOC (MTYPE_KEYCHAIN, sizeof (struct keychain));
+ memset (new, 0, sizeof (struct keychain));
+ return new;
+}
+
+void
+keychain_free (struct keychain *keychain)
+{
+ XFREE (MTYPE_KEYCHAIN, keychain);
+}
+
+struct key *
+key_new ()
+{
+ struct key *new;
+ new = XMALLOC (MTYPE_KEY, sizeof (struct key));
+ memset (new, 0, sizeof (struct key));
+ return new;
+}
+
+void
+key_free (struct key *key)
+{
+ XFREE (MTYPE_KEY, key);
+}
+
+struct keychain *
+keychain_lookup (char *name)
+{
+ struct listnode *nn;
+ struct keychain *keychain;
+
+ if (name == NULL)
+ return NULL;
+
+ LIST_LOOP (keychain_list, keychain, nn)
+ {
+ if (strcmp (keychain->name, name) == 0)
+ return keychain;
+ }
+ return NULL;
+}
+
+int
+key_cmp_func (struct key *k1, struct key *k2)
+{
+ if (k1->index > k2->index)
+ return 1;
+ if (k1->index < k2->index)
+ return -1;
+ return 0;
+}
+
+void
+key_delete_func (struct key *key)
+{
+ if (key->string)
+ free (key->string);
+ key_free (key);
+}
+
+struct keychain *
+keychain_get (char *name)
+{
+ struct keychain *keychain;
+
+ keychain = keychain_lookup (name);
+
+ if (keychain)
+ return keychain;
+
+ keychain = keychain_new ();
+ keychain->name = strdup (name);
+ keychain->key = list_new ();
+ keychain->key->cmp = (int (*)(void *, void *)) key_cmp_func;
+ keychain->key->del = (void (*)(void *)) key_delete_func;
+ listnode_add (keychain_list, keychain);
+
+ return keychain;
+}
+
+void
+keychain_delete (struct keychain *keychain)
+{
+ if (keychain->name)
+ free (keychain->name);
+
+ list_delete (keychain->key);
+ listnode_delete (keychain_list, keychain);
+ keychain_free (keychain);
+}
+
+struct key *
+key_lookup (struct keychain *keychain, u_int32_t index)
+{
+ struct listnode *nn;
+ struct key *key;
+
+ LIST_LOOP (keychain->key, key, nn)
+ {
+ if (key->index == index)
+ return key;
+ }
+ return NULL;
+}
+
+struct key *
+key_lookup_for_accept (struct keychain *keychain, u_int32_t index)
+{
+ struct listnode *nn;
+ struct key *key;
+ time_t now;
+
+ now = time (NULL);
+
+ LIST_LOOP (keychain->key, key, nn)
+ {
+ if (key->index >= index)
+ {
+ if (key->accept.start == 0)
+ return key;
+
+ if (key->accept.start <= now)
+ if (key->accept.end >= now || key->accept.end == -1)
+ return key;
+ }
+ }
+ return NULL;
+}
+
+struct key *
+key_match_for_accept (struct keychain *keychain, char *auth_str)
+{
+ struct listnode *nn;
+ struct key *key;
+ time_t now;
+
+ now = time (NULL);
+
+ LIST_LOOP (keychain->key, key, nn)
+ {
+ if (key->accept.start == 0 ||
+ (key->accept.start <= now &&
+ (key->accept.end >= now || key->accept.end == -1)))
+ if (strncmp (key->string, auth_str, 16) == 0)
+ return key;
+ }
+ return NULL;
+}
+
+struct key *
+key_lookup_for_send (struct keychain *keychain)
+{
+ struct listnode *nn;
+ struct key *key;
+ time_t now;
+
+ now = time (NULL);
+
+ LIST_LOOP (keychain->key, key, nn)
+ {
+ if (key->send.start == 0)
+ return key;
+
+ if (key->send.start <= now)
+ if (key->send.end >= now || key->send.end == -1)
+ return key;
+ }
+ return NULL;
+}
+
+struct key *
+key_get (struct keychain *keychain, u_int32_t index)
+{
+ struct key *key;
+
+ key = key_lookup (keychain, index);
+
+ if (key)
+ return key;
+
+ key = key_new ();
+ key->index = index;
+ listnode_add_sort (keychain->key, key);
+
+ return key;
+}
+
+void
+key_delete (struct keychain *keychain, struct key *key)
+{
+ listnode_delete (keychain->key, key);
+
+ if (key->string)
+ free (key->string);
+ key_free (key);
+}
+
+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 <zebra.h>
+
+#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 <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "command.h"
+
+struct zlog *zlog_default = NULL;
+
+const char *zlog_proto_names[] =
+{
+ "NONE",
+ "DEFAULT",
+ "ZEBRA",
+ "RIP",
+ "BGP",
+ "OSPF",
+ "RIPNG",
+ "OSPF6",
+ "MASC",
+ NULL,
+};
+
+const char *zlog_priority[] =
+{
+ "emergencies",
+ "alerts",
+ "critical",
+ "errors",
+ "warnings",
+ "notifications",
+ "informational",
+ "debugging",
+ NULL,
+};
+
+
+
+/* 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 <syslog.h>
+
+#define ZLOG_NOLOG 0x00
+#define ZLOG_FILE 0x01
+#define ZLOG_SYSLOG 0x02
+#define ZLOG_STDOUT 0x04
+#define ZLOG_STDERR 0x08
+
+#define ZLOG_NOLOG_INDEX 0
+#define ZLOG_FILE_INDEX 1
+#define ZLOG_SYSLOG_INDEX 2
+#define ZLOG_STDOUT_INDEX 3
+#define ZLOG_STDERR_INDEX 4
+#define ZLOG_MAX_INDEX 5
+
+typedef enum
+{
+ ZLOG_NONE,
+ ZLOG_DEFAULT,
+ ZLOG_ZEBRA,
+ ZLOG_RIP,
+ ZLOG_BGP,
+ ZLOG_OSPF,
+ ZLOG_RIPNG,
+ ZLOG_OSPF6,
+ ZLOG_MASC
+} zlog_proto_t;
+
+struct zlog
+{
+ const char *ident;
+ zlog_proto_t protocol;
+ int flags;
+ FILE *fp;
+ char *filename;
+ int syslog;
+ int stat;
+ int connected;
+ int maskpri; /* as per syslog setlogmask */
+ int priority; /* as per syslog priority */
+ int facility; /* as per syslog facility */
+ int record_priority;
+};
+
+/* Message structure. */
+struct message
+{
+ int key;
+ char *str;
+};
+
+/* Default logging strucutre. */
+extern struct zlog *zlog_default;
+
+/* Open zlog function */
+struct zlog *openzlog (const char *, int, zlog_proto_t, int, int);
+
+/* Close zlog function. */
+void closezlog (struct zlog *zl);
+
+/* GCC have printf type attribute check. */
+#ifdef __GNUC__
+#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
+#else
+#define PRINTF_ATTRIBUTE(a,b)
+#endif /* __GNUC__ */
+
+/* Generic function for zlog. */
+void zlog (struct zlog *zl, int priority, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
+
+/* Handy zlog functions. */
+void zlog_err (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+void zlog_warn (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+void zlog_info (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+void zlog_notice (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+void zlog_debug (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+
+/* For bgpd's peer oriented log. */
+void plog_err (struct zlog *, const char *format, ...);
+void plog_warn (struct zlog *, const char *format, ...);
+void plog_info (struct zlog *, const char *format, ...);
+void plog_notice (struct zlog *, const char *format, ...);
+void plog_debug (struct zlog *, const char *format, ...);
+
+/* Set zlog flags. */
+void zlog_set_flag (struct zlog *zl, int flags);
+void zlog_reset_flag (struct zlog *zl, int flags);
+
+/* Set zlog filename. */
+int zlog_set_file (struct zlog *zl, int flags, char *filename);
+int zlog_reset_file (struct zlog *zl);
+
+/* Rotate log. */
+int zlog_rotate ();
+
+/* For hackey massage lookup and check */
+#define LOOKUP(x, y) mes_lookup(x, x ## _max, y)
+
+char *lookup (struct message *, int);
+char *mes_lookup (struct message *meslist, int max, int index);
+
+extern const char *zlog_priority[];
+
+#endif /* _ZEBRA_LOG_H */
diff --git a/lib/md5-gnu.h b/lib/md5-gnu.h
new file mode 100644
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 <stdio.h>
+
+#if defined HAVE_LIMITS_H || _LIBC
+# include <limits.h>
+#endif
+
+/* The following contortions are an attempt to use the C preprocessor
+ to determine an unsigned integral type that is 32 bits wide. An
+ alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
+ doing that would require that the configure script compile and *run*
+ the resulting executable. Locally running cross-compiled executables
+ is usually not possible. */
+
+#ifdef _LIBC
+# include <sys/types.h>
+typedef u_int32_t md5_uint32;
+#else
+# if defined __STDC__ && __STDC__
+# define UINT_MAX_32_BITS 4294967295U
+# else
+# define UINT_MAX_32_BITS 0xFFFFFFFF
+# endif
+
+/* If UINT_MAX isn't defined, assume it's a 32-bit type.
+ This should be valid for all systems GNU cares about because
+ that doesn't include 16-bit systems, and only modern systems
+ (that certainly have <limits.h>) have 64+-bit integral types. */
+
+# ifndef UINT_MAX
+# define UINT_MAX UINT_MAX_32_BITS
+# endif
+
+# if UINT_MAX == UINT_MAX_32_BITS
+ typedef unsigned int md5_uint32;
+# else
+# if USHRT_MAX == UINT_MAX_32_BITS
+ typedef unsigned short md5_uint32;
+# else
+# if ULONG_MAX == UINT_MAX_32_BITS
+ typedef unsigned long md5_uint32;
+# else
+ /* The following line is intended to evoke an error.
+ Using #error is not portable enough. */
+ "Cannot determine unsigned 32-bit data type."
+# endif
+# endif
+# endif
+#endif
+
+#undef __P
+#if defined (__STDC__) && __STDC__
+# define __P(x) x
+#else
+# define __P(x) ()
+#endif
+
+/* Structure to save state of computation between the single steps. */
+struct md5_ctx
+{
+ md5_uint32 A;
+ md5_uint32 B;
+ md5_uint32 C;
+ md5_uint32 D;
+
+ md5_uint32 total[2];
+ md5_uint32 buflen;
+ char buffer[128];
+};
+
+/*
+ * The following three functions are build up the low level used in
+ * the functions `md5_stream' and `md5_buffer'.
+ */
+
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+extern void __md5_init_ctx __P ((struct md5_ctx *ctx));
+extern void md5_init_ctx __P ((struct md5_ctx *ctx));
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is necessary that LEN is a multiple of 64!!! */
+extern void __md5_process_block __P ((const void *buffer, size_t len,
+ struct md5_ctx *ctx));
+extern void md5_process_block __P ((const void *buffer, size_t len,
+ struct md5_ctx *ctx));
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is NOT required that LEN is a multiple of 64. */
+extern void __md5_process_bytes __P ((const void *buffer, size_t len,
+ struct md5_ctx *ctx));
+extern void md5_process_bytes __P ((const void *buffer, size_t len,
+ struct md5_ctx *ctx));
+
+/* Process the remaining bytes in the buffer and put result from CTX
+ in first 16 bytes following RESBUF. The result is always in little
+ endian byte order, so that a byte-wise output yields to the wanted
+ ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+extern void *__md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));
+extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));
+
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result is
+ always in little endian byte order, so that a byte-wise output yields
+ to the wanted ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+extern void *__md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf));
+extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf));
+
+
+/* Compute MD5 message digest for bytes read from STREAM. The
+ resulting message digest number will be written into the 16 bytes
+ beginning at RESBLOCK. */
+extern int __md5_stream __P ((FILE *stream, void *resblock));
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+extern void *__md5_buffer __P ((const char *buffer, size_t len,
+ void *resblock));
+extern void *md5_buffer __P ((const char *buffer, size_t len,
+ void *resblock));
+
+#endif /* md5.h */
diff --git a/lib/md5.c b/lib/md5.c
new file mode 100644
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 <drepper@gnu.ai.mit.edu>, 1995. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+# include <string.h>
+#else
+# ifndef HAVE_MEMCPY
+# define memcpy(d, s, n) bcopy ((s), (d), (n))
+# endif
+#endif
+
+#include "md5-gnu.h"
+
+#ifdef _LIBC
+# include <endian.h>
+# if __BYTE_ORDER == __BIG_ENDIAN
+# define WORDS_BIGENDIAN 1
+# endif
+/* We need to keep the namespace clean so define the MD5 function
+ protected using leading __ and use weak aliases. */
+# define md5_init_ctx __md5_init_ctx
+# define md5_process_block __md5_process_block
+# define md5_process_bytes __md5_process_bytes
+# define md5_finish_ctx __md5_finish_ctx
+# define md5_read_ctx __md5_read_ctx
+# define md5_stream __md5_stream
+# define md5_buffer __md5_buffer
+#endif
+
+#ifdef WORDS_BIGENDIAN
+# define SWAP(n) \
+ (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
+#else
+# define SWAP(n) (n)
+#endif
+
+
+/* This array contains the bytes used to pad the buffer to the next
+ 64-byte boundary. (RFC 1321, 3.1: Step 1) */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
+
+
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+void
+md5_init_ctx (ctx)
+ struct md5_ctx *ctx;
+{
+ ctx->A = 0x67452301;
+ ctx->B = 0xefcdab89;
+ ctx->C = 0x98badcfe;
+ ctx->D = 0x10325476;
+
+ ctx->total[0] = ctx->total[1] = 0;
+ ctx->buflen = 0;
+}
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result
+ must be in little endian byte order.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+void *
+md5_read_ctx (ctx, resbuf)
+ const struct md5_ctx *ctx;
+ void *resbuf;
+{
+ ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
+ ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
+ ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
+ ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
+
+ return resbuf;
+}
+
+/* Process the remaining bytes in the internal buffer and the usual
+ prolog according to the standard and write the result to RESBUF.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+void *
+md5_finish_ctx (ctx, resbuf)
+ struct md5_ctx *ctx;
+ void *resbuf;
+{
+ /* Take yet unprocessed bytes into account. */
+ md5_uint32 bytes = ctx->buflen;
+ size_t pad;
+
+ /* Now count remaining bytes. */
+ ctx->total[0] += bytes;
+ if (ctx->total[0] < bytes)
+ ++ctx->total[1];
+
+ pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
+ memcpy (&ctx->buffer[bytes], fillbuf, pad);
+
+ /* Put the 64-bit file length in *bits* at the end of the buffer. */
+ *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3);
+ *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) |
+ (ctx->total[0] >> 29));
+
+ /* Process last bytes. */
+ md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
+
+ return md5_read_ctx (ctx, resbuf);
+}
+
+/* Compute MD5 message digest for bytes read from STREAM. The
+ resulting message digest number will be written into the 16 bytes
+ beginning at RESBLOCK. */
+int
+md5_stream (stream, resblock)
+ FILE *stream;
+ void *resblock;
+{
+ /* Important: BLOCKSIZE must be a multiple of 64. */
+#define BLOCKSIZE 4096
+ struct md5_ctx ctx;
+ char buffer[BLOCKSIZE + 72];
+ size_t sum;
+
+ /* Initialize the computation context. */
+ md5_init_ctx (&ctx);
+
+ /* Iterate over full file contents. */
+ while (1)
+ {
+ /* We read the file in blocks of BLOCKSIZE bytes. One call of the
+ computation function processes the whole buffer so that with the
+ next round of the loop another block can be read. */
+ size_t n;
+ sum = 0;
+
+ /* Read block. Take care for partial reads. */
+ do
+ {
+ n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
+
+ sum += n;
+ }
+ while (sum < BLOCKSIZE && n != 0);
+ if (n == 0 && ferror (stream))
+ return 1;
+
+ /* If end of file is reached, end the loop. */
+ if (n == 0)
+ break;
+
+ /* Process buffer with BLOCKSIZE bytes. Note that
+ BLOCKSIZE % 64 == 0
+ */
+ md5_process_block (buffer, BLOCKSIZE, &ctx);
+ }
+
+ /* Add the last bytes if necessary. */
+ if (sum > 0)
+ md5_process_bytes (buffer, sum, &ctx);
+
+ /* Construct result in desired memory. */
+ md5_finish_ctx (&ctx, resblock);
+ return 0;
+}
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+void *
+md5_buffer (buffer, len, resblock)
+ const char *buffer;
+ size_t len;
+ void *resblock;
+{
+ struct md5_ctx ctx;
+
+ /* Initialize the computation context. */
+ md5_init_ctx (&ctx);
+
+ /* Process whole buffer but last len % 64 bytes. */
+ md5_process_bytes (buffer, len, &ctx);
+
+ /* Put result in desired memory area. */
+ return md5_finish_ctx (&ctx, resblock);
+}
+
+
+void
+md5_process_bytes (buffer, len, ctx)
+ const void *buffer;
+ size_t len;
+ struct md5_ctx *ctx;
+{
+ /* When we already have some bits in our internal buffer concatenate
+ both inputs first. */
+ if (ctx->buflen != 0)
+ {
+ size_t left_over = ctx->buflen;
+ size_t add = 128 - left_over > len ? len : 128 - left_over;
+
+ memcpy (&ctx->buffer[left_over], buffer, add);
+ ctx->buflen += add;
+
+ if (left_over + add > 64)
+ {
+ md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx);
+ /* The regions in the following copy operation cannot overlap. */
+ memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
+ (left_over + add) & 63);
+ ctx->buflen = (left_over + add) & 63;
+ }
+
+ buffer = (const char *) buffer + add;
+ len -= add;
+ }
+
+ /* Process available complete blocks. */
+ if (len > 64)
+ {
+ md5_process_block (buffer, len & ~63, ctx);
+ buffer = (const char *) buffer + (len & ~63);
+ len &= 63;
+ }
+
+ /* Move remaining bytes in internal buffer. */
+ if (len > 0)
+ {
+ memcpy (ctx->buffer, buffer, len);
+ ctx->buflen = len;
+ }
+}
+
+
+/* These are the four functions used in the four steps of the MD5 algorithm
+ and defined in the RFC 1321. The first function is a little bit optimized
+ (as found in Colin Plumbs public domain implementation). */
+/* #define FF(b, c, d) ((b & c) | (~b & d)) */
+#define FF(b, c, d) (d ^ (b & (c ^ d)))
+#define FG(b, c, d) FF (d, b, c)
+#define FH(b, c, d) (b ^ c ^ d)
+#define FI(b, c, d) (c ^ (b | ~d))
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+ It is assumed that LEN % 64 == 0. */
+
+void
+md5_process_block (buffer, len, ctx)
+ const void *buffer;
+ size_t len;
+ struct md5_ctx *ctx;
+{
+ md5_uint32 correct_words[16];
+ const md5_uint32 *words = buffer;
+ size_t nwords = len / sizeof (md5_uint32);
+ const md5_uint32 *endp = words + nwords;
+ md5_uint32 A = ctx->A;
+ md5_uint32 B = ctx->B;
+ md5_uint32 C = ctx->C;
+ md5_uint32 D = ctx->D;
+
+ /* First increment the byte count. RFC 1321 specifies the possible
+ length of the file up to 2^64 bits. Here we only compute the
+ number of bytes. Do a double word increment. */
+ ctx->total[0] += len;
+ if (ctx->total[0] < len)
+ ++ctx->total[1];
+
+ /* Process all bytes in the buffer with 64 bytes in each round of
+ the loop. */
+ while (words < endp)
+ {
+ md5_uint32 *cwp = correct_words;
+ md5_uint32 A_save = A;
+ md5_uint32 B_save = B;
+ md5_uint32 C_save = C;
+ md5_uint32 D_save = D;
+
+ /* First round: using the given function, the context and a constant
+ the next context is computed. Because the algorithms processing
+ unit is a 32-bit word and it is determined to work on words in
+ little endian byte order we perhaps have to change the byte order
+ before the computation. To reduce the work for the next steps
+ we store the swapped words in the array CORRECT_WORDS. */
+
+#define OP(a, b, c, d, s, T) \
+ do \
+ { \
+ a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
+ ++words; \
+ CYCLIC (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* It is unfortunate that C does not provide an operator for
+ cyclic rotation. Hope the C compiler is smart enough. */
+#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
+
+ /* Before we start, one word to the strange constants.
+ They are defined in RFC 1321 as
+
+ T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
+ */
+
+ /* Round 1. */
+ OP (A, B, C, D, 7, 0xd76aa478);
+ OP (D, A, B, C, 12, 0xe8c7b756);
+ OP (C, D, A, B, 17, 0x242070db);
+ OP (B, C, D, A, 22, 0xc1bdceee);
+ OP (A, B, C, D, 7, 0xf57c0faf);
+ OP (D, A, B, C, 12, 0x4787c62a);
+ OP (C, D, A, B, 17, 0xa8304613);
+ OP (B, C, D, A, 22, 0xfd469501);
+ OP (A, B, C, D, 7, 0x698098d8);
+ OP (D, A, B, C, 12, 0x8b44f7af);
+ OP (C, D, A, B, 17, 0xffff5bb1);
+ OP (B, C, D, A, 22, 0x895cd7be);
+ OP (A, B, C, D, 7, 0x6b901122);
+ OP (D, A, B, C, 12, 0xfd987193);
+ OP (C, D, A, B, 17, 0xa679438e);
+ OP (B, C, D, A, 22, 0x49b40821);
+
+ /* For the second to fourth round we have the possibly swapped words
+ in CORRECT_WORDS. Redefine the macro to take an additional first
+ argument specifying the function to use. */
+#undef OP
+#define OP(f, a, b, c, d, k, s, T) \
+ do \
+ { \
+ a += f (b, c, d) + correct_words[k] + T; \
+ CYCLIC (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* Round 2. */
+ OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
+ OP (FG, D, A, B, C, 6, 9, 0xc040b340);
+ OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
+ OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
+ OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
+ OP (FG, D, A, B, C, 10, 9, 0x02441453);
+ OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
+ OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
+ OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
+ OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
+ OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
+ OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
+ OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
+ OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
+ OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
+ OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
+
+ /* Round 3. */
+ OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
+ OP (FH, D, A, B, C, 8, 11, 0x8771f681);
+ OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
+ OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
+ OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
+ OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
+ OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
+ OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
+ OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
+ OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
+ OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
+ OP (FH, B, C, D, A, 6, 23, 0x04881d05);
+ OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
+ OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
+ OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
+ OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
+
+ /* Round 4. */
+ OP (FI, A, B, C, D, 0, 6, 0xf4292244);
+ OP (FI, D, A, B, C, 7, 10, 0x432aff97);
+ OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
+ OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
+ OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
+ OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
+ OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
+ OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
+ OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
+ OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
+ OP (FI, C, D, A, B, 6, 15, 0xa3014314);
+ OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
+ OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
+ OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
+ OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
+ OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
+
+ /* Add the starting values of the context. */
+ A += A_save;
+ B += B_save;
+ C += C_save;
+ D += D_save;
+ }
+
+ /* Put checksum in context given as argument. */
+ ctx->A = A;
+ ctx->B = B;
+ ctx->C = C;
+ ctx->D = D;
+}
+
+
+#ifdef _LIBC
+/* Define weak aliases. */
+# undef md5_init_ctx
+weak_alias (__md5_init_ctx, md5_init_ctx)
+# undef md5_process_block
+weak_alias (__md5_process_block, md5_process_block)
+# undef md5_process_bytes
+weak_alias (__md5_process_bytes, md5_process_bytes)
+# undef md5_finish_ctx
+weak_alias (__md5_finish_ctx, md5_finish_ctx)
+# undef md5_read_ctx
+weak_alias (__md5_read_ctx, md5_read_ctx)
+# undef md5_stream
+weak_alias (__md5_stream, md5_stream)
+# undef md5_buffer
+weak_alias (__md5_buffer, md5_buffer)
+#endif
diff --git a/lib/memory.c b/lib/memory.c
new file mode 100644
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 <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+
+void alloc_inc (int);
+void alloc_dec (int);
+
+struct message mstr [] =
+{
+ { MTYPE_THREAD, "thread" },
+ { MTYPE_THREAD_MASTER, "thread_master" },
+ { MTYPE_VECTOR, "vector" },
+ { MTYPE_VECTOR_INDEX, "vector_index" },
+ { MTYPE_IF, "interface" },
+ { 0, NULL },
+};
+
+/* Fatal memory allocation error occured. */
+static void
+zerror (const char *fname, int type, size_t size)
+{
+ fprintf (stderr, "%s : can't allocate memory for `%s' size %d\n",
+ fname, lookup (mstr, type), (int) size);
+ exit (1);
+}
+
+/* Memory allocation. */
+void *
+zmalloc (int type, size_t size)
+{
+ void *memory;
+
+ memory = malloc (size);
+
+ if (memory == NULL)
+ zerror ("malloc", type, size);
+
+ alloc_inc (type);
+
+ return memory;
+}
+
+/* Memory allocation with num * size with cleared. */
+void *
+zcalloc (int type, size_t size)
+{
+ void *memory;
+
+ memory = calloc (1, size);
+
+ if (memory == NULL)
+ zerror ("calloc", type, size);
+
+ alloc_inc (type);
+
+ return memory;
+}
+
+/* Memory reallocation. */
+void *
+zrealloc (int type, void *ptr, size_t size)
+{
+ void *memory;
+
+ memory = realloc (ptr, size);
+ if (memory == NULL)
+ zerror ("realloc", type, size);
+ return memory;
+}
+
+/* Memory free. */
+void
+zfree (int type, void *ptr)
+{
+ alloc_dec (type);
+ free (ptr);
+}
+
+/* String duplication. */
+char *
+zstrdup (int type, char *str)
+{
+ void *dup;
+
+ dup = strdup (str);
+ if (dup == NULL)
+ zerror ("strdup", type, strlen (str));
+ alloc_inc (type);
+ return dup;
+}
+
+#ifdef MEMORY_LOG
+struct
+{
+ char *name;
+ unsigned long alloc;
+ unsigned long t_malloc;
+ unsigned long c_malloc;
+ unsigned long t_calloc;
+ unsigned long c_calloc;
+ unsigned long t_realloc;
+ unsigned long t_free;
+ unsigned long c_strdup;
+} mstat [MTYPE_MAX];
+
+void
+mtype_log (char *func, void *memory, const char *file, int line, int type)
+{
+ zlog_info ("%s: %s %p %s %d", func, lookup (mstr, type), memory, file, line);
+}
+
+void *
+mtype_zmalloc (const char *file, int line, int type, size_t size)
+{
+ void *memory;
+
+ mstat[type].c_malloc++;
+ mstat[type].t_malloc++;
+
+ memory = zmalloc (type, size);
+ mtype_log ("zmalloc", memory, file, line, type);
+
+ return memory;
+}
+
+void *
+mtype_zcalloc (const char *file, int line, int type, size_t size)
+{
+ void *memory;
+
+ mstat[type].c_calloc++;
+ mstat[type].t_calloc++;
+
+ memory = zcalloc (type, size);
+ mtype_log ("xcalloc", memory, file, line, type);
+
+ return memory;
+}
+
+void *
+mtype_zrealloc (const char *file, int line, int type, void *ptr, size_t size)
+{
+ void *memory;
+
+ /* Realloc need before allocated pointer. */
+ mstat[type].t_realloc++;
+
+ memory = zrealloc (type, ptr, size);
+
+ mtype_log ("xrealloc", memory, file, line, type);
+
+ return memory;
+}
+
+/* Important function. */
+void
+mtype_zfree (const char *file, int line, int type, void *ptr)
+{
+ mstat[type].t_free++;
+
+ mtype_log ("xfree", ptr, file, line, type);
+
+ zfree (type, ptr);
+}
+
+char *
+mtype_zstrdup (const char *file, int line, int type, char *str)
+{
+ char *memory;
+
+ mstat[type].c_strdup++;
+
+ memory = zstrdup (type, str);
+
+ mtype_log ("xstrdup", memory, file, line, type);
+
+ return memory;
+}
+#else
+struct
+{
+ char *name;
+ unsigned long alloc;
+} mstat [MTYPE_MAX];
+#endif /* MTPYE_LOG */
+
+/* Increment allocation counter. */
+void
+alloc_inc (int type)
+{
+ mstat[type].alloc++;
+}
+
+/* Decrement allocation counter. */
+void
+alloc_dec (int type)
+{
+ mstat[type].alloc--;
+}
+
+/* Looking up memory status from vty interface. */
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+
+/* For pretty printng of memory allocate information. */
+struct memory_list
+{
+ int index;
+ char *format;
+};
+
+struct memory_list memory_list_lib[] =
+{
+ { MTYPE_TMP, "Temporary memory" },
+ { MTYPE_ROUTE_TABLE, "Route table " },
+ { MTYPE_ROUTE_NODE, "Route node " },
+ { MTYPE_RIB, "RIB " },
+ { MTYPE_NEXTHOP, "Nexthop " },
+ { MTYPE_LINK_LIST, "Link List " },
+ { MTYPE_LINK_NODE, "Link Node " },
+ { MTYPE_HASH, "Hash " },
+ { MTYPE_HASH_BACKET, "Hash Bucket " },
+ { MTYPE_ACCESS_LIST, "Access List " },
+ { MTYPE_ACCESS_LIST_STR, "Access List Str " },
+ { MTYPE_ACCESS_FILTER, "Access Filter " },
+ { MTYPE_PREFIX_LIST, "Prefix List " },
+ { MTYPE_PREFIX_LIST_STR, "Prefix List Str " },
+ { MTYPE_PREFIX_LIST_ENTRY, "Prefix List Entry "},
+ { MTYPE_ROUTE_MAP, "Route map " },
+ { MTYPE_ROUTE_MAP_NAME, "Route map name " },
+ { MTYPE_ROUTE_MAP_INDEX, "Route map index " },
+ { MTYPE_ROUTE_MAP_RULE, "Route map rule " },
+ { MTYPE_ROUTE_MAP_RULE_STR, "Route map rule str" },
+ { MTYPE_DESC, "Command desc " },
+ { MTYPE_BUFFER, "Buffer " },
+ { MTYPE_BUFFER_DATA, "Buffer data " },
+ { MTYPE_STREAM, "Stream " },
+ { MTYPE_KEYCHAIN, "Key chain " },
+ { MTYPE_KEY, "Key " },
+ { MTYPE_VTY, "VTY " },
+ { -1, NULL }
+};
+
+struct memory_list memory_list_bgp[] =
+{
+ { MTYPE_BGP_PEER, "BGP peer" },
+ { MTYPE_ATTR, "BGP attribute" },
+ { MTYPE_AS_PATH, "BGP aspath" },
+ { MTYPE_AS_SEG, "BGP aspath seg" },
+ { MTYPE_AS_STR, "BGP aspath str" },
+ { 0, NULL },
+ { MTYPE_BGP_TABLE, "BGP table" },
+ { MTYPE_BGP_NODE, "BGP node" },
+ { MTYPE_BGP_ADVERTISE_ATTR, "BGP adv attr" },
+ { MTYPE_BGP_ADVERTISE, "BGP adv" },
+ { MTYPE_BGP_ADJ_IN, "BGP adj in" },
+ { MTYPE_BGP_ADJ_OUT, "BGP adj out" },
+ { 0, NULL },
+ { MTYPE_AS_LIST, "BGP AS list" },
+ { MTYPE_AS_FILTER, "BGP AS filter" },
+ { MTYPE_AS_FILTER_STR, "BGP AS filter str" },
+ { 0, NULL },
+ { MTYPE_COMMUNITY, "community" },
+ { MTYPE_COMMUNITY_VAL, "community val" },
+ { MTYPE_COMMUNITY_STR, "community str" },
+ { 0, NULL },
+ { MTYPE_ECOMMUNITY, "extcommunity" },
+ { MTYPE_ECOMMUNITY_VAL, "extcommunity val" },
+ { MTYPE_ECOMMUNITY_STR, "extcommunity str" },
+ { 0, NULL },
+ { MTYPE_COMMUNITY_LIST, "community-list" },
+ { MTYPE_COMMUNITY_LIST_NAME, "community-list name" },
+ { MTYPE_COMMUNITY_LIST_ENTRY, "community-list entry" },
+ { MTYPE_COMMUNITY_LIST_CONFIG, "community-list config" },
+ { 0, NULL },
+ { MTYPE_CLUSTER, "Cluster list" },
+ { MTYPE_CLUSTER_VAL, "Cluster list val" },
+ { 0, NULL },
+ { MTYPE_TRANSIT, "BGP transit attr" },
+ { MTYPE_TRANSIT_VAL, "BGP transit val" },
+ { 0, NULL },
+ { MTYPE_BGP_DISTANCE, "BGP distance" },
+ { MTYPE_BGP_NEXTHOP_CACHE, "BGP nexthop" },
+ { MTYPE_BGP_CONFED_LIST, "BGP confed list" },
+ { MTYPE_PEER_UPDATE_SOURCE, "peer update if" },
+ { MTYPE_BGP_DAMP_INFO, "Dampening info" },
+ { MTYPE_BGP_REGEXP, "BGP regexp" },
+ { -1, NULL }
+};
+
+struct memory_list memory_list_rip[] =
+{
+ { MTYPE_RIP, "RIP structure " },
+ { MTYPE_RIP_INFO, "RIP route info " },
+ { MTYPE_RIP_INTERFACE, "RIP interface " },
+ { MTYPE_RIP_PEER, "RIP peer " },
+ { MTYPE_RIP_OFFSET_LIST, "RIP offset list " },
+ { MTYPE_RIP_DISTANCE, "RIP distance " },
+ { -1, NULL }
+};
+
+struct memory_list memory_list_ospf[] =
+{
+ { MTYPE_OSPF_TOP, "OSPF top " },
+ { MTYPE_OSPF_AREA, "OSPF area " },
+ { MTYPE_OSPF_AREA_RANGE, "OSPF area range " },
+ { MTYPE_OSPF_NETWORK, "OSPF network " },
+#ifdef NBMA_ENABLE
+ { MTYPE_OSPF_NEIGHBOR_STATIC,"OSPF static nbr " },
+#endif /* NBMA_ENABLE */
+ { MTYPE_OSPF_IF, "OSPF interface " },
+ { MTYPE_OSPF_NEIGHBOR, "OSPF neighbor " },
+ { MTYPE_OSPF_ROUTE, "OSPF route " },
+ { MTYPE_OSPF_TMP, "OSPF tmp mem " },
+ { MTYPE_OSPF_LSA, "OSPF LSA " },
+ { MTYPE_OSPF_LSA_DATA, "OSPF LSA data " },
+ { MTYPE_OSPF_LSDB, "OSPF LSDB " },
+ { MTYPE_OSPF_PACKET, "OSPF packet " },
+ { MTYPE_OSPF_FIFO, "OSPF FIFO queue " },
+ { MTYPE_OSPF_VERTEX, "OSPF vertex " },
+ { MTYPE_OSPF_NEXTHOP, "OSPF nexthop " },
+ { MTYPE_OSPF_PATH, "OSPF path " },
+ { MTYPE_OSPF_VL_DATA, "OSPF VL data " },
+ { MTYPE_OSPF_CRYPT_KEY, "OSPF crypt key " },
+ { MTYPE_OSPF_EXTERNAL_INFO, "OSPF ext. info " },
+ { MTYPE_OSPF_DISTANCE, "OSPF distance " },
+ { MTYPE_OSPF_IF_INFO, "OSPF if info " },
+ { MTYPE_OSPF_IF_PARAMS, "OSPF if params " },
+ { -1, NULL },
+};
+
+struct memory_list memory_list_ospf6[] =
+{
+ { MTYPE_OSPF6_TOP, "OSPF6 top " },
+ { MTYPE_OSPF6_AREA, "OSPF6 area " },
+ { MTYPE_OSPF6_IF, "OSPF6 interface " },
+ { MTYPE_OSPF6_NEIGHBOR, "OSPF6 neighbor " },
+ { MTYPE_OSPF6_ROUTE, "OSPF6 route " },
+ { MTYPE_OSPF6_PREFIX, "OSPF6 prefix " },
+ { MTYPE_OSPF6_MESSAGE, "OSPF6 message " },
+ { MTYPE_OSPF6_LSA, "OSPF6 LSA " },
+ { MTYPE_OSPF6_LSA_SUMMARY, "OSPF6 LSA summary " },
+ { MTYPE_OSPF6_LSDB, "OSPF6 LSA database" },
+ { MTYPE_OSPF6_VERTEX, "OSPF6 vertex " },
+ { MTYPE_OSPF6_SPFTREE, "OSPF6 SPF tree " },
+ { MTYPE_OSPF6_NEXTHOP, "OSPF6 nexthop " },
+ { MTYPE_OSPF6_EXTERNAL_INFO,"OSPF6 ext. info " },
+ { MTYPE_OSPF6_OTHER, "OSPF6 other " },
+ { -1, NULL },
+};
+
+struct memory_list memory_list_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 <zebra.h>
+
+/* Read nbytes from fd and store into ptr. */
+int
+readn (int fd, char *ptr, int nbytes)
+{
+ int nleft;
+ int nread;
+
+ nleft = nbytes;
+
+ while (nleft > 0)
+ {
+ nread = read (fd, ptr, nleft);
+
+ if (nread < 0)
+ return (nread);
+ else
+ if (nread == 0)
+ break;
+
+ nleft -= nread;
+ ptr += nread;
+ }
+
+ return nbytes - nleft;
+}
+
+/* Write nbytes from ptr to fd. */
+int
+writen(int fd, char *ptr, int nbytes)
+{
+ int nleft;
+ int nwritten;
+
+ nleft = nbytes;
+
+ while (nleft > 0)
+ {
+ nwritten = write(fd, ptr, nleft);
+
+ if (nwritten <= 0)
+ return (nwritten);
+
+ nleft -= nwritten;
+ ptr += nwritten;
+ }
+ return nbytes - nleft;
+}
diff --git a/lib/network.h b/lib/network.h
new file mode 100644
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 <zebra.h>
+
+pid_t
+pid_output (char *path)
+{
+ FILE *fp;
+ pid_t pid;
+
+ pid = getpid();
+
+ fp = fopen (path, "w");
+ if (fp != NULL)
+ {
+ fprintf (fp, "%d\n", (int) pid);
+ fclose (fp);
+ return -1;
+ }
+ return pid;
+}
+
+pid_t
+pid_output_lock (char *path)
+{
+ int tmp;
+ int fd;
+ pid_t pid;
+ char buf[16], *p;
+
+ pid = getpid ();
+
+ fd = open (path, O_RDWR | O_CREAT | O_EXCL, 0644);
+ if (fd < 0)
+ {
+ fd = open (path, O_RDONLY);
+ if (fd < 0)
+ fprintf (stderr, "Can't creat pid lock file, exit\n");
+ else
+ {
+ read (fd, buf, sizeof (buf));
+ if ((p = index (buf, '\n')) != NULL)
+ *p = 0;
+ fprintf (stderr, "Another process(%s) running, exit\n", buf);
+ }
+ exit (-1);
+ }
+ else
+ {
+ sprintf (buf, "%d\n", (int) pid);
+ tmp = write (fd, buf, strlen (buf));
+ close (fd);
+ }
+
+ return pid;
+}
+
diff --git a/lib/plist.c b/lib/plist.c
new file mode 100644
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 <zebra.h>
+
+#include "prefix.h"
+#include "command.h"
+#include "memory.h"
+#include "plist.h"
+#include "sockunion.h"
+#include "buffer.h"
+
+/* Each prefix-list's entry. */
+struct prefix_list_entry
+{
+ int seq;
+
+ int le;
+ int ge;
+
+ enum prefix_list_type type;
+
+ int any;
+ struct prefix prefix;
+
+ unsigned long refcnt;
+ unsigned long hitcnt;
+
+ struct prefix_list_entry *next;
+ struct prefix_list_entry *prev;
+};
+
+/* List of struct prefix_list. */
+struct prefix_list_list
+{
+ struct prefix_list *head;
+ struct prefix_list *tail;
+};
+
+/* Master structure of prefix_list. */
+struct prefix_master
+{
+ /* List of prefix_list which name is number. */
+ struct prefix_list_list num;
+
+ /* List of prefix_list which name is string. */
+ struct prefix_list_list str;
+
+ /* Whether sequential number is used. */
+ int seqnum;
+
+ /* The latest update. */
+ struct prefix_list *recent;
+
+ /* Hook function which is executed when new prefix_list is added. */
+ void (*add_hook) ();
+
+ /* Hook function which is executed when prefix_list is deleted. */
+ void (*delete_hook) ();
+};
+
+/* Static structure of IPv4 prefix_list's master. */
+static struct prefix_master prefix_master_ipv4 =
+{
+ {NULL, NULL},
+ {NULL, NULL},
+ 1,
+ NULL,
+ NULL,
+};
+
+#ifdef HAVE_IPV6
+/* Static structure of IPv6 prefix-list's master. */
+static struct prefix_master prefix_master_ipv6 =
+{
+ {NULL, NULL},
+ {NULL, NULL},
+ 1,
+ NULL,
+ NULL,
+};
+#endif /* HAVE_IPV6*/
+
+/* Static structure of BGP ORF prefix_list's master. */
+static struct prefix_master prefix_master_orf =
+{
+ {NULL, NULL},
+ {NULL, NULL},
+ 1,
+ NULL,
+ NULL,
+};
+
+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 <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL,
+ argv[1], argv[2], NULL, NULL);
+}
+
+DEFUN (ip_prefix_list_ge,
+ ip_prefix_list_ge_cmd,
+ "ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32>",
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1],
+ argv[2], argv[3], NULL);
+}
+
+DEFUN (ip_prefix_list_ge_le,
+ ip_prefix_list_ge_le_cmd,
+ "ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32> le <0-32>",
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1],
+ argv[2], argv[3], argv[4]);
+}
+
+DEFUN (ip_prefix_list_le,
+ ip_prefix_list_le_cmd,
+ "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>",
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1],
+ argv[2], NULL, argv[3]);
+}
+
+DEFUN (ip_prefix_list_le_ge,
+ ip_prefix_list_le_ge_cmd,
+ "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32> ge <0-32>",
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1],
+ argv[2], argv[4], argv[3]);
+}
+
+DEFUN (ip_prefix_list_seq,
+ ip_prefix_list_seq_cmd,
+ "ip prefix-list WORD seq <1-4294967295> (deny|permit) (A.B.C.D/M|any)",
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2],
+ argv[3], NULL, NULL);
+}
+
+DEFUN (ip_prefix_list_seq_ge,
+ ip_prefix_list_seq_ge_cmd,
+ "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32>",
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2],
+ argv[3], argv[4], NULL);
+}
+
+DEFUN (ip_prefix_list_seq_ge_le,
+ ip_prefix_list_seq_ge_le_cmd,
+ "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>",
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2],
+ argv[3], argv[4], argv[5]);
+}
+
+DEFUN (ip_prefix_list_seq_le,
+ ip_prefix_list_seq_le_cmd,
+ "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32>",
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2],
+ argv[3], NULL, argv[4]);
+}
+
+DEFUN (ip_prefix_list_seq_le_ge,
+ ip_prefix_list_seq_le_ge_cmd,
+ "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32> ge <0-32>",
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2],
+ argv[3], argv[5], argv[4]);
+}
+
+DEFUN (no_ip_prefix_list,
+ no_ip_prefix_list_cmd,
+ "no ip prefix-list WORD",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, NULL,
+ NULL, NULL, NULL);
+}
+
+DEFUN (no_ip_prefix_list_prefix,
+ no_ip_prefix_list_prefix_cmd,
+ "no ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1],
+ argv[2], NULL, NULL);
+}
+
+DEFUN (no_ip_prefix_list_ge,
+ no_ip_prefix_list_ge_cmd,
+ "no ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32>",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1],
+ argv[2], argv[3], NULL);
+}
+
+DEFUN (no_ip_prefix_list_ge_le,
+ no_ip_prefix_list_ge_le_cmd,
+ "no ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32> le <0-32>",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1],
+ argv[2], argv[3], argv[4]);
+}
+
+DEFUN (no_ip_prefix_list_le,
+ no_ip_prefix_list_le_cmd,
+ "no ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1],
+ argv[2], NULL, argv[3]);
+}
+
+DEFUN (no_ip_prefix_list_le_ge,
+ no_ip_prefix_list_le_ge_cmd,
+ "no ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32> ge <0-32>",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1],
+ argv[2], argv[4], argv[3]);
+}
+
+DEFUN (no_ip_prefix_list_seq,
+ no_ip_prefix_list_seq_cmd,
+ "no ip prefix-list WORD seq <1-4294967295> (deny|permit) (A.B.C.D/M|any)",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2],
+ argv[3], NULL, NULL);
+}
+
+DEFUN (no_ip_prefix_list_seq_ge,
+ no_ip_prefix_list_seq_ge_cmd,
+ "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32>",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2],
+ argv[3], argv[4], NULL);
+}
+
+DEFUN (no_ip_prefix_list_seq_ge_le,
+ no_ip_prefix_list_seq_ge_le_cmd,
+ "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2],
+ argv[3], argv[4], argv[5]);
+}
+
+DEFUN (no_ip_prefix_list_seq_le,
+ no_ip_prefix_list_seq_le_cmd,
+ "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32>",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2],
+ argv[3], NULL, argv[4]);
+}
+
+DEFUN (no_ip_prefix_list_seq_le_ge,
+ no_ip_prefix_list_seq_le_ge_cmd,
+ "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32> ge <0-32>",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2],
+ argv[3], argv[5], argv[4]);
+}
+
+DEFUN (ip_prefix_list_sequence_number,
+ ip_prefix_list_sequence_number_cmd,
+ "ip prefix-list sequence-number",
+ IP_STR
+ PREFIX_LIST_STR
+ "Include/exclude sequence numbers in NVGEN\n")
+{
+ prefix_master_ipv4.seqnum = 1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_prefix_list_sequence_number,
+ no_ip_prefix_list_sequence_number_cmd,
+ "no ip prefix-list sequence-number",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Include/exclude sequence numbers in NVGEN\n")
+{
+ prefix_master_ipv4.seqnum = 0;
+ return CMD_SUCCESS;
+}
+
+DEFUN (ip_prefix_list_description,
+ ip_prefix_list_description_cmd,
+ "ip prefix-list WORD description .LINE",
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Prefix-list specific description\n"
+ "Up to 80 characters describing this prefix-list\n")
+{
+ struct prefix_list *plist;
+ struct buffer *b;
+ int i;
+
+ plist = prefix_list_get (AFI_IP, argv[0]);
+
+ if (plist->desc)
+ {
+ XFREE (MTYPE_TMP, plist->desc);
+ plist->desc = NULL;
+ }
+
+ /* Below is description get codes. */
+ b = buffer_new (1024);
+ for (i = 1; i < argc; i++)
+ {
+ buffer_putstr (b, (u_char *)argv[i]);
+ buffer_putc (b, ' ');
+ }
+ buffer_putc (b, '\0');
+
+ plist->desc = buffer_getstr (b);
+
+ buffer_free (b);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_prefix_list_description,
+ no_ip_prefix_list_description_cmd,
+ "no ip prefix-list WORD description",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Prefix-list specific description\n")
+{
+ return vty_prefix_list_desc_unset (vty, AFI_IP, argv[0]);
+}
+
+ALIAS (no_ip_prefix_list_description,
+ no_ip_prefix_list_description_arg_cmd,
+ "no ip prefix-list WORD description .LINE",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Prefix-list specific description\n"
+ "Up to 80 characters describing this prefix-list\n")
+
+DEFUN (show_ip_prefix_list,
+ show_ip_prefix_list_cmd,
+ "show ip prefix-list",
+ SHOW_STR
+ IP_STR
+ PREFIX_LIST_STR)
+{
+ return vty_show_prefix_list (vty, AFI_IP, NULL, NULL, normal_display);
+}
+
+DEFUN (show_ip_prefix_list_name,
+ show_ip_prefix_list_name_cmd,
+ "show ip prefix-list WORD",
+ SHOW_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n")
+{
+ return vty_show_prefix_list (vty, AFI_IP, argv[0], NULL, normal_display);
+}
+
+DEFUN (show_ip_prefix_list_name_seq,
+ show_ip_prefix_list_name_seq_cmd,
+ "show ip prefix-list WORD seq <1-4294967295>",
+ SHOW_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n")
+{
+ return vty_show_prefix_list (vty, AFI_IP, argv[0], argv[1], sequential_display);
+}
+
+DEFUN (show_ip_prefix_list_prefix,
+ show_ip_prefix_list_prefix_cmd,
+ "show ip prefix-list WORD A.B.C.D/M",
+ SHOW_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+ return vty_show_prefix_list_prefix (vty, AFI_IP, argv[0], argv[1], normal_display);
+}
+
+DEFUN (show_ip_prefix_list_prefix_longer,
+ show_ip_prefix_list_prefix_longer_cmd,
+ "show ip prefix-list WORD A.B.C.D/M longer",
+ SHOW_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Lookup longer prefix\n")
+{
+ return vty_show_prefix_list_prefix (vty, AFI_IP, argv[0], argv[1], longer_display);
+}
+
+DEFUN (show_ip_prefix_list_prefix_first_match,
+ show_ip_prefix_list_prefix_first_match_cmd,
+ "show ip prefix-list WORD A.B.C.D/M first-match",
+ SHOW_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "First matched prefix\n")
+{
+ return vty_show_prefix_list_prefix (vty, AFI_IP, argv[0], argv[1], first_match_display);
+}
+
+DEFUN (show_ip_prefix_list_summary,
+ show_ip_prefix_list_summary_cmd,
+ "show ip prefix-list summary",
+ SHOW_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Summary of prefix lists\n")
+{
+ return vty_show_prefix_list (vty, AFI_IP, NULL, NULL, summary_display);
+}
+
+DEFUN (show_ip_prefix_list_summary_name,
+ show_ip_prefix_list_summary_name_cmd,
+ "show ip prefix-list summary WORD",
+ SHOW_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Summary of prefix lists\n"
+ "Name of a prefix list\n")
+{
+ return vty_show_prefix_list (vty, AFI_IP, argv[0], NULL, summary_display);
+}
+
+
+DEFUN (show_ip_prefix_list_detail,
+ show_ip_prefix_list_detail_cmd,
+ "show ip prefix-list detail",
+ SHOW_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Detail of prefix lists\n")
+{
+ return vty_show_prefix_list (vty, AFI_IP, NULL, NULL, detail_display);
+}
+
+DEFUN (show_ip_prefix_list_detail_name,
+ show_ip_prefix_list_detail_name_cmd,
+ "show ip prefix-list detail WORD",
+ SHOW_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Detail of prefix lists\n"
+ "Name of a prefix list\n")
+{
+ return vty_show_prefix_list (vty, AFI_IP, argv[0], NULL, detail_display);
+}
+
+DEFUN (clear_ip_prefix_list,
+ clear_ip_prefix_list_cmd,
+ "clear ip prefix-list",
+ CLEAR_STR
+ IP_STR
+ PREFIX_LIST_STR)
+{
+ return vty_clear_prefix_list (vty, AFI_IP, NULL, NULL);
+}
+
+DEFUN (clear_ip_prefix_list_name,
+ clear_ip_prefix_list_name_cmd,
+ "clear ip prefix-list WORD",
+ CLEAR_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n")
+{
+ return vty_clear_prefix_list (vty, AFI_IP, argv[0], NULL);
+}
+
+DEFUN (clear_ip_prefix_list_name_prefix,
+ clear_ip_prefix_list_name_prefix_cmd,
+ "clear ip prefix-list WORD A.B.C.D/M",
+ CLEAR_STR
+ IP_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+ return vty_clear_prefix_list (vty, AFI_IP, argv[0], argv[1]);
+}
+
+#ifdef HAVE_IPV6
+DEFUN (ipv6_prefix_list,
+ ipv6_prefix_list_cmd,
+ "ipv6 prefix-list WORD (deny|permit) (X:X::X:X/M|any)",
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Any prefix match. Same as \"::0/0 le 128\"\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL,
+ argv[1], argv[2], NULL, NULL);
+}
+
+DEFUN (ipv6_prefix_list_ge,
+ ipv6_prefix_list_ge_cmd,
+ "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128>",
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1],
+ argv[2], argv[3], NULL);
+}
+
+DEFUN (ipv6_prefix_list_ge_le,
+ ipv6_prefix_list_ge_le_cmd,
+ "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128> le <0-128>",
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+
+{
+ return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1],
+ argv[2], argv[3], argv[4]);
+}
+
+DEFUN (ipv6_prefix_list_le,
+ ipv6_prefix_list_le_cmd,
+ "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128>",
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1],
+ argv[2], NULL, argv[3]);
+}
+
+DEFUN (ipv6_prefix_list_le_ge,
+ ipv6_prefix_list_le_ge_cmd,
+ "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128> ge <0-128>",
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1],
+ argv[2], argv[4], argv[3]);
+}
+
+DEFUN (ipv6_prefix_list_seq,
+ ipv6_prefix_list_seq_cmd,
+ "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) (X:X::X:X/M|any)",
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Any prefix match. Same as \"::0/0 le 128\"\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2],
+ argv[3], NULL, NULL);
+}
+
+DEFUN (ipv6_prefix_list_seq_ge,
+ ipv6_prefix_list_seq_ge_cmd,
+ "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128>",
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2],
+ argv[3], argv[4], NULL);
+}
+
+DEFUN (ipv6_prefix_list_seq_ge_le,
+ ipv6_prefix_list_seq_ge_le_cmd,
+ "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128> le <0-128>",
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2],
+ argv[3], argv[4], argv[5]);
+}
+
+DEFUN (ipv6_prefix_list_seq_le,
+ ipv6_prefix_list_seq_le_cmd,
+ "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128>",
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2],
+ argv[3], NULL, argv[4]);
+}
+
+DEFUN (ipv6_prefix_list_seq_le_ge,
+ ipv6_prefix_list_seq_le_ge_cmd,
+ "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128> ge <0-128>",
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+{
+ return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2],
+ argv[3], argv[5], argv[4]);
+}
+
+DEFUN (no_ipv6_prefix_list,
+ no_ipv6_prefix_list_cmd,
+ "no ipv6 prefix-list WORD",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, NULL,
+ NULL, NULL, NULL);
+}
+
+DEFUN (no_ipv6_prefix_list_prefix,
+ no_ipv6_prefix_list_prefix_cmd,
+ "no ipv6 prefix-list WORD (deny|permit) (X:X::X:X/M|any)",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Any prefix match. Same as \"::0/0 le 128\"\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1],
+ argv[2], NULL, NULL);
+}
+
+DEFUN (no_ipv6_prefix_list_ge,
+ no_ipv6_prefix_list_ge_cmd,
+ "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128>",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1],
+ argv[2], argv[3], NULL);
+}
+
+DEFUN (no_ipv6_prefix_list_ge_le,
+ no_ipv6_prefix_list_ge_le_cmd,
+ "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128> le <0-128>",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1],
+ argv[2], argv[3], argv[4]);
+}
+
+DEFUN (no_ipv6_prefix_list_le,
+ no_ipv6_prefix_list_le_cmd,
+ "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128>",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1],
+ argv[2], NULL, argv[3]);
+}
+
+DEFUN (no_ipv6_prefix_list_le_ge,
+ no_ipv6_prefix_list_le_ge_cmd,
+ "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128> ge <0-128>",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1],
+ argv[2], argv[4], argv[3]);
+}
+
+DEFUN (no_ipv6_prefix_list_seq,
+ no_ipv6_prefix_list_seq_cmd,
+ "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) (X:X::X:X/M|any)",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Any prefix match. Same as \"::0/0 le 128\"\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2],
+ argv[3], NULL, NULL);
+}
+
+DEFUN (no_ipv6_prefix_list_seq_ge,
+ no_ipv6_prefix_list_seq_ge_cmd,
+ "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128>",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2],
+ argv[3], argv[4], NULL);
+}
+
+DEFUN (no_ipv6_prefix_list_seq_ge_le,
+ no_ipv6_prefix_list_seq_ge_le_cmd,
+ "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128> le <0-128>",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2],
+ argv[3], argv[4], argv[5]);
+}
+
+DEFUN (no_ipv6_prefix_list_seq_le,
+ no_ipv6_prefix_list_seq_le_cmd,
+ "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128>",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2],
+ argv[3], NULL, argv[4]);
+}
+
+DEFUN (no_ipv6_prefix_list_seq_le_ge,
+ no_ipv6_prefix_list_seq_le_ge_cmd,
+ "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128> ge <0-128>",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+{
+ return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2],
+ argv[3], argv[5], argv[4]);
+}
+
+DEFUN (ipv6_prefix_list_sequence_number,
+ ipv6_prefix_list_sequence_number_cmd,
+ "ipv6 prefix-list sequence-number",
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Include/exclude sequence numbers in NVGEN\n")
+{
+ prefix_master_ipv6.seqnum = 1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_prefix_list_sequence_number,
+ no_ipv6_prefix_list_sequence_number_cmd,
+ "no ipv6 prefix-list sequence-number",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Include/exclude sequence numbers in NVGEN\n")
+{
+ prefix_master_ipv6.seqnum = 0;
+ return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_prefix_list_description,
+ ipv6_prefix_list_description_cmd,
+ "ipv6 prefix-list WORD description .LINE",
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Prefix-list specific description\n"
+ "Up to 80 characters describing this prefix-list\n")
+{
+ struct prefix_list *plist;
+ struct buffer *b;
+ int i;
+
+ plist = prefix_list_get (AFI_IP6, argv[0]);
+
+ if (plist->desc)
+ {
+ XFREE (MTYPE_TMP, plist->desc);
+ plist->desc = NULL;
+ }
+
+ /* Below is description get codes. */
+ b = buffer_new (1024);
+ for (i = 1; i < argc; i++)
+ {
+ buffer_putstr (b, (u_char *)argv[i]);
+ buffer_putc (b, ' ');
+ }
+ buffer_putc (b, '\0');
+
+ plist->desc = buffer_getstr (b);
+
+ buffer_free (b);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_prefix_list_description,
+ no_ipv6_prefix_list_description_cmd,
+ "no ipv6 prefix-list WORD description",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Prefix-list specific description\n")
+{
+ return vty_prefix_list_desc_unset (vty, AFI_IP6, argv[0]);
+}
+
+ALIAS (no_ipv6_prefix_list_description,
+ no_ipv6_prefix_list_description_arg_cmd,
+ "no ipv6 prefix-list WORD description .LINE",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "Prefix-list specific description\n"
+ "Up to 80 characters describing this prefix-list\n")
+
+DEFUN (show_ipv6_prefix_list,
+ show_ipv6_prefix_list_cmd,
+ "show ipv6 prefix-list",
+ SHOW_STR
+ IPV6_STR
+ PREFIX_LIST_STR)
+{
+ return vty_show_prefix_list (vty, AFI_IP6, NULL, NULL, normal_display);
+}
+
+DEFUN (show_ipv6_prefix_list_name,
+ show_ipv6_prefix_list_name_cmd,
+ "show ipv6 prefix-list WORD",
+ SHOW_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n")
+{
+ return vty_show_prefix_list (vty, AFI_IP6, argv[0], NULL, normal_display);
+}
+
+DEFUN (show_ipv6_prefix_list_name_seq,
+ show_ipv6_prefix_list_name_seq_cmd,
+ "show ipv6 prefix-list WORD seq <1-4294967295>",
+ SHOW_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n")
+{
+ return vty_show_prefix_list (vty, AFI_IP6, argv[0], argv[1], sequential_display);
+}
+
+DEFUN (show_ipv6_prefix_list_prefix,
+ show_ipv6_prefix_list_prefix_cmd,
+ "show ipv6 prefix-list WORD X:X::X:X/M",
+ SHOW_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+{
+ return vty_show_prefix_list_prefix (vty, AFI_IP6, argv[0], argv[1], normal_display);
+}
+
+DEFUN (show_ipv6_prefix_list_prefix_longer,
+ show_ipv6_prefix_list_prefix_longer_cmd,
+ "show ipv6 prefix-list WORD X:X::X:X/M longer",
+ SHOW_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Lookup longer prefix\n")
+{
+ return vty_show_prefix_list_prefix (vty, AFI_IP6, argv[0], argv[1], longer_display);
+}
+
+DEFUN (show_ipv6_prefix_list_prefix_first_match,
+ show_ipv6_prefix_list_prefix_first_match_cmd,
+ "show ipv6 prefix-list WORD X:X::X:X/M first-match",
+ SHOW_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "First matched prefix\n")
+{
+ return vty_show_prefix_list_prefix (vty, AFI_IP6, argv[0], argv[1], first_match_display);
+}
+
+DEFUN (show_ipv6_prefix_list_summary,
+ show_ipv6_prefix_list_summary_cmd,
+ "show ipv6 prefix-list summary",
+ SHOW_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Summary of prefix lists\n")
+{
+ return vty_show_prefix_list (vty, AFI_IP6, NULL, NULL, summary_display);
+}
+
+DEFUN (show_ipv6_prefix_list_summary_name,
+ show_ipv6_prefix_list_summary_name_cmd,
+ "show ipv6 prefix-list summary WORD",
+ SHOW_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Summary of prefix lists\n"
+ "Name of a prefix list\n")
+{
+ return vty_show_prefix_list (vty, AFI_IP6, argv[0], NULL, summary_display);
+}
+
+DEFUN (show_ipv6_prefix_list_detail,
+ show_ipv6_prefix_list_detail_cmd,
+ "show ipv6 prefix-list detail",
+ SHOW_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Detail of prefix lists\n")
+{
+ return vty_show_prefix_list (vty, AFI_IP6, NULL, NULL, detail_display);
+}
+
+DEFUN (show_ipv6_prefix_list_detail_name,
+ show_ipv6_prefix_list_detail_name_cmd,
+ "show ipv6 prefix-list detail WORD",
+ SHOW_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Detail of prefix lists\n"
+ "Name of a prefix list\n")
+{
+ return vty_show_prefix_list (vty, AFI_IP6, argv[0], NULL, detail_display);
+}
+
+DEFUN (clear_ipv6_prefix_list,
+ clear_ipv6_prefix_list_cmd,
+ "clear ipv6 prefix-list",
+ CLEAR_STR
+ IPV6_STR
+ PREFIX_LIST_STR)
+{
+ return vty_clear_prefix_list (vty, AFI_IP6, NULL, NULL);
+}
+
+DEFUN (clear_ipv6_prefix_list_name,
+ clear_ipv6_prefix_list_name_cmd,
+ "clear ipv6 prefix-list WORD",
+ CLEAR_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n")
+{
+ return vty_clear_prefix_list (vty, AFI_IP6, argv[0], NULL);
+}
+
+DEFUN (clear_ipv6_prefix_list_name_prefix,
+ clear_ipv6_prefix_list_name_prefix_cmd,
+ "clear ipv6 prefix-list WORD X:X::X:X/M",
+ CLEAR_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ "Name of a prefix list\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+{
+ return vty_clear_prefix_list (vty, AFI_IP6, argv[0], argv[1]);
+}
+#endif /* HAVE_IPV6 */
+
+/* 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 <zebra.h>
+
+#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 <zebra.h>
+
+#include "version.h"
+
+void
+print_version (char *progname)
+{
+ printf ("%s version %s (%s)\n", progname, ZEBRA_VERSION, host_name);
+ printf ("Copyright 1996-2001, Kunihiro Ishiguro\n");
+}
diff --git a/lib/regex-gnu.h b/lib/regex-gnu.h
new file mode 100644
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 <sys/types.h> must be included (by the caller) before
+ <regex.h>. */
+
+#if !defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE && defined VMS
+/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
+ should be there. */
+# include <stddef.h>
+#endif
+
+/* The following two types have to be signed and unsigned integer type
+ wide enough to hold a value of a pointer. For most ANSI compilers
+ ptrdiff_t and size_t should be likely OK. Still size of these two
+ types is 2 for Microsoft C. Ugh... */
+typedef long int s_reg_t;
+typedef unsigned long int active_reg_t;
+
+/* The following bits are used to determine the regexp syntax we
+ recognize. The set/not-set meanings are chosen so that Emacs syntax
+ remains the value 0. The bits are given in alphabetical order, and
+ the definitions shifted by one from the previous bit; thus, when we
+ add or remove a bit, only one other definition need change. */
+typedef unsigned long int reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+ If set, then such a \ quotes the following character. */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+ literals.
+ If set, then \+ and \? are operators and + and ? are literals. */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* If this bit is set, then character classes are supported. They are:
+ [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
+ [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
+ If not set, then character classes are not supported. */
+#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+ expressions, of course).
+ If this bit is not set, then it depends:
+ ^ is an anchor if it is at the beginning of a regular
+ expression or after an open-group or an alternation operator;
+ $ is an anchor if it is at the end of a regular expression, or
+ before a close-group or an alternation operator.
+
+ This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+ POSIX draft 11.2 says that * etc. in leading positions is undefined.
+ We already implemented a previous draft which made those constructs
+ invalid, though, so we haven't changed the code back. */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+ regardless of where they are in the pattern.
+ If this bit is not set, then special characters are special only in
+ some contexts; otherwise they are ordinary. Specifically,
+ * + ? and intervals are only special when not after the beginning,
+ open-group, or alternation operator. */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+ immediately after an alternation or begin-group operator. */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+ If not set, then it doesn't. */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+ If not set, then it does. */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+ If not set, they do. */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+ interval, depending on RE_NO_BK_BRACES.
+ If not set, \{, \}, {, and } are literals. */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+ If not set, they are. */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+ If not set, newline is literal. */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+ are literals.
+ If not set, then `\{...\}' defines an interval. */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+ If not set, \(...\) defines a group, and ( and ) are literals. */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+ If not set, then \<digit> is a back-reference. */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal.
+ If not set, then \| is an alternation operator, and | is literal. */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+ than the starting range point, as in [z-a], is invalid.
+ If not set, then when ending range point collates higher than the
+ starting range point, the range is ignored. */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+ If not set, then an unmatched ) is invalid. */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* If this bit is set, succeed as soon as we match the whole pattern,
+ without further backtracking. */
+#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
+
+/* If this bit is set, do not process the GNU regex operators.
+ If not set, then the GNU regex operators are recognized. */
+#define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1)
+
+/* If this bit is set, turn on internal regex debugging.
+ If not set, and debugging was on, turn it off.
+ This only works if regex.c is compiled -DDEBUG.
+ We define this bit always, so that all that's needed to turn on
+ debugging is to recompile regex.c; the calling code can always have
+ this bit set, and it won't affect anything in the normal case. */
+#define RE_DEBUG (RE_NO_GNU_OPS << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+ some interfaces). When a regexp is compiled, the syntax used is
+ stored in the pattern buffer, so changing this does not affect
+ already-compiled regexps. */
+extern reg_syntax_t re_syntax_options;
+
+/* 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 <config.h>
+#endif
+
+#ifndef PARAMS
+# if defined __GNUC__ || (defined __STDC__ && __STDC__)
+# define PARAMS(args) args
+# else
+# define PARAMS(args) ()
+# endif /* GCC. */
+#endif /* Not PARAMS. */
+
+#if defined STDC_HEADERS && !defined emacs
+# include <stddef.h>
+#else
+/* We need this for `regex.h', and perhaps for the Emacs include files. */
+# include <sys/types.h>
+#endif
+
+#define WIDE_CHAR_SUPPORT (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC)
+
+/* For platform which support the ISO C amendement 1 functionality we
+ support user defined character classes. */
+#if defined _LIBC || WIDE_CHAR_SUPPORT
+/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
+# include <wchar.h>
+# include <wctype.h>
+#endif
+
+#ifdef _LIBC
+/* We have to keep the namespace clean. */
+# define regfree(preg) __regfree (preg)
+# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef)
+# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags)
+# define regerror(errcode, preg, errbuf, errbuf_size) \
+ __regerror(errcode, preg, errbuf, errbuf_size)
+# define re_set_registers(bu, re, nu, st, en) \
+ __re_set_registers (bu, re, nu, st, en)
+# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \
+ __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
+# define re_match(bufp, string, size, pos, regs) \
+ __re_match (bufp, string, size, pos, regs)
+# define re_search(bufp, string, size, startpos, range, regs) \
+ __re_search (bufp, string, size, startpos, range, regs)
+# define re_compile_pattern(pattern, length, bufp) \
+ __re_compile_pattern (pattern, length, bufp)
+# define re_set_syntax(syntax) __re_set_syntax (syntax)
+# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \
+ __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop)
+# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp)
+
+#define btowc __btowc
+#endif
+
+/* This is for other GNU distributions with internationalized messages. */
+#if HAVE_LIBINTL_H || defined _LIBC
+# include <libintl.h>
+#else
+# define gettext(msgid) (msgid)
+#endif
+
+#ifndef gettext_noop
+/* This define is so xgettext can find the internationalizable
+ strings. */
+# define gettext_noop(String) String
+#endif
+
+/* The `emacs' switch turns on certain matching commands
+ that make sense only in Emacs. */
+#ifdef emacs
+
+# include "lisp.h"
+# include "buffer.h"
+# include "syntax.h"
+
+#else /* not emacs */
+
+/* If we are not linking with Emacs proper,
+ we can't use the relocating allocator
+ even if config.h says that we can. */
+# undef REL_ALLOC
+
+# if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+# else
+char *malloc ();
+char *realloc ();
+# endif
+
+/* When used in Emacs's lib-src, we need to get bzero and bcopy somehow.
+ If nothing else has been done, use the method below. */
+# ifdef INHIBIT_STRING_HEADER
+# if !(defined HAVE_BZERO && defined HAVE_BCOPY)
+# if !defined bzero && !defined bcopy
+# undef INHIBIT_STRING_HEADER
+# endif
+# endif
+# endif
+
+/* This is the normal way of making sure we have a bcopy and a bzero.
+ This is used in most programs--a few other programs avoid this
+ by defining INHIBIT_STRING_HEADER. */
+# ifndef INHIBIT_STRING_HEADER
+# if defined HAVE_STRING_H || defined STDC_HEADERS || defined _LIBC
+# include <string.h>
+# ifndef bzero
+# ifndef _LIBC
+# define bzero(s, n) (memset (s, '\0', n), (s))
+# else
+# define bzero(s, n) __bzero (s, n)
+# endif
+# endif
+# else
+# include <strings.h>
+# ifndef memcmp
+# define memcmp(s1, s2, n) bcmp (s1, s2, n)
+# endif
+# ifndef memcpy
+# define memcpy(d, s, n) (bcopy (s, d, n), (d))
+# endif
+# endif
+# endif
+
+/* Define the syntax stuff for \<, \>, etc. */
+
+/* This must be nonzero for the wordchar and notwordchar pattern
+ commands in re_match_2. */
+# ifndef Sword
+# define Sword 1
+# endif
+
+# ifdef SWITCH_ENUM_BUG
+# define SWITCH_ENUM_CAST(x) ((int)(x))
+# else
+# define SWITCH_ENUM_CAST(x) (x)
+# endif
+
+/* How many characters in the character set. */
+# define CHAR_SET_SIZE 256
+
+# ifdef SYNTAX_TABLE
+
+extern char *re_syntax_table;
+
+# else /* not SYNTAX_TABLE */
+
+static char re_syntax_table[CHAR_SET_SIZE];
+
+static void
+init_syntax_once ()
+{
+ register int c;
+ static int done;
+
+ if (done)
+ return;
+
+ bzero (re_syntax_table, sizeof re_syntax_table);
+
+ for (c = 'a'; c <= 'z'; c++)
+ re_syntax_table[c] = Sword;
+
+ for (c = 'A'; c <= 'Z'; c++)
+ re_syntax_table[c] = Sword;
+
+ for (c = '0'; c <= '9'; c++)
+ re_syntax_table[c] = Sword;
+
+ re_syntax_table['_'] = Sword;
+
+ done = 1;
+}
+
+# endif /* not SYNTAX_TABLE */
+
+# define SYNTAX(c) re_syntax_table[c]
+
+#endif /* not emacs */
+
+/* Get the interface, including the syntax bits. */
+#include <regex-gnu.h>
+
+/* isalpha etc. are used for the character classes. */
+#include <ctype.h>
+
+/* Jim Meyering writes:
+
+ "... Some ctype macros are valid only for character codes that
+ isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
+ using /bin/cc or gcc but without giving an ansi option). So, all
+ ctype uses should be through macros like ISPRINT... If
+ STDC_HEADERS is defined, then autoconf has verified that the ctype
+ macros don't need to be guarded with references to isascii. ...
+ Defining isascii to 1 should let any compiler worth its salt
+ eliminate the && through constant folding."
+ Solaris defines some of these symbols so we must undefine them first. */
+
+#undef ISASCII
+#if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII)
+# define ISASCII(c) 1
+#else
+# define ISASCII(c) isascii(c)
+#endif
+
+#ifdef isblank
+# define ISBLANK(c) (ISASCII (c) && isblank (c))
+#else
+# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+#endif
+#ifdef isgraph
+# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
+#else
+# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
+#endif
+
+#undef ISPRINT
+#define ISPRINT(c) (ISASCII (c) && isprint (c))
+#define ISDIGIT(c) (ISASCII (c) && isdigit (c))
+#define ISALNUM(c) (ISASCII (c) && isalnum (c))
+#define ISALPHA(c) (ISASCII (c) && isalpha (c))
+#define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
+#define ISLOWER(c) (ISASCII (c) && islower (c))
+#define ISPUNCT(c) (ISASCII (c) && ispunct (c))
+#define ISSPACE(c) (ISASCII (c) && isspace (c))
+#define ISUPPER(c) (ISASCII (c) && isupper (c))
+#define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
+
+#ifdef _tolower
+# define TOLOWER(c) _tolower(c)
+#else
+# define TOLOWER(c) tolower(c)
+#endif
+
+#ifndef NULL
+# define NULL (void *)0
+#endif
+
+/* We remove any previous definition of `SIGN_EXTEND_CHAR',
+ since ours (we hope) works properly with all combinations of
+ machines, compilers, `char' and `unsigned char' argument types.
+ (Per Bothner suggested the basic approach.) */
+#undef SIGN_EXTEND_CHAR
+#if __STDC__
+# define SIGN_EXTEND_CHAR(c) ((signed char) (c))
+#else /* not __STDC__ */
+/* As in Harbison and Steele. */
+# define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
+#endif
+
+/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we
+ use `alloca' instead of `malloc'. This is because using malloc in
+ re_search* or re_match* could cause memory leaks when C-g is used in
+ Emacs; also, malloc is slower and causes storage fragmentation. On
+ the other hand, malloc is more portable, and easier to debug.
+
+ Because we sometimes use alloca, some routines have to be macros,
+ not functions -- `alloca'-allocated space disappears at the end of the
+ function it is called in. */
+
+#ifdef REGEX_MALLOC
+
+# define REGEX_ALLOCATE malloc
+# define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
+# define REGEX_FREE free
+
+#else /* not REGEX_MALLOC */
+
+/* Emacs already defines alloca, sometimes. */
+# ifndef alloca
+
+/* Make alloca work the best possible way. */
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# else /* not __GNUC__ */
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# endif /* HAVE_ALLOCA_H */
+# endif /* not __GNUC__ */
+
+# endif /* not alloca */
+
+# define REGEX_ALLOCATE alloca
+
+/* Assumes a `char *destination' variable. */
+# define REGEX_REALLOCATE(source, osize, nsize) \
+ (destination = (char *) alloca (nsize), \
+ memcpy (destination, source, osize))
+
+/* No need to do anything to free, after alloca. */
+# define REGEX_FREE(arg) ((void)0) /* Do nothing! But inhibit gcc warning. */
+
+#endif /* not REGEX_MALLOC */
+
+/* Define how to allocate the failure stack. */
+
+#if defined REL_ALLOC && defined REGEX_MALLOC
+
+# define REGEX_ALLOCATE_STACK(size) \
+ r_alloc (&failure_stack_ptr, (size))
+# define REGEX_REALLOCATE_STACK(source, osize, nsize) \
+ r_re_alloc (&failure_stack_ptr, (nsize))
+# define REGEX_FREE_STACK(ptr) \
+ r_alloc_free (&failure_stack_ptr)
+
+#else /* not using relocating allocator */
+
+# ifdef REGEX_MALLOC
+
+# define REGEX_ALLOCATE_STACK malloc
+# define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize)
+# define REGEX_FREE_STACK free
+
+# else /* not REGEX_MALLOC */
+
+# define REGEX_ALLOCATE_STACK alloca
+
+# define REGEX_REALLOCATE_STACK(source, osize, nsize) \
+ REGEX_REALLOCATE (source, osize, nsize)
+/* No need to explicitly free anything. */
+# define REGEX_FREE_STACK(arg)
+
+# endif /* not REGEX_MALLOC */
+#endif /* not using relocating allocator */
+
+
+/* True if `size1' is non-NULL and PTR is pointing anywhere inside
+ `string1' or just past its end. This works if PTR is NULL, which is
+ a good thing. */
+#define FIRST_STRING_P(ptr) \
+ (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
+
+/* (Re)Allocate N items of type T using malloc, or fail. */
+#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
+#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
+#define RETALLOC_IF(addr, n, t) \
+ if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t)
+#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
+
+#define BYTEWIDTH 8 /* In bits. */
+
+#define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
+
+#undef MAX
+#undef MIN
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+typedef char boolean;
+#define false 0
+#define true 1
+
+static int re_match_2_internal PARAMS ((struct re_pattern_buffer *bufp,
+ const char *string1, int size1,
+ const char *string2, int size2,
+ int pos,
+ struct re_registers *regs,
+ int stop));
+
+/* 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 <stdio.h>
+
+/* It is useful to test things that ``must'' be true when debugging. */
+# include <assert.h>
+
+static int debug;
+
+# define DEBUG_STATEMENT(e) e
+# define DEBUG_PRINT1(x) if (debug) printf (x)
+# define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
+# define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
+# define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
+# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \
+ if (debug) print_partial_compiled_pattern (s, e)
+# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \
+ if (debug) print_double_string (w, s1, sz1, s2, sz2)
+
+
+/* Print the fastmap in human-readable form. */
+
+void
+print_fastmap (fastmap)
+ char *fastmap;
+{
+ unsigned was_a_range = 0;
+ unsigned i = 0;
+
+ while (i < (1 << BYTEWIDTH))
+ {
+ if (fastmap[i++])
+ {
+ was_a_range = 0;
+ putchar (i - 1);
+ while (i < (1 << BYTEWIDTH) && fastmap[i])
+ {
+ was_a_range = 1;
+ i++;
+ }
+ if (was_a_range)
+ {
+ printf ("-");
+ putchar (i - 1);
+ }
+ }
+ }
+ putchar ('\n');
+}
+
+
+/* Print a compiled pattern string in human-readable form, starting at
+ the START pointer into it and ending just before the pointer END. */
+
+void
+print_partial_compiled_pattern (start, end)
+ unsigned char *start;
+ unsigned char *end;
+{
+ int mcnt, mcnt2;
+ unsigned char *p1;
+ unsigned char *p = start;
+ unsigned char *pend = end;
+
+ if (start == NULL)
+ {
+ printf ("(null)\n");
+ return;
+ }
+
+ /* Loop over pattern commands. */
+ while (p < pend)
+ {
+ printf ("%d:\t", p - start);
+
+ switch ((re_opcode_t) *p++)
+ {
+ case no_op:
+ printf ("/no_op");
+ break;
+
+ case exactn:
+ mcnt = *p++;
+ printf ("/exactn/%d", mcnt);
+ do
+ {
+ putchar ('/');
+ putchar (*p++);
+ }
+ while (--mcnt);
+ break;
+
+ case start_memory:
+ mcnt = *p++;
+ printf ("/start_memory/%d/%d", mcnt, *p++);
+ break;
+
+ case stop_memory:
+ mcnt = *p++;
+ printf ("/stop_memory/%d/%d", mcnt, *p++);
+ break;
+
+ case duplicate:
+ printf ("/duplicate/%d", *p++);
+ break;
+
+ case anychar:
+ printf ("/anychar");
+ break;
+
+ case charset:
+ case charset_not:
+ {
+ register int c, last = -100;
+ register int in_range = 0;
+
+ printf ("/charset [%s",
+ (re_opcode_t) *(p - 1) == charset_not ? "^" : "");
+
+ assert (p + *p < pend);
+
+ for (c = 0; c < 256; c++)
+ if (c / 8 < *p
+ && (p[1 + (c/8)] & (1 << (c % 8))))
+ {
+ /* Are we starting a range? */
+ if (last + 1 == c && ! in_range)
+ {
+ putchar ('-');
+ in_range = 1;
+ }
+ /* Have we broken a range? */
+ else if (last + 1 != c && in_range)
+ {
+ putchar (last);
+ in_range = 0;
+ }
+
+ if (! in_range)
+ putchar (c);
+
+ last = c;
+ }
+
+ if (in_range)
+ putchar (last);
+
+ putchar (']');
+
+ p += 1 + *p;
+ }
+ break;
+
+ case begline:
+ printf ("/begline");
+ break;
+
+ case endline:
+ printf ("/endline");
+ break;
+
+ case on_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/on_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case on_failure_keep_string_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/on_failure_keep_string_jump to %d", p + mcnt - start);
+ break;
+
+ case dummy_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/dummy_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case push_dummy_failure:
+ printf ("/push_dummy_failure");
+ break;
+
+ case maybe_pop_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/maybe_pop_jump to %d", p + mcnt - start);
+ break;
+
+ case pop_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/pop_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case jump_past_alt:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/jump_past_alt to %d", p + mcnt - start);
+ break;
+
+ case jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/jump to %d", p + mcnt - start);
+ break;
+
+ case succeed_n:
+ extract_number_and_incr (&mcnt, &p);
+ p1 = p + mcnt;
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/succeed_n to %d, %d times", p1 - start, mcnt2);
+ break;
+
+ case jump_n:
+ extract_number_and_incr (&mcnt, &p);
+ p1 = p + mcnt;
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/jump_n to %d, %d times", p1 - start, mcnt2);
+ break;
+
+ case set_number_at:
+ extract_number_and_incr (&mcnt, &p);
+ p1 = p + mcnt;
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/set_number_at location %d to %d", p1 - start, mcnt2);
+ break;
+
+ case wordbound:
+ printf ("/wordbound");
+ break;
+
+ case notwordbound:
+ printf ("/notwordbound");
+ break;
+
+ case wordbeg:
+ printf ("/wordbeg");
+ break;
+
+ case wordend:
+ printf ("/wordend");
+
+# ifdef emacs
+ case before_dot:
+ printf ("/before_dot");
+ break;
+
+ case at_dot:
+ printf ("/at_dot");
+ break;
+
+ case after_dot:
+ printf ("/after_dot");
+ break;
+
+ case syntaxspec:
+ printf ("/syntaxspec");
+ mcnt = *p++;
+ printf ("/%d", mcnt);
+ break;
+
+ case notsyntaxspec:
+ printf ("/notsyntaxspec");
+ mcnt = *p++;
+ printf ("/%d", mcnt);
+ break;
+# endif /* emacs */
+
+ case wordchar:
+ printf ("/wordchar");
+ break;
+
+ case notwordchar:
+ printf ("/notwordchar");
+ break;
+
+ case begbuf:
+ printf ("/begbuf");
+ break;
+
+ case endbuf:
+ printf ("/endbuf");
+ break;
+
+ default:
+ printf ("?%d", *(p-1));
+ }
+
+ putchar ('\n');
+ }
+
+ printf ("%d:\tend of pattern.\n", p - start);
+}
+
+
+void
+print_compiled_pattern (bufp)
+ struct re_pattern_buffer *bufp;
+{
+ unsigned char *buffer = bufp->buffer;
+
+ print_partial_compiled_pattern (buffer, buffer + bufp->used);
+ printf ("%ld bytes used/%ld bytes allocated.\n",
+ bufp->used, bufp->allocated);
+
+ if (bufp->fastmap_accurate && bufp->fastmap)
+ {
+ printf ("fastmap: ");
+ print_fastmap (bufp->fastmap);
+ }
+
+ printf ("re_nsub: %d\t", bufp->re_nsub);
+ printf ("regs_alloc: %d\t", bufp->regs_allocated);
+ printf ("can_be_null: %d\t", bufp->can_be_null);
+ printf ("newline_anchor: %d\n", bufp->newline_anchor);
+ printf ("no_sub: %d\t", bufp->no_sub);
+ printf ("not_bol: %d\t", bufp->not_bol);
+ printf ("not_eol: %d\t", bufp->not_eol);
+ printf ("syntax: %lx\n", bufp->syntax);
+ /* Perhaps we should print the translate table? */
+}
+
+
+void
+print_double_string (where, string1, size1, string2, size2)
+ const char *where;
+ const char *string1;
+ const char *string2;
+ int size1;
+ int size2;
+{
+ int this_char;
+
+ if (where == NULL)
+ printf ("(null)");
+ else
+ {
+ if (FIRST_STRING_P (where))
+ {
+ for (this_char = where - string1; this_char < size1; this_char++)
+ putchar (string1[this_char]);
+
+ where = string2;
+ }
+
+ for (this_char = where - string2; this_char < size2; this_char++)
+ putchar (string2[this_char]);
+ }
+}
+
+void
+printchar (c)
+ int c;
+{
+ putc (c, stderr);
+}
+
+#else /* not DEBUG */
+
+# undef assert
+# define assert(e)
+
+# define DEBUG_STATEMENT(e)
+# define DEBUG_PRINT1(x)
+# define DEBUG_PRINT2(x1, x2)
+# define DEBUG_PRINT3(x1, x2, x3)
+# define DEBUG_PRINT4(x1, x2, x3, x4)
+# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
+# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
+
+#endif /* not DEBUG */
+
+/* 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 (&reg_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 <jump count> <upper bound>
+ set_number_at <succeed_n count> <lower bound>
+ succeed_n <after jump addr> <succeed_n count>
+ <body of loop>
+ jump_n <succeed_n addr> <jump count>
+ (The upper bound and `jump_n' are omitted if
+ `upper_bound' is 1, though.) */
+ else
+ { /* If the upper bound is > 1, we need to insert
+ more at the end of the loop. */
+ unsigned nbytes = 10 + (upper_bound > 1) * 10;
+
+ GET_BUFFER_SPACE (nbytes);
+
+ /* Initialize lower bound of the `succeed_n', even
+ though it will be set during matching by its
+ attendant `set_number_at' (inserted next),
+ because `re_compile_fastmap' needs to know.
+ Jump to the `jump_n' we might insert below. */
+ INSERT_JUMP2 (succeed_n, laststart,
+ b + 5 + (upper_bound > 1) * 5,
+ lower_bound);
+ b += 5;
+
+ /* Code to initialize the lower bound. Insert
+ before the `succeed_n'. The `5' is the last two
+ bytes of this `set_number_at', plus 3 bytes of
+ the following `succeed_n'. */
+ insert_op2 (set_number_at, laststart, 5, lower_bound, b);
+ b += 5;
+
+ if (upper_bound > 1)
+ { /* More than one repetition is allowed, so
+ append a backward jump to the `succeed_n'
+ that starts this interval.
+
+ When we've reached this during matching,
+ we'll have matched the interval once, so
+ jump back only `upper_bound - 1' times. */
+ STORE_JUMP2 (jump_n, b, laststart + 5,
+ upper_bound - 1);
+ b += 5;
+
+ /* The location we want to set is the second
+ parameter of the `jump_n'; that is `b-2' as
+ an absolute address. `laststart' will be
+ the `set_number_at' we're about to insert;
+ `laststart+3' the number to set, the source
+ for the relative address. But we are
+ inserting into the middle of the pattern --
+ so everything is getting moved up by 5.
+ Conclusion: (b - 2) - (laststart + 3) + 5,
+ i.e., b - laststart.
+
+ We insert this at the beginning of the loop
+ so that if we fail during matching, we'll
+ reinitialize the bounds. */
+ insert_op2 (set_number_at, laststart, b - laststart,
+ upper_bound - 1, b);
+ b += 5;
+ }
+ }
+ pending_exact = 0;
+ beg_interval = NULL;
+ }
+ break;
+
+ unfetch_interval:
+ /* If an invalid interval, match the characters as literals. */
+ assert (beg_interval);
+ p = beg_interval;
+ beg_interval = NULL;
+
+ /* normal_char and normal_backslash need `c'. */
+ PATFETCH (c);
+
+ if (!(syntax & RE_NO_BK_BRACES))
+ {
+ if (p > pattern && p[-1] == '\\')
+ goto normal_backslash;
+ }
+ goto normal_char;
+
+#ifdef emacs
+ /* There is no way to specify the before_dot and after_dot
+ operators. rms says this is ok. --karl */
+ case '=':
+ BUF_PUSH (at_dot);
+ break;
+
+ case 's':
+ laststart = b;
+ PATFETCH (c);
+ BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
+ break;
+
+ case 'S':
+ laststart = b;
+ PATFETCH (c);
+ BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
+ break;
+#endif /* emacs */
+
+
+ case 'w':
+ if (syntax & RE_NO_GNU_OPS)
+ goto normal_char;
+ laststart = b;
+ BUF_PUSH (wordchar);
+ break;
+
+
+ case 'W':
+ if (syntax & RE_NO_GNU_OPS)
+ goto normal_char;
+ laststart = b;
+ BUF_PUSH (notwordchar);
+ break;
+
+
+ case '<':
+ if (syntax & RE_NO_GNU_OPS)
+ goto normal_char;
+ BUF_PUSH (wordbeg);
+ break;
+
+ case '>':
+ if (syntax & RE_NO_GNU_OPS)
+ goto normal_char;
+ BUF_PUSH (wordend);
+ break;
+
+ case 'b':
+ if (syntax & RE_NO_GNU_OPS)
+ goto normal_char;
+ BUF_PUSH (wordbound);
+ break;
+
+ case 'B':
+ if (syntax & RE_NO_GNU_OPS)
+ goto normal_char;
+ BUF_PUSH (notwordbound);
+ break;
+
+ case '`':
+ if (syntax & RE_NO_GNU_OPS)
+ goto normal_char;
+ BUF_PUSH (begbuf);
+ break;
+
+ case '\'':
+ if (syntax & RE_NO_GNU_OPS)
+ goto normal_char;
+ BUF_PUSH (endbuf);
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ if (syntax & RE_NO_BK_REFS)
+ goto normal_char;
+
+ c1 = c - '0';
+
+ if (c1 > regnum)
+ FREE_STACK_RETURN (REG_ESUBREG);
+
+ /* Can't back reference to a subexpression if inside of it. */
+ if (group_in_compile_stack (compile_stack, (regnum_t) c1))
+ goto normal_char;
+
+ laststart = b;
+ BUF_PUSH_2 (duplicate, c1);
+ break;
+
+
+ case '+':
+ case '?':
+ if (syntax & RE_BK_PLUS_QM)
+ goto handle_plus;
+ else
+ goto normal_backslash;
+
+ default:
+ normal_backslash:
+ /* You might think it would be useful for \ to mean
+ not to translate; but if we don't translate it
+ it will never match anything. */
+ c = TRANSLATE (c);
+ goto normal_char;
+ }
+ break;
+
+
+ default:
+ /* Expects the character in `c'. */
+ normal_char:
+ /* If no exactn currently being built. */
+ if (!pending_exact
+
+ /* If last exactn not at current position. */
+ || pending_exact + *pending_exact + 1 != b
+
+ /* We have only one byte following the exactn for the count. */
+ || *pending_exact == (1 << BYTEWIDTH) - 1
+
+ /* If followed by a repetition operator. */
+ || *p == '*' || *p == '^'
+ || ((syntax & RE_BK_PLUS_QM)
+ ? *p == '\\' && (p[1] == '+' || p[1] == '?')
+ : (*p == '+' || *p == '?'))
+ || ((syntax & RE_INTERVALS)
+ && ((syntax & RE_NO_BK_BRACES)
+ ? *p == '{'
+ : (p[0] == '\\' && p[1] == '{'))))
+ {
+ /* Start building a new exactn. */
+
+ laststart = b;
+
+ BUF_PUSH_2 (exactn, 0);
+ pending_exact = b - 1;
+ }
+
+ BUF_PUSH (c);
+ (*pending_exact)++;
+ break;
+ } /* switch (c) */
+ } /* while p != pend */
+
+
+ /* Through the pattern now. */
+
+ if (fixup_alt_jump)
+ STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+ if (!COMPILE_STACK_EMPTY)
+ FREE_STACK_RETURN (REG_EPAREN);
+
+ /* If we don't want backtracking, force success
+ the first time we reach the end of the compiled pattern. */
+ if (syntax & RE_NO_POSIX_BACKTRACKING)
+ BUF_PUSH (succeed);
+
+ free (compile_stack.stack);
+
+ /* We have succeeded; set the length of the buffer. */
+ bufp->used = b - bufp->buffer;
+
+#ifdef DEBUG
+ if (debug)
+ {
+ DEBUG_PRINT1 ("\nCompiled pattern: \n");
+ print_compiled_pattern (bufp);
+ }
+#endif /* DEBUG */
+
+#ifndef MATCH_MAY_ALLOCATE
+ /* Initialize the failure stack to the largest possible stack. This
+ isn't necessary unless we're trying to avoid calling alloca in
+ the search and match routines. */
+ {
+ int num_regs = bufp->re_nsub + 1;
+
+ /* Since DOUBLE_FAIL_STACK refuses to double only if the current size
+ is strictly greater than re_max_failures, the largest possible stack
+ is 2 * re_max_failures failure points. */
+ if (fail_stack.size < (2 * re_max_failures * MAX_FAILURE_ITEMS))
+ {
+ fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS);
+
+# ifdef emacs
+ if (! fail_stack.stack)
+ fail_stack.stack
+ = (fail_stack_elt_t *) xmalloc (fail_stack.size
+ * sizeof (fail_stack_elt_t));
+ else
+ fail_stack.stack
+ = (fail_stack_elt_t *) xrealloc (fail_stack.stack,
+ (fail_stack.size
+ * sizeof (fail_stack_elt_t)));
+# else /* not emacs */
+ if (! fail_stack.stack)
+ fail_stack.stack
+ = (fail_stack_elt_t *) malloc (fail_stack.size
+ * sizeof (fail_stack_elt_t));
+ else
+ fail_stack.stack
+ = (fail_stack_elt_t *) realloc (fail_stack.stack,
+ (fail_stack.size
+ * sizeof (fail_stack_elt_t)));
+# endif /* not emacs */
+ }
+
+ regex_grow_registers (num_regs);
+ }
+#endif /* not MATCH_MAY_ALLOCATE */
+
+ return REG_NOERROR;
+} /* regex_compile */
+
+/* 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;
+
+
+ /* \<digit> has been turned into a `duplicate' command which is
+ followed by the numeric value of <digit> as the register number. */
+ case duplicate:
+ {
+ register const char *d2, *dend2;
+ int regno = *p++; /* Get which register to match against. */
+ DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
+
+ /* Can't back reference a group which we've never matched. */
+ if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
+ goto fail;
+
+ /* Where in input to try to start matching. */
+ d2 = regstart[regno];
+
+ /* Where to stop matching; if both the place to start and
+ the place to stop matching are in the same string, then
+ set to the place to stop, otherwise, for now have to use
+ the end of the first string. */
+
+ dend2 = ((FIRST_STRING_P (regstart[regno])
+ == FIRST_STRING_P (regend[regno]))
+ ? regend[regno] : end_match_1);
+ for (;;)
+ {
+ /* If necessary, advance to next segment in register
+ contents. */
+ while (d2 == dend2)
+ {
+ if (dend2 == end_match_2) break;
+ if (dend2 == regend[regno]) break;
+
+ /* End of string1 => advance to string2. */
+ d2 = string2;
+ dend2 = regend[regno];
+ }
+ /* At end of register contents => success */
+ if (d2 == dend2) break;
+
+ /* If necessary, advance to next segment in data. */
+ PREFETCH ();
+
+ /* How many characters left in this segment to match. */
+ mcnt = dend - d;
+
+ /* Want how many consecutive characters we can match in
+ one shot, so, if necessary, adjust the count. */
+ if (mcnt > dend2 - d2)
+ mcnt = dend2 - d2;
+
+ /* Compare that many; failure if mismatch, else move
+ past them. */
+ if (translate
+ ? bcmp_translate (d, d2, mcnt, translate)
+ : memcmp (d, d2, mcnt))
+ goto fail;
+ d += mcnt, d2 += mcnt;
+
+ /* Do this because we've match some characters. */
+ SET_REGS_MATCHED ();
+ }
+ }
+ break;
+
+
+ /* begline matches the empty string at the beginning of the string
+ (unless `not_bol' is set in `bufp'), and, if
+ `newline_anchor' is set, after newlines. */
+ case begline:
+ DEBUG_PRINT1 ("EXECUTING begline.\n");
+
+ if (AT_STRINGS_BEG (d))
+ {
+ if (!bufp->not_bol) break;
+ }
+ else if (d[-1] == '\n' && bufp->newline_anchor)
+ {
+ break;
+ }
+ /* In all other cases, we fail. */
+ goto fail;
+
+
+ /* endline is the dual of begline. */
+ case endline:
+ DEBUG_PRINT1 ("EXECUTING endline.\n");
+
+ if (AT_STRINGS_END (d))
+ {
+ if (!bufp->not_eol) break;
+ }
+
+ /* We have to ``prefetch'' the next character. */
+ else if ((d == end1 ? *string2 : *d) == '\n'
+ && bufp->newline_anchor)
+ {
+ break;
+ }
+ goto fail;
+
+
+ /* Match at the very beginning of the data. */
+ case begbuf:
+ DEBUG_PRINT1 ("EXECUTING begbuf.\n");
+ if (AT_STRINGS_BEG (d))
+ break;
+ goto fail;
+
+
+ /* Match at the very end of the data. */
+ case endbuf:
+ DEBUG_PRINT1 ("EXECUTING endbuf.\n");
+ if (AT_STRINGS_END (d))
+ break;
+ goto fail;
+
+
+ /* on_failure_keep_string_jump is used to optimize `.*\n'. It
+ pushes NULL as the value for the string on the stack. Then
+ `pop_failure_point' will keep the current value for the
+ string, instead of restoring it. To see why, consider
+ matching `foo\nbar' against `.*\n'. The .* matches the foo;
+ then the . fails against the \n. But the next thing we want
+ to do is match the \n against the \n; if we restored the
+ string value, we would be back at the foo.
+
+ Because this is used only in specific cases, we don't need to
+ check all the things that `on_failure_jump' does, to make
+ sure the right things get saved on the stack. Hence we don't
+ share its code. The only reason to push anything on the
+ stack at all is that otherwise we would have to change
+ `anychar's code to do something besides goto fail in this
+ case; that seems worse than this. */
+ case on_failure_keep_string_jump:
+ DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
+
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+#ifdef _LIBC
+ DEBUG_PRINT3 (" %d (to %p):\n", mcnt, p + mcnt);
+#else
+ DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
+#endif
+
+ PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
+ break;
+
+
+ /* Uses of on_failure_jump:
+
+ Each alternative starts with an on_failure_jump that points
+ to the beginning of the next alternative. Each alternative
+ except the last ends with a jump that in effect jumps past
+ the rest of the alternatives. (They really jump to the
+ ending jump of the following alternative, because tensioning
+ these jumps is a hassle.)
+
+ Repeats start with an on_failure_jump that points past both
+ the repetition text and either the following jump or
+ pop_failure_jump back to this on_failure_jump. */
+ case on_failure_jump:
+ on_failure:
+ DEBUG_PRINT1 ("EXECUTING on_failure_jump");
+
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+#ifdef _LIBC
+ DEBUG_PRINT3 (" %d (to %p)", mcnt, p + mcnt);
+#else
+ DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
+#endif
+
+ /* If this on_failure_jump comes right before a group (i.e.,
+ the original * applied to a group), save the information
+ for that group and all inner ones, so that if we fail back
+ to this point, the group's information will be correct.
+ For example, in \(a*\)*\1, we need the preceding group,
+ and in \(zz\(a*\)b*\)\2, we need the inner group. */
+
+ /* We can't use `p' to check ahead because we push
+ a failure point to `p + mcnt' after we do this. */
+ p1 = p;
+
+ /* We need to skip no_op's before we look for the
+ start_memory in case this on_failure_jump is happening as
+ the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
+ against aba. */
+ while (p1 < pend && (re_opcode_t) *p1 == no_op)
+ p1++;
+
+ if (p1 < pend && (re_opcode_t) *p1 == start_memory)
+ {
+ /* We have a new highest active register now. This will
+ get reset at the start_memory we are about to get to,
+ but we will have saved all the registers relevant to
+ this repetition op, as described above. */
+ highest_active_reg = *(p1 + 1) + *(p1 + 2);
+ if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+ lowest_active_reg = *(p1 + 1);
+ }
+
+ DEBUG_PRINT1 (":\n");
+ PUSH_FAILURE_POINT (p + mcnt, d, -2);
+ break;
+
+
+ /* A smart repeat ends with `maybe_pop_jump'.
+ We change it to either `pop_failure_jump' or `jump'. */
+ case maybe_pop_jump:
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
+ {
+ register unsigned char *p2 = p;
+
+ /* Compare the beginning of the repeat with what in the
+ pattern follows its end. If we can establish that there
+ is nothing that they would both match, i.e., that we
+ would have to backtrack because of (as in, e.g., `a*a')
+ then we can change to pop_failure_jump, because we'll
+ never have to backtrack.
+
+ This is not true in the case of alternatives: in
+ `(a|ab)*' we do need to backtrack to the `ab' alternative
+ (e.g., if the string was `ab'). But instead of trying to
+ detect that here, the alternative has put on a dummy
+ failure point which is what we will end up popping. */
+
+ /* Skip over open/close-group commands.
+ If what follows this loop is a ...+ construct,
+ look at what begins its body, since we will have to
+ match at least one of that. */
+ while (1)
+ {
+ if (p2 + 2 < pend
+ && ((re_opcode_t) *p2 == stop_memory
+ || (re_opcode_t) *p2 == start_memory))
+ p2 += 3;
+ else if (p2 + 6 < pend
+ && (re_opcode_t) *p2 == dummy_failure_jump)
+ p2 += 6;
+ else
+ break;
+ }
+
+ p1 = p + mcnt;
+ /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
+ to the `maybe_finalize_jump' of this case. Examine what
+ follows. */
+
+ /* If we're at the end of the pattern, we can change. */
+ if (p2 == pend)
+ {
+ /* Consider what happens when matching ":\(.*\)"
+ against ":/". I don't really understand this code
+ yet. */
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1
+ (" End of pattern: change to `pop_failure_jump'.\n");
+ }
+
+ else if ((re_opcode_t) *p2 == exactn
+ || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
+ {
+ register unsigned char c
+ = *p2 == (unsigned char) endline ? '\n' : p2[2];
+
+ if ((re_opcode_t) p1[3] == exactn && p1[5] != c)
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n",
+ c, p1[5]);
+ }
+
+ else if ((re_opcode_t) p1[3] == charset
+ || (re_opcode_t) p1[3] == charset_not)
+ {
+ int not = (re_opcode_t) p1[3] == charset_not;
+
+ if (c < (unsigned char) (p1[4] * BYTEWIDTH)
+ && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+ not = !not;
+
+ /* `not' is equal to 1 if c would match, which means
+ that we can't change to pop_failure_jump. */
+ if (!not)
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
+ }
+ }
+ }
+ else if ((re_opcode_t) *p2 == charset)
+ {
+#ifdef DEBUG
+ register unsigned char c
+ = *p2 == (unsigned char) endline ? '\n' : p2[2];
+#endif
+
+#if 0
+ if ((re_opcode_t) p1[3] == exactn
+ && ! ((int) p2[1] * BYTEWIDTH > (int) p1[5]
+ && (p2[2 + p1[5] / BYTEWIDTH]
+ & (1 << (p1[5] % BYTEWIDTH)))))
+#else
+ if ((re_opcode_t) p1[3] == exactn
+ && ! ((int) p2[1] * BYTEWIDTH > (int) p1[4]
+ && (p2[2 + p1[4] / BYTEWIDTH]
+ & (1 << (p1[4] % BYTEWIDTH)))))
+#endif
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n",
+ c, p1[5]);
+ }
+
+ else if ((re_opcode_t) p1[3] == charset_not)
+ {
+ int idx;
+ /* We win if the charset_not inside the loop
+ lists every character listed in the charset after. */
+ for (idx = 0; idx < (int) p2[1]; idx++)
+ if (! (p2[2 + idx] == 0
+ || (idx < (int) p1[4]
+ && ((p2[2 + idx] & ~ p1[5 + idx]) == 0))))
+ break;
+
+ if (idx == p2[1])
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
+ }
+ }
+ else if ((re_opcode_t) p1[3] == charset)
+ {
+ int idx;
+ /* We win if the charset inside the loop
+ has no overlap with the one after the loop. */
+ for (idx = 0;
+ idx < (int) p2[1] && idx < (int) p1[4];
+ idx++)
+ if ((p2[2 + idx] & p1[5 + idx]) != 0)
+ break;
+
+ if (idx == p2[1] || idx == p1[4])
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
+ }
+ }
+ }
+ }
+ p -= 2; /* Point at relative address again. */
+ if ((re_opcode_t) p[-1] != pop_failure_jump)
+ {
+ p[-1] = (unsigned char) jump;
+ DEBUG_PRINT1 (" Match => jump.\n");
+ goto unconditional_jump;
+ }
+ /* Note fall through. */
+
+
+ /* The end of a simple repeat has a pop_failure_jump back to
+ its matching on_failure_jump, where the latter will push a
+ failure point. The pop_failure_jump takes off failure
+ points put on by this pop_failure_jump's matching
+ on_failure_jump; we got through the pattern to here from the
+ matching on_failure_jump, so didn't fail. */
+ case pop_failure_jump:
+ {
+ /* We need to pass separate storage for the lowest and
+ highest registers, even though we don't care about the
+ actual values. Otherwise, we will restore only one
+ register from the stack, since lowest will == highest in
+ `pop_failure_point'. */
+ active_reg_t dummy_low_reg, dummy_high_reg;
+ unsigned char *pdummy;
+ const char *sdummy;
+
+ DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
+ POP_FAILURE_POINT (sdummy, pdummy,
+ dummy_low_reg, dummy_high_reg,
+ reg_dummy, reg_dummy, reg_info_dummy);
+ }
+ /* Note fall through. */
+
+ unconditional_jump:
+#ifdef _LIBC
+ DEBUG_PRINT2 ("\n%p: ", p);
+#else
+ DEBUG_PRINT2 ("\n0x%x: ", p);
+#endif
+ /* Note fall through. */
+
+ /* Unconditionally jump (without popping any failure points). */
+ case jump:
+ EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */
+ DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
+ p += mcnt; /* Do the jump. */
+#ifdef _LIBC
+ DEBUG_PRINT2 ("(to %p).\n", p);
+#else
+ DEBUG_PRINT2 ("(to 0x%x).\n", p);
+#endif
+ break;
+
+
+ /* We need this opcode so we can detect where alternatives end
+ in `group_match_null_string_p' et al. */
+ case jump_past_alt:
+ DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
+ goto unconditional_jump;
+
+
+ /* Normally, the on_failure_jump pushes a failure point, which
+ then gets popped at pop_failure_jump. We will end up at
+ pop_failure_jump, also, and with a pattern of, say, `a+', we
+ are skipping over the on_failure_jump, so we have to push
+ something meaningless for pop_failure_jump to pop. */
+ case dummy_failure_jump:
+ DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
+ /* It doesn't matter what we push for the string here. What
+ the code at `fail' tests is the value for the pattern. */
+ PUSH_FAILURE_POINT (NULL, NULL, -2);
+ goto unconditional_jump;
+
+
+ /* At the end of an alternative, we need to push a dummy failure
+ point in case we are followed by a `pop_failure_jump', because
+ we don't want the failure point for the alternative to be
+ popped. For example, matching `(a|ab)*' against `aab'
+ requires that we match the `ab' alternative. */
+ case push_dummy_failure:
+ DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
+ /* See comments just above at `dummy_failure_jump' about the
+ two zeroes. */
+ PUSH_FAILURE_POINT (NULL, NULL, -2);
+ break;
+
+ /* Have to succeed matching what follows at least n times.
+ After that, handle like `on_failure_jump'. */
+ case succeed_n:
+ EXTRACT_NUMBER (mcnt, p + 2);
+ DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
+
+ assert (mcnt >= 0);
+ /* Originally, this is how many times we HAVE to succeed. */
+ if (mcnt > 0)
+ {
+ mcnt--;
+ p += 2;
+ STORE_NUMBER_AND_INCR (p, mcnt);
+#ifdef _LIBC
+ DEBUG_PRINT3 (" Setting %p to %d.\n", p - 2, mcnt);
+#else
+ DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p - 2, mcnt);
+#endif
+ }
+ else if (mcnt == 0)
+ {
+#ifdef _LIBC
+ DEBUG_PRINT2 (" Setting two bytes from %p to no_op.\n", p+2);
+#else
+ DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2);
+#endif
+ p[2] = (unsigned char) no_op;
+ p[3] = (unsigned char) no_op;
+ goto on_failure;
+ }
+ break;
+
+ case jump_n:
+ EXTRACT_NUMBER (mcnt, p + 2);
+ DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
+
+ /* Originally, this is how many times we CAN jump. */
+ if (mcnt)
+ {
+ mcnt--;
+ STORE_NUMBER (p + 2, mcnt);
+#ifdef _LIBC
+ DEBUG_PRINT3 (" Setting %p to %d.\n", p + 2, mcnt);
+#else
+ DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p + 2, mcnt);
+#endif
+ goto unconditional_jump;
+ }
+ /* If don't have to jump any more, skip over the rest of command. */
+ else
+ p += 4;
+ break;
+
+ case set_number_at:
+ {
+ DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
+
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ p1 = p + mcnt;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+#ifdef _LIBC
+ DEBUG_PRINT3 (" Setting %p to %d.\n", p1, mcnt);
+#else
+ DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt);
+#endif
+ STORE_NUMBER (p1, mcnt);
+ break;
+ }
+
+#if 0
+ /* The DEC Alpha C compiler 3.x generates incorrect code for the
+ test WORDCHAR_P (d - 1) != WORDCHAR_P (d) in the expansion of
+ AT_WORD_BOUNDARY, so this code is disabled. Expanding the
+ macro and introducing temporary variables works around the bug. */
+
+ case wordbound:
+ DEBUG_PRINT1 ("EXECUTING wordbound.\n");
+ if (AT_WORD_BOUNDARY (d))
+ break;
+ goto fail;
+
+ case notwordbound:
+ DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
+ if (AT_WORD_BOUNDARY (d))
+ goto fail;
+ break;
+#else
+ case wordbound:
+ {
+ boolean prevchar, thischar;
+
+ DEBUG_PRINT1 ("EXECUTING wordbound.\n");
+ if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d))
+ break;
+
+ prevchar = WORDCHAR_P (d - 1);
+ thischar = WORDCHAR_P (d);
+ if (prevchar != thischar)
+ break;
+ goto fail;
+ }
+
+ case notwordbound:
+ {
+ boolean prevchar, thischar;
+
+ DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
+ if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d))
+ goto fail;
+
+ prevchar = WORDCHAR_P (d - 1);
+ thischar = WORDCHAR_P (d);
+ if (prevchar != thischar)
+ goto fail;
+ break;
+ }
+#endif
+
+ case wordbeg:
+ DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
+ if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
+ break;
+ goto fail;
+
+ case wordend:
+ DEBUG_PRINT1 ("EXECUTING wordend.\n");
+ if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
+ && (!WORDCHAR_P (d) || AT_STRINGS_END (d)))
+ break;
+ goto fail;
+
+#ifdef emacs
+ case before_dot:
+ DEBUG_PRINT1 ("EXECUTING before_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) >= point)
+ goto fail;
+ break;
+
+ case at_dot:
+ DEBUG_PRINT1 ("EXECUTING at_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) != point)
+ goto fail;
+ break;
+
+ case after_dot:
+ DEBUG_PRINT1 ("EXECUTING after_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) <= point)
+ goto fail;
+ break;
+
+ case syntaxspec:
+ DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
+ mcnt = *p++;
+ goto matchsyntax;
+
+ case wordchar:
+ DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
+ mcnt = (int) Sword;
+ matchsyntax:
+ PREFETCH ();
+ /* Can't use *d++ here; SYNTAX may be an unsafe macro. */
+ d++;
+ if (SYNTAX (d[-1]) != (enum syntaxcode) mcnt)
+ goto fail;
+ SET_REGS_MATCHED ();
+ break;
+
+ case notsyntaxspec:
+ DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
+ mcnt = *p++;
+ goto matchnotsyntax;
+
+ case notwordchar:
+ DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
+ mcnt = (int) Sword;
+ matchnotsyntax:
+ PREFETCH ();
+ /* Can't use *d++ here; SYNTAX may be an unsafe macro. */
+ d++;
+ if (SYNTAX (d[-1]) == (enum syntaxcode) mcnt)
+ goto fail;
+ SET_REGS_MATCHED ();
+ break;
+
+#else /* not emacs */
+ case wordchar:
+ DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
+ PREFETCH ();
+ if (!WORDCHAR_P (d))
+ goto fail;
+ SET_REGS_MATCHED ();
+ d++;
+ break;
+
+ case notwordchar:
+ DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
+ PREFETCH ();
+ if (WORDCHAR_P (d))
+ goto fail;
+ SET_REGS_MATCHED ();
+ d++;
+ break;
+#endif /* not emacs */
+
+ default:
+ abort ();
+ }
+ continue; /* Successfully executed one pattern command; keep going. */
+
+
+ /* We goto here if a matching operation fails. */
+ fail:
+ if (!FAIL_STACK_EMPTY ())
+ { /* A restart point is known. Restore to that state. */
+ DEBUG_PRINT1 ("\nFAIL:\n");
+ POP_FAILURE_POINT (d, p,
+ lowest_active_reg, highest_active_reg,
+ regstart, regend, reg_info);
+
+ /* If this failure point is a dummy, try the next one. */
+ if (!p)
+ goto fail;
+
+ /* If we failed to the end of the pattern, don't examine *p. */
+ assert (p <= pend);
+ if (p < pend)
+ {
+ boolean is_a_jump_n = false;
+
+ /* If failed to a backwards jump that's part of a repetition
+ loop, need to pop this failure point and use the next one. */
+ switch ((re_opcode_t) *p)
+ {
+ case jump_n:
+ is_a_jump_n = true;
+ case maybe_pop_jump:
+ case pop_failure_jump:
+ case jump:
+ p1 = p + 1;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ p1 += mcnt;
+
+ if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
+ || (!is_a_jump_n
+ && (re_opcode_t) *p1 == on_failure_jump))
+ goto fail;
+ break;
+ default:
+ /* do nothing */ ;
+ }
+ }
+
+ if (d >= string1 && d <= end1)
+ dend = end_match_1;
+ }
+ else
+ break; /* Matching at this starting point really fails. */
+ } /* for (;;) */
+
+ if (best_regs_set)
+ goto restore_best_regs;
+
+ FREE_VARIABLES ();
+
+ return -1; /* Failure to match. */
+} /* re_match_2 */
+
+/* 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 ? &regs : (struct re_registers *) 0);
+
+ /* Copy the register information to the POSIX structure. */
+ if (want_reg_info)
+ {
+ if (ret >= 0)
+ {
+ unsigned r;
+
+ for (r = 0; r < nmatch; r++)
+ {
+ pmatch[r].rm_so = regs.start[r];
+ pmatch[r].rm_eo = regs.end[r];
+ }
+ }
+
+ /* If we needed the temporary register info, free the space now. */
+ free (regs.start);
+ }
+
+ /* We want zero return to mean success, unlike `re_search'. */
+ return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
+}
+#ifdef _LIBC
+weak_alias (__regexec, regexec)
+#endif
+
+
+/* Returns a message corresponding to an error code, ERRCODE, returned
+ from either regcomp or regexec. We don't use PREG here. */
+
+size_t
+regerror (errcode, preg, errbuf, errbuf_size)
+ int errcode;
+ const regex_t *preg;
+ char *errbuf;
+ size_t errbuf_size;
+{
+ const char *msg;
+ size_t msg_size;
+
+ if (errcode < 0
+ || errcode >= (int) (sizeof (re_error_msgid_idx)
+ / sizeof (re_error_msgid_idx[0])))
+ /* Only error codes returned by the rest of the code should be passed
+ to this routine. If we are given anything else, or if other regex
+ code generates an invalid error code, then the program has a bug.
+ Dump core so we can fix it. */
+ abort ();
+
+ msg = gettext (re_error_msgid + re_error_msgid_idx[errcode]);
+
+ msg_size = strlen (msg) + 1; /* Includes the null. */
+
+ if (errbuf_size != 0)
+ {
+ if (msg_size > errbuf_size)
+ {
+#if defined HAVE_MEMPCPY || defined _LIBC
+ *((char *) __mempcpy (errbuf, msg, errbuf_size - 1)) = '\0';
+#else
+ memcpy (errbuf, msg, errbuf_size - 1);
+ errbuf[errbuf_size - 1] = 0;
+#endif
+ }
+ else
+ memcpy (errbuf, msg, msg_size);
+ }
+
+ return msg_size;
+}
+#ifdef _LIBC
+weak_alias (__regerror, regerror)
+#endif
+
+
+/* Free dynamically allocated space used by PREG. */
+
+void
+regfree (preg)
+ regex_t *preg;
+{
+ if (preg->buffer != NULL)
+ free (preg->buffer);
+ preg->buffer = NULL;
+
+ preg->allocated = 0;
+ preg->used = 0;
+
+ if (preg->fastmap != NULL)
+ free (preg->fastmap);
+ preg->fastmap = NULL;
+ preg->fastmap_accurate = 0;
+
+ if (preg->translate != NULL)
+ free (preg->translate);
+ preg->translate = NULL;
+}
+#ifdef _LIBC
+weak_alias (__regfree, regfree)
+#endif
+
+#endif /* not emacs */
diff --git a/lib/routemap.c b/lib/routemap.c
new file mode 100644
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 <zebra.h>
+
+#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 <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#ifdef HAVE_SNMP
+
+#include <asn1.h>
+#include <snmp.h>
+#include <snmp_impl.h>
+
+#include "smux.h"
+#include "log.h"
+#include "thread.h"
+#include "linklist.h"
+#include "command.h"
+#include "version.h"
+#include "memory.h"
+#include "sockunion.h"
+
+#define min(A,B) ((A) < (B) ? (A) : (B))
+
+enum smux_event {SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ};
+
+void smux_event (enum smux_event, int);
+
+
+/* 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 <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_SNMP_H
+#define _ZEBRA_SNMP_H
+
+#define SMUX_PORT_DEFAULT 199
+
+#define SMUXMAXPKTSIZE 1500
+#define SMUXMAXSTRLEN 256
+
+#define SMUX_OPEN (ASN_APPLICATION | ASN_CONSTRUCTOR | 0)
+#define SMUX_CLOSE (ASN_APPLICATION | ASN_PRIMITIVE | 1)
+#define SMUX_RREQ (ASN_APPLICATION | ASN_CONSTRUCTOR | 2)
+#define SMUX_RRSP (ASN_APPLICATION | ASN_PRIMITIVE | 3)
+#define SMUX_SOUT (ASN_APPLICATION | ASN_PRIMITIVE | 4)
+
+#define SMUX_GET (ASN_CONTEXT | ASN_CONSTRUCTOR | 0)
+#define SMUX_GETNEXT (ASN_CONTEXT | ASN_CONSTRUCTOR | 1)
+#define SMUX_GETRSP (ASN_CONTEXT | ASN_CONSTRUCTOR | 2)
+#define SMUX_SET (ASN_CONTEXT | ASN_CONSTRUCTOR | 3)
+#define SMUX_TRAP (ASN_CONTEXT | ASN_CONSTRUCTOR | 4)
+
+#define SMUX_MAX_FAILURE 3
+
+/* Structures here are mostly compatible with UCD SNMP 4.1.1 */
+#define MATCH_FAILED (-1)
+#define MATCH_SUCCEEDED 0
+
+/* SYNTAX TruthValue from SNMPv2-TC. */
+#define SNMP_TRUE 1
+#define SNMP_FALSE 2
+
+/* SYNTAX RowStatus from SNMPv2-TC. */
+#define SNMP_VALID 1
+#define SNMP_INVALID 2
+
+#define IN_ADDR_SIZE sizeof(struct in_addr)
+
+struct variable;
+
+#define REGISTER_MIB(descr, var, vartype, theoid) \
+ smux_register_mib(descr, (struct variable *)var, sizeof(struct vartype), \
+ sizeof(var)/sizeof(struct vartype), \
+ theoid, sizeof(theoid)/sizeof(oid))
+
+typedef int (WriteMethod)(int action,
+ u_char *var_val,
+ u_char var_val_type,
+ size_t var_val_len,
+ u_char *statP,
+ oid *name,
+ size_t length,
+ struct variable *v);
+
+typedef u_char *(FindVarMethod)(struct variable *v,
+ oid *name,
+ size_t *length,
+ int exact,
+ size_t *var_len,
+ WriteMethod **write_method);
+
+/* SNMP variable */
+struct variable
+{
+ /* Index of the MIB.*/
+ u_char magic;
+
+ /* Type of variable. */
+ char type;
+
+ /* Access control list. */
+ u_short acl;
+
+ /* Callback function. */
+ FindVarMethod *findVar;
+
+ /* Suffix of the MIB. */
+ u_char namelen;
+ oid name[MAX_OID_LEN];
+};
+
+/* SNMP tree. */
+struct subtree
+{
+ /* Tree's oid. */
+ oid name[MAX_OID_LEN];
+ u_char name_len;
+
+ /* List of the variables. */
+ struct variable *variables;
+
+ /* Length of the variables list. */
+ int variables_num;
+
+ /* Width of the variables list. */
+ int variables_width;
+
+ /* Registered flag. */
+ int registered;
+};
+
+struct trap_object
+{
+ FindVarMethod *findVar;
+ u_char namelen;
+ oid name[MAX_OID_LEN];
+};
+
+/* Declare SMUX return value. */
+#define SNMP_LOCAL_VARIABLES \
+ static int32_t snmp_int_val; \
+ static struct in_addr snmp_in_addr_val;
+
+#define SNMP_INTEGER(V) \
+ ( \
+ *var_len = sizeof (int32_t), \
+ snmp_int_val = V, \
+ (u_char *) &snmp_int_val \
+ )
+
+#define SNMP_IPADDRESS(V) \
+ ( \
+ *var_len = sizeof (struct in_addr), \
+ snmp_in_addr_val = V, \
+ (u_char *) &snmp_in_addr_val \
+ )
+
+void smux_init (oid [], size_t);
+void smux_start (void);
+void smux_register_mib(char *, struct variable *, size_t, int, oid [], size_t);
+int smux_header_generic (struct variable *, oid [], size_t *, int, size_t *,
+ WriteMethod **);
+int smux_trap (oid *, size_t, oid *, size_t, struct trap_object *, size_t, unsigned int);
+
+int oid_compare (oid *, int, oid *, int);
+void oid2in_addr (oid [], int, struct in_addr *);
+void *oid_copy (void *, void *, size_t);
+void oid_copy_addr (oid [], struct in_addr *, int);
+
+#endif /* _ZEBRA_SNMP_H */
diff --git a/lib/sockopt.c b/lib/sockopt.c
new file mode 100644
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 <zebra.h>
+#include "log.h"
+
+#ifdef HAVE_IPV6
+/* Set IPv6 packet info to the socket. */
+int
+setsockopt_ipv6_pktinfo (int sock, int val)
+{
+ int ret;
+
+#ifdef IPV6_RECVPKTINFO /*2292bis-01*/
+ ret = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val));
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IPV6_RECVPKTINFO : %s", strerror (errno));
+#else /*RFC2292*/
+ ret = setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &val, sizeof(val));
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IPV6_PKTINFO : %s", strerror (errno));
+#endif /* INIA_IPV6 */
+ return ret;
+}
+
+/* Set multicast hops val to the socket. */
+int
+setsockopt_ipv6_checksum (int sock, int val)
+{
+ int ret;
+
+#ifdef GNU_LINUX
+ ret = setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val));
+#else
+ ret = setsockopt(sock, IPPROTO_IPV6, IPV6_CHECKSUM, &val, sizeof(val));
+#endif /* GNU_LINUX */
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IPV6_CHECKSUM");
+ return ret;
+}
+
+/* Set multicast hops val to the socket. */
+int
+setsockopt_ipv6_multicast_hops (int sock, int val)
+{
+ int ret;
+
+ ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val));
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IPV6_MULTICAST_HOPS");
+ return ret;
+}
+
+/* Set multicast hops val to the socket. */
+int
+setsockopt_ipv6_unicast_hops (int sock, int val)
+{
+ int ret;
+
+ ret = setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val));
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IPV6_UNICAST_HOPS");
+ return ret;
+}
+
+int
+setsockopt_ipv6_hoplimit (int sock, int val)
+{
+ int ret;
+
+#ifdef IPV6_RECVHOPLIMIT /*2292bis-01*/
+ ret = setsockopt (sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val));
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IPV6_RECVHOPLIMIT");
+#else /*RFC2292*/
+ ret = setsockopt (sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &val, sizeof(val));
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IPV6_HOPLIMIT");
+#endif
+ return ret;
+}
+
+/* Set multicast loop zero to the socket. */
+int
+setsockopt_ipv6_multicast_loop (int sock, int val)
+{
+ int ret;
+
+ ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
+ sizeof (val));
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IPV6_MULTICAST_LOOP");
+ return ret;
+}
+
+#endif /* HAVE_IPV6 */
+
+
+/* Set up a multicast socket options for IPv4
+ This is here so that people only have to do their OS multicast mess
+ in one place rather than all through zebra, ospfd, and ripd
+ NB: This is a hookpoint for specific OS functionality */
+int
+setsockopt_multicast_ipv4(int sock,
+ int optname,
+ struct in_addr if_addr,
+ unsigned int mcast_addr,
+ unsigned int ifindex)
+{
+
+ /* Linux 2.2.0 and up */
+#if defined(GNU_LINUX) && LINUX_VERSION_CODE > 131584
+ /* This is better because it uses ifindex directly */
+ struct ip_mreqn mreqn;
+
+ switch (optname)
+ {
+ case IP_MULTICAST_IF:
+ case IP_ADD_MEMBERSHIP:
+ case IP_DROP_MEMBERSHIP:
+ memset (&mreqn, 0, sizeof(mreqn));
+
+ if (mcast_addr)
+ mreqn.imr_multiaddr.s_addr = mcast_addr;
+
+ if (ifindex)
+ mreqn.imr_ifindex = ifindex;
+ else
+ mreqn.imr_address = if_addr;
+
+ return setsockopt(sock, IPPROTO_IP, optname, (void *)&mreqn, sizeof(mreqn));
+ break;
+
+ default:
+ /* Can out and give an understandable error */
+ errno = EINVAL;
+ return -1;
+ break;
+ }
+
+ /* Example defines for another OS, boilerplate off other code in this
+ function, AND handle optname as per other sections for consistency !! */
+ /* #elif defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */
+ /* Add your favourite OS here! */
+
+#else /* #if OS_TYPE */
+ /* default OS support */
+
+ struct in_addr m;
+ struct ip_mreq mreq;
+
+ switch (optname)
+ {
+ case IP_MULTICAST_IF:
+ m = if_addr;
+
+ return setsockopt (sock, IPPROTO_IP, optname, (void *)&m, sizeof(m));
+ break;
+
+ case IP_ADD_MEMBERSHIP:
+ case IP_DROP_MEMBERSHIP:
+ memset (&mreq, 0, sizeof(mreq));
+ mreq.imr_multiaddr.s_addr = mcast_addr;
+ mreq.imr_interface = if_addr;
+
+ return setsockopt (sock,
+ IPPROTO_IP,
+ optname,
+ (void *)&mreq,
+ sizeof(mreq));
+ break;
+
+ default:
+ /* Can out and give an understandable error */
+ errno = EINVAL;
+ return -1;
+ break;
+ }
+#endif /* #if OS_TYPE */
+
+}
diff --git a/lib/sockopt.h b/lib/sockopt.h
new file mode 100644
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 <zebra.h>
+
+#include "prefix.h"
+#include "vty.h"
+#include "sockunion.h"
+#include "memory.h"
+#include "str.h"
+#include "log.h"
+
+#ifndef HAVE_INET_ATON
+int
+inet_aton (const char *cp, struct in_addr *inaddr)
+{
+ int dots = 0;
+ register u_long addr = 0;
+ register u_long val = 0, base = 10;
+
+ do
+ {
+ register char c = *cp;
+
+ switch (c)
+ {
+ case '0': case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ val = (val * base) + (c - '0');
+ break;
+ case '.':
+ if (++dots > 3)
+ return 0;
+ case '\0':
+ if (val > 255)
+ return 0;
+ addr = addr << 8 | val;
+ val = 0;
+ break;
+ default:
+ return 0;
+ }
+ } while (*cp++) ;
+
+ if (dots < 3)
+ addr <<= 8 * (3 - dots);
+ if (inaddr)
+ inaddr->s_addr = htonl (addr);
+ return 1;
+}
+#endif /* ! HAVE_INET_ATON */
+
+
+#ifndef HAVE_INET_PTON
+int
+inet_pton (int family, const char *strptr, void *addrptr)
+{
+ if (family == AF_INET)
+ {
+ struct in_addr in_val;
+
+ if (inet_aton (strptr, &in_val))
+ {
+ memcpy (addrptr, &in_val, sizeof (struct in_addr));
+ return 1;
+ }
+ return 0;
+ }
+ errno = EAFNOSUPPORT;
+ return -1;
+}
+#endif /* ! HAVE_INET_PTON */
+
+#ifndef HAVE_INET_NTOP
+const char *
+inet_ntop (int family, const void *addrptr, char *strptr, size_t len)
+{
+ unsigned char *p = (unsigned char *) addrptr;
+
+ if (family == AF_INET)
+ {
+ char temp[INET_ADDRSTRLEN];
+
+ snprintf(temp, sizeof(temp), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+
+ if (strlen(temp) >= len)
+ {
+ errno = ENOSPC;
+ return NULL;
+ }
+ strcpy(strptr, temp);
+ return strptr;
+ }
+
+ errno = EAFNOSUPPORT;
+ return NULL;
+}
+#endif /* ! HAVE_INET_NTOP */
+
+const char *
+inet_sutop (union sockunion *su, char *str)
+{
+ switch (su->sa.sa_family)
+ {
+ case AF_INET:
+ inet_ntop (AF_INET, &su->sin.sin_addr, str, INET_ADDRSTRLEN);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, INET6_ADDRSTRLEN);
+ break;
+#endif /* HAVE_IPV6 */
+ }
+ return str;
+}
+
+int
+str2sockunion (char *str, union sockunion *su)
+{
+ int ret;
+
+ memset (su, 0, sizeof (union sockunion));
+
+ ret = inet_pton (AF_INET, str, &su->sin.sin_addr);
+ if (ret > 0) /* Valid IPv4 address format. */
+ {
+ su->sin.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+ su->sin.sin_len = sizeof(struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+ return 0;
+ }
+#ifdef HAVE_IPV6
+ ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr);
+ if (ret > 0) /* Valid IPv6 address format. */
+ {
+ su->sin6.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+ su->sin6.sin6_len = sizeof(struct sockaddr_in6);
+#endif /* SIN6_LEN */
+ return 0;
+ }
+#endif /* HAVE_IPV6 */
+ return -1;
+}
+
+const char *
+sockunion2str (union sockunion *su, char *buf, size_t len)
+{
+ if (su->sa.sa_family == AF_INET)
+ return inet_ntop (AF_INET, &su->sin.sin_addr, buf, len);
+#ifdef HAVE_IPV6
+ else if (su->sa.sa_family == AF_INET6)
+ return inet_ntop (AF_INET6, &su->sin6.sin6_addr, buf, len);
+#endif /* HAVE_IPV6 */
+ return NULL;
+}
+
+union sockunion *
+sockunion_str2su (char *str)
+{
+ int ret;
+ union sockunion *su;
+
+ su = XMALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
+ memset (su, 0, sizeof (union sockunion));
+
+ ret = inet_pton (AF_INET, str, &su->sin.sin_addr);
+ if (ret > 0) /* Valid IPv4 address format. */
+ {
+ su->sin.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+ su->sin.sin_len = sizeof(struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+ return su;
+ }
+#ifdef HAVE_IPV6
+ ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr);
+ if (ret > 0) /* Valid IPv6 address format. */
+ {
+ su->sin6.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+ su->sin6.sin6_len = sizeof(struct sockaddr_in6);
+#endif /* SIN6_LEN */
+ return su;
+ }
+#endif /* HAVE_IPV6 */
+
+ XFREE (MTYPE_SOCKUNION, su);
+ return NULL;
+}
+
+char *
+sockunion_su2str (union sockunion *su)
+{
+ char str[INET6_ADDRSTRLEN];
+
+ switch (su->sa.sa_family)
+ {
+ case AF_INET:
+ inet_ntop (AF_INET, &su->sin.sin_addr, str, sizeof (str));
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, sizeof (str));
+ break;
+#endif /* HAVE_IPV6 */
+ }
+ return strdup (str);
+}
+
+/* Return socket of sockunion. */
+int
+sockunion_socket (union sockunion *su)
+{
+ int sock;
+
+ sock = socket (su->sa.sa_family, SOCK_STREAM, 0);
+ if (sock < 0)
+ {
+ zlog (NULL, LOG_WARNING, "Can't make socket : %s", strerror (errno));
+ return -1;
+ }
+
+ return sock;
+}
+
+/* Return accepted new socket file descriptor. */
+int
+sockunion_accept (int sock, union sockunion *su)
+{
+ socklen_t len;
+ int client_sock;
+
+ len = sizeof (union sockunion);
+ client_sock = accept (sock, (struct sockaddr *) su, &len);
+
+ /* Convert IPv4 compatible IPv6 address to IPv4 address. */
+#ifdef HAVE_IPV6
+ if (su->sa.sa_family == AF_INET6)
+ {
+ if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr))
+ {
+ struct sockaddr_in sin;
+
+ memset (&sin, 0, sizeof (struct sockaddr_in));
+ sin.sin_family = AF_INET;
+ memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4);
+ memcpy (su, &sin, sizeof (struct sockaddr_in));
+ }
+ }
+#endif /* HAVE_IPV6 */
+
+ return client_sock;
+}
+
+/* Return sizeof union sockunion. */
+int
+sockunion_sizeof (union sockunion *su)
+{
+ int ret;
+
+ ret = 0;
+ switch (su->sa.sa_family)
+ {
+ case AF_INET:
+ ret = sizeof (struct sockaddr_in);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ ret = sizeof (struct sockaddr_in6);
+ break;
+#endif /* AF_INET6 */
+ }
+ return ret;
+}
+
+/* return sockunion structure : this function should be revised. */
+char *
+sockunion_log (union sockunion *su)
+{
+ static char buf[SU_ADDRSTRLEN];
+
+ switch (su->sa.sa_family)
+ {
+ case AF_INET:
+ snprintf (buf, BUFSIZ, "%s", inet_ntoa (su->sin.sin_addr));
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ snprintf (buf, BUFSIZ, "%s",
+ inet_ntop (AF_INET6, &(su->sin6.sin6_addr), buf, BUFSIZ));
+ break;
+#endif /* HAVE_IPV6 */
+ default:
+ snprintf (buf, BUFSIZ, "af_unknown %d ", su->sa.sa_family);
+ break;
+ }
+ return buf;
+}
+
+/* sockunion_connect returns
+ -1 : error occured
+ 0 : connect success
+ 1 : connect is in progress */
+enum connect_result
+sockunion_connect (int fd, union sockunion *peersu, unsigned short port,
+ unsigned int ifindex)
+{
+ int ret;
+ int val;
+ union sockunion su;
+
+ memcpy (&su, peersu, sizeof (union sockunion));
+
+ switch (su.sa.sa_family)
+ {
+ case AF_INET:
+ su.sin.sin_port = port;
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ su.sin6.sin6_port = port;
+#ifdef KAME
+ if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex)
+ {
+#ifdef HAVE_SIN6_SCOPE_ID
+ /* su.sin6.sin6_scope_id = ifindex; */
+#endif /* HAVE_SIN6_SCOPE_ID */
+ SET_IN6_LINKLOCAL_IFINDEX (su.sin6.sin6_addr, ifindex);
+ }
+#endif /* KAME */
+ break;
+#endif /* HAVE_IPV6 */
+ }
+
+ /* Make socket non-block. */
+ val = fcntl (fd, F_GETFL, 0);
+ fcntl (fd, F_SETFL, val|O_NONBLOCK);
+
+ /* Call connect function. */
+ ret = connect (fd, (struct sockaddr *) &su, sockunion_sizeof (&su));
+
+ /* Immediate success */
+ if (ret == 0)
+ {
+ fcntl (fd, F_SETFL, val);
+ return connect_success;
+ }
+
+ /* If connect is in progress then return 1 else it's real error. */
+ if (ret < 0)
+ {
+ if (errno != EINPROGRESS)
+ {
+ zlog_info ("can't connect to %s fd %d : %s",
+ sockunion_log (&su), fd, strerror (errno));
+ return connect_error;
+ }
+ }
+
+ fcntl (fd, F_SETFL, val);
+
+ return connect_in_progress;
+}
+
+/* Make socket from sockunion union. */
+int
+sockunion_stream_socket (union sockunion *su)
+{
+ int sock;
+
+ if (su->sa.sa_family == 0)
+ su->sa.sa_family = AF_INET_UNION;
+
+ sock = socket (su->sa.sa_family, SOCK_STREAM, 0);
+
+ if (sock < 0)
+ zlog (NULL, LOG_WARNING, "can't make socket sockunion_stream_socket");
+
+ return sock;
+}
+
+/* Bind socket to specified address. */
+int
+sockunion_bind (int sock, union sockunion *su, unsigned short port,
+ union sockunion *su_addr)
+{
+ int size = 0;
+ int ret;
+
+ if (su->sa.sa_family == AF_INET)
+ {
+ size = sizeof (struct sockaddr_in);
+ su->sin.sin_port = htons (port);
+#ifdef HAVE_SIN_LEN
+ su->sin.sin_len = size;
+#endif /* HAVE_SIN_LEN */
+ if (su_addr == NULL)
+ su->sin.sin_addr.s_addr = htonl (INADDR_ANY);
+ }
+#ifdef HAVE_IPV6
+ else if (su->sa.sa_family == AF_INET6)
+ {
+ size = sizeof (struct sockaddr_in6);
+ su->sin6.sin6_port = htons (port);
+#ifdef SIN6_LEN
+ su->sin6.sin6_len = size;
+#endif /* SIN6_LEN */
+ if (su_addr == NULL)
+ {
+#if defined(LINUX_IPV6) || defined(NRL)
+ memset (&su->sin6.sin6_addr, 0, sizeof (struct in6_addr));
+#else
+ su->sin6.sin6_addr = in6addr_any;
+#endif /* LINUX_IPV6 */
+ }
+ }
+#endif /* HAVE_IPV6 */
+
+
+ ret = bind (sock, (struct sockaddr *)su, size);
+ if (ret < 0)
+ zlog (NULL, LOG_WARNING, "can't bind socket : %s", strerror (errno));
+
+ return ret;
+}
+
+int
+sockopt_reuseaddr (int sock)
+{
+ int ret;
+ int on = 1;
+
+ ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
+ (void *) &on, sizeof (on));
+ if (ret < 0)
+ {
+ zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEADDR to socket %d", sock);
+ return -1;
+ }
+ return 0;
+}
+
+#ifdef SO_REUSEPORT
+int
+sockopt_reuseport (int sock)
+{
+ int ret;
+ int on = 1;
+
+ ret = setsockopt (sock, SOL_SOCKET, SO_REUSEPORT,
+ (void *) &on, sizeof (on));
+ if (ret < 0)
+ {
+ zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEADDR to socket %d", sock);
+ return -1;
+ }
+ return 0;
+}
+#else
+int
+sockopt_reuseport (int sock)
+{
+ return 0;
+}
+#endif /* 0 */
+
+int
+sockopt_ttl (int family, int sock, int ttl)
+{
+ int ret;
+
+#ifdef IP_TTL
+ if (family == AF_INET)
+ {
+ ret = setsockopt (sock, IPPROTO_IP, IP_TTL,
+ (void *) &ttl, sizeof (int));
+ if (ret < 0)
+ {
+ zlog (NULL, LOG_WARNING, "can't set sockopt IP_TTL %d to socket %d", ttl, sock);
+ return -1;
+ }
+ return 0;
+ }
+#endif /* IP_TTL */
+#ifdef HAVE_IPV6
+ if (family == AF_INET6)
+ {
+ ret = setsockopt (sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
+ (void *) &ttl, sizeof (int));
+ if (ret < 0)
+ {
+ zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_UNICAST_HOPS %d to socket %d",
+ ttl, sock);
+ return -1;
+ }
+ return 0;
+ }
+#endif /* HAVE_IPV6 */
+ return 0;
+}
+
+/* If same family and same prefix return 1. */
+int
+sockunion_same (union sockunion *su1, union sockunion *su2)
+{
+ int ret = 0;
+
+ if (su1->sa.sa_family != su2->sa.sa_family)
+ return 0;
+
+ switch (su1->sa.sa_family)
+ {
+ case AF_INET:
+ ret = memcmp (&su1->sin.sin_addr, &su2->sin.sin_addr,
+ sizeof (struct in_addr));
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ ret = memcmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr,
+ sizeof (struct in6_addr));
+ break;
+#endif /* HAVE_IPV6 */
+ }
+ if (ret == 0)
+ return 1;
+ else
+ return 0;
+}
+
+/* After TCP connection is established. Get local address and port. */
+union sockunion *
+sockunion_getsockname (int fd)
+{
+ int ret;
+ int len;
+ union
+ {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 sin6;
+#endif /* HAVE_IPV6 */
+ char tmp_buffer[128];
+ } name;
+ union sockunion *su;
+
+ memset (&name, 0, sizeof name);
+ len = sizeof name;
+
+ ret = getsockname (fd, (struct sockaddr *)&name, &len);
+ if (ret < 0)
+ {
+ zlog_warn ("Can't get local address and port by getsockname: %s",
+ strerror (errno));
+ return NULL;
+ }
+
+ if (name.sa.sa_family == AF_INET)
+ {
+ su = XCALLOC (MTYPE_TMP, sizeof (union sockunion));
+ memcpy (su, &name, sizeof (struct sockaddr_in));
+ return su;
+ }
+#ifdef HAVE_IPV6
+ if (name.sa.sa_family == AF_INET6)
+ {
+ su = XCALLOC (MTYPE_TMP, sizeof (union sockunion));
+ memcpy (su, &name, sizeof (struct sockaddr_in6));
+
+ if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr))
+ {
+ struct sockaddr_in sin;
+
+ sin.sin_family = AF_INET;
+ memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4);
+ sin.sin_port = su->sin6.sin6_port;
+ memcpy (su, &sin, sizeof (struct sockaddr_in));
+ }
+ return su;
+ }
+#endif /* HAVE_IPV6 */
+ return NULL;
+}
+
+/* After TCP connection is established. Get remote address and port. */
+union sockunion *
+sockunion_getpeername (int fd)
+{
+ int ret;
+ int len;
+ union
+ {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 sin6;
+#endif /* HAVE_IPV6 */
+ char tmp_buffer[128];
+ } name;
+ union sockunion *su;
+
+ memset (&name, 0, sizeof name);
+ len = sizeof name;
+ ret = getpeername (fd, (struct sockaddr *)&name, &len);
+ if (ret < 0)
+ {
+ zlog (NULL, LOG_WARNING, "Can't get remote address and port: %s",
+ strerror (errno));
+ return NULL;
+ }
+
+ if (name.sa.sa_family == AF_INET)
+ {
+ su = XCALLOC (MTYPE_TMP, sizeof (union sockunion));
+ memcpy (su, &name, sizeof (struct sockaddr_in));
+ return su;
+ }
+#ifdef HAVE_IPV6
+ if (name.sa.sa_family == AF_INET6)
+ {
+ su = XCALLOC (MTYPE_TMP, sizeof (union sockunion));
+ memcpy (su, &name, sizeof (struct sockaddr_in6));
+
+ if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr))
+ {
+ struct sockaddr_in sin;
+
+ sin.sin_family = AF_INET;
+ memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4);
+ sin.sin_port = su->sin6.sin6_port;
+ memcpy (su, &sin, sizeof (struct sockaddr_in));
+ }
+ return su;
+ }
+#endif /* HAVE_IPV6 */
+ return NULL;
+}
+
+/* Print sockunion structure */
+void
+sockunion_print (union sockunion *su)
+{
+ if (su == NULL)
+ return;
+
+ switch (su->sa.sa_family)
+ {
+ case AF_INET:
+ printf ("%s\n", inet_ntoa (su->sin.sin_addr));
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ {
+ char buf [64];
+
+ printf ("%s\n", inet_ntop (AF_INET6, &(su->sin6.sin6_addr),
+ buf, sizeof (buf)));
+ }
+ break;
+#endif /* HAVE_IPV6 */
+
+#ifdef AF_LINK
+ case AF_LINK:
+ {
+ struct sockaddr_dl *sdl;
+
+ sdl = (struct sockaddr_dl *)&(su->sa);
+ printf ("link#%d\n", sdl->sdl_index);
+ }
+ break;
+#endif /* AF_LINK */
+ default:
+ printf ("af_unknown %d\n", su->sa.sa_family);
+ break;
+ }
+}
+
+#ifdef HAVE_IPV6
+int
+in6addr_cmp (struct in6_addr *addr1, struct in6_addr *addr2)
+{
+ int i;
+ u_char *p1, *p2;
+
+ p1 = (u_char *)addr1;
+ p2 = (u_char *)addr2;
+
+ for (i = 0; i < sizeof (struct in6_addr); i++)
+ {
+ if (p1[i] > p2[i])
+ return 1;
+ else if (p1[i] < p2[i])
+ return -1;
+ }
+ return 0;
+}
+#endif /* HAVE_IPV6 */
+
+int
+sockunion_cmp (union sockunion *su1, union sockunion *su2)
+{
+ if (su1->sa.sa_family > su2->sa.sa_family)
+ return 1;
+ if (su1->sa.sa_family < su2->sa.sa_family)
+ return -1;
+
+ if (su1->sa.sa_family == AF_INET)
+ {
+ if (ntohl (su1->sin.sin_addr.s_addr) == ntohl (su2->sin.sin_addr.s_addr))
+ return 0;
+ if (ntohl (su1->sin.sin_addr.s_addr) > ntohl (su2->sin.sin_addr.s_addr))
+ return 1;
+ else
+ return -1;
+ }
+#ifdef HAVE_IPV6
+ if (su1->sa.sa_family == AF_INET6)
+ return in6addr_cmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr);
+#endif /* HAVE_IPV6 */
+ return 0;
+}
+
+/* Duplicate sockunion. */
+union sockunion *
+sockunion_dup (union sockunion *su)
+{
+ union sockunion *dup = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
+ memcpy (dup, su, sizeof (union sockunion));
+ return dup;
+}
+
+void
+sockunion_free (union sockunion *su)
+{
+ XFREE (MTYPE_SOCKUNION, su);
+}
diff --git a/lib/sockunion.h b/lib/sockunion.h
new file mode 100644
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 <zebra.h>
+
+#include "str.h"
+
+#ifndef HAVE_SNPRINTF
+/*
+ * snprint() is a real basic wrapper around the standard sprintf()
+ * without any bounds checking
+ */
+int
+snprintf(char *str, size_t size, const char *format, ...)
+{
+ va_list args;
+
+ va_start (args, format);
+
+ return vsprintf (str, format, args);
+}
+#endif
+
+#ifndef HAVE_STRLCPY
+/*
+ * strlcpy is a safer version of strncpy(), checking the total
+ * size of the buffer
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t size)
+{
+ strncpy(dst, src, size);
+
+ return (strlen(dst));
+}
+#endif
+
+#ifndef HAVE_STRLCAT
+/*
+ * strlcat is a safer version of strncat(), checking the total
+ * size of the buffer
+ */
+size_t
+strlcat(char *dst, const char *src, size_t size)
+{
+ /* strncpy(dst, src, size - strlen(dst)); */
+
+ /* I've just added below code only for workable under Linux. So
+ need rewrite -- Kunihiro. */
+ if (strlen (dst) + strlen (src) >= size)
+ return -1;
+
+ strcat (dst, src);
+
+ return (strlen(dst));
+}
+#endif
diff --git a/lib/str.h b/lib/str.h
new file mode 100644
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 <zebra.h>
+
+#include "stream.h"
+#include "memory.h"
+#include "network.h"
+#include "prefix.h"
+
+
+/*A macro to check pointers in order to not
+ go behind the allocated mem block
+ S -- stream reference
+ Z -- size of data to be written
+*/
+
+#define CHECK_SIZE(S, Z) \
+ if (((S)->putp + (Z)) > (S)->size) \
+ (Z) = (S)->size - (S)->putp;
+
+/* Stream is fixed length buffer for network output/input. */
+
+/* Make stream buffer. */
+struct stream *
+stream_new (size_t size)
+{
+ struct stream *s;
+
+ s = XCALLOC (MTYPE_STREAM, sizeof (struct stream));
+
+ s->data = XCALLOC (MTYPE_STREAM_DATA, size);
+ s->size = size;
+ return s;
+}
+
+/* Free it now. */
+void
+stream_free (struct stream *s)
+{
+ XFREE (MTYPE_STREAM_DATA, s->data);
+ XFREE (MTYPE_STREAM, s);
+}
+
+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 <zebra.h>
+
+#include "prefix.h"
+#include "table.h"
+#include "memory.h"
+#include "sockunion.h"
+
+void route_node_delete (struct route_node *);
+void route_table_free (struct route_table *);
+
+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 <zebra.h>
+
+#include "command.h"
+#include "prefix.h"
+
+#define FILTER_TYPE_IP 1
+#define FILTER_TYPE_TCP 2
+#define FILTER_TYPE_UDP 3
+
+DEFUN (al_tcp_filter,
+ al_tcp_filter_cmd,
+ "access-list WORD (deny|permit) tcp (A.B.C.D/M|any) (A.B.C.D/M|any)",
+ "Add an access list entry\n"
+ "Access-list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Transmission Control Protocol\n"
+ "Source address prefix\n"
+ "Any source host\n"
+ "Destination address prefix\n"
+ "Any destination host\n")
+{
+ return CMD_SUCCESS;
+}
+
+DEFUN (al_tcp_filter_eq,
+ al_tcp_filter_eq_cmd,
+ "access-list WORD (deny|permit) tcp (A.B.C.D/M|any) (A.B.C.D/M|any) eq <0-65535>",
+ "Add an access list entry\n"
+ "Access-list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Transmission Control Protocol\n"
+ "Source address prefix\n"
+ "Any source host\n"
+ "Destination address prefix\n"
+ "Any destination host\n"
+ "Port number\n")
+{
+ return CMD_SUCCESS;
+}
+
+void
+tcpfilter_init ()
+{
+ install_element (CONFIG_NODE, &al_tcp_filter_cmd);
+ install_element (CONFIG_NODE, &al_tcp_filter_eq_cmd);
+}
diff --git a/lib/tcpfilter.h b/lib/tcpfilter.h
new file mode 100644
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 <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+/* #define DEBUG */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "log.h"
+
+/* Struct timeval's tv_usec one second value. */
+#define TIMER_SECOND_MICRO 1000000L
+
+struct timeval
+timeval_adjust (struct timeval a)
+{
+ while (a.tv_usec >= TIMER_SECOND_MICRO)
+ {
+ a.tv_usec -= TIMER_SECOND_MICRO;
+ a.tv_sec++;
+ }
+
+ while (a.tv_usec < 0)
+ {
+ a.tv_usec += TIMER_SECOND_MICRO;
+ a.tv_sec--;
+ }
+
+ if (a.tv_sec < 0)
+ {
+ a.tv_sec = 0;
+ a.tv_usec = 10;
+ }
+
+ if (a.tv_sec > TIMER_SECOND_MICRO)
+ a.tv_sec = TIMER_SECOND_MICRO;
+
+ return a;
+}
+
+static struct timeval
+timeval_subtract (struct timeval a, struct timeval b)
+{
+ struct timeval ret;
+
+ ret.tv_usec = a.tv_usec - b.tv_usec;
+ ret.tv_sec = a.tv_sec - b.tv_sec;
+
+ return timeval_adjust (ret);
+}
+
+static int
+timeval_cmp (struct timeval a, struct timeval b)
+{
+ return (a.tv_sec == b.tv_sec
+ ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
+}
+
+static unsigned long
+timeval_elapsed (struct timeval a, struct timeval b)
+{
+ return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
+ + (a.tv_usec - b.tv_usec));
+}
+
+/* List allocation and head/tail print out. */
+static void
+thread_list_debug (struct thread_list *list)
+{
+ printf ("count [%d] head [%p] tail [%p]\n",
+ list->count, list->head, list->tail);
+}
+
+/* Debug print for thread_master. */
+void
+thread_master_debug (struct thread_master *m)
+{
+ printf ("-----------\n");
+ printf ("readlist : ");
+ thread_list_debug (&m->read);
+ printf ("writelist : ");
+ thread_list_debug (&m->write);
+ printf ("timerlist : ");
+ thread_list_debug (&m->timer);
+ printf ("eventlist : ");
+ thread_list_debug (&m->event);
+ printf ("unuselist : ");
+ thread_list_debug (&m->unuse);
+ printf ("total alloc: [%ld]\n", m->alloc);
+ printf ("-----------\n");
+}
+
+/* Allocate new thread master. */
+struct thread_master *
+thread_master_create ()
+{
+ return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER,
+ sizeof (struct thread_master));
+}
+
+/* Add a new thread to the list. */
+static void
+thread_list_add (struct thread_list *list, struct thread *thread)
+{
+ thread->next = NULL;
+ thread->prev = list->tail;
+ if (list->tail)
+ list->tail->next = thread;
+ else
+ list->head = thread;
+ list->tail = thread;
+ list->count++;
+}
+
+/* Add a new thread just before the point. */
+static void
+thread_list_add_before (struct thread_list *list,
+ struct thread *point,
+ struct thread *thread)
+{
+ thread->next = point;
+ thread->prev = point->prev;
+ if (point->prev)
+ point->prev->next = thread;
+ else
+ list->head = thread;
+ point->prev = thread;
+ list->count++;
+}
+
+/* Delete a thread from the list. */
+static struct thread *
+thread_list_delete (struct thread_list *list, struct thread *thread)
+{
+ if (thread->next)
+ thread->next->prev = thread->prev;
+ else
+ list->tail = thread->prev;
+ if (thread->prev)
+ thread->prev->next = thread->next;
+ else
+ list->head = thread->next;
+ thread->next = thread->prev = NULL;
+ list->count--;
+ return thread;
+}
+
+/* Move thread to unuse list. */
+static void
+thread_add_unuse (struct thread_master *m, struct thread *thread)
+{
+ assert (m != NULL);
+ assert (thread->next == NULL);
+ assert (thread->prev == NULL);
+ assert (thread->type == THREAD_UNUSED);
+ thread_list_add (&m->unuse, thread);
+}
+
+/* Free all unused thread. */
+static void
+thread_list_free (struct thread_master *m, struct thread_list *list)
+{
+ struct thread *t;
+ struct thread *next;
+
+ for (t = list->head; t; t = next)
+ {
+ next = t->next;
+ XFREE (MTYPE_THREAD, t);
+ list->count--;
+ m->alloc--;
+ }
+}
+
+/* Stop thread scheduler. */
+void
+thread_master_free (struct thread_master *m)
+{
+ thread_list_free (m, &m->read);
+ thread_list_free (m, &m->write);
+ thread_list_free (m, &m->timer);
+ thread_list_free (m, &m->event);
+ thread_list_free (m, &m->ready);
+ thread_list_free (m, &m->unuse);
+
+ XFREE (MTYPE_THREAD_MASTER, m);
+}
+
+/* Delete top of the list and return it. */
+static struct thread *
+thread_trim_head (struct thread_list *list)
+{
+ if (list->head)
+ return thread_list_delete (list, list->head);
+ return NULL;
+}
+
+/* Thread list is empty or not. */
+int
+thread_empty (struct thread_list *list)
+{
+ return list->head ? 0 : 1;
+}
+
+/* Return remain time in second. */
+unsigned long
+thread_timer_remain_second (struct thread *thread)
+{
+ struct timeval timer_now;
+
+ gettimeofday (&timer_now, NULL);
+
+ if (thread->u.sands.tv_sec - timer_now.tv_sec > 0)
+ return thread->u.sands.tv_sec - timer_now.tv_sec;
+ else
+ return 0;
+}
+
+/* Get new thread. */
+static struct thread *
+thread_get (struct thread_master *m, u_char type,
+ int (*func) (struct thread *), void *arg)
+{
+ struct thread *thread;
+
+ if (m->unuse.head)
+ thread = thread_trim_head (&m->unuse);
+ else
+ {
+ thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
+ m->alloc++;
+ }
+ thread->type = type;
+ thread->master = m;
+ thread->func = func;
+ thread->arg = arg;
+
+ return thread;
+}
+
+/* Add new read thread. */
+struct thread *
+thread_add_read (struct thread_master *m,
+ int (*func) (struct thread *), void *arg, int fd)
+{
+ struct thread *thread;
+
+ assert (m != NULL);
+
+ if (FD_ISSET (fd, &m->readfd))
+ {
+ zlog (NULL, LOG_WARNING, "There is already read fd [%d]", fd);
+ return NULL;
+ }
+
+ thread = thread_get (m, THREAD_READ, func, arg);
+ FD_SET (fd, &m->readfd);
+ thread->u.fd = fd;
+ thread_list_add (&m->read, thread);
+
+ return thread;
+}
+
+/* Add new write thread. */
+struct thread *
+thread_add_write (struct thread_master *m,
+ int (*func) (struct thread *), void *arg, int fd)
+{
+ struct thread *thread;
+
+ assert (m != NULL);
+
+ if (FD_ISSET (fd, &m->writefd))
+ {
+ zlog (NULL, LOG_WARNING, "There is already write fd [%d]", fd);
+ return NULL;
+ }
+
+ thread = thread_get (m, THREAD_WRITE, func, arg);
+ FD_SET (fd, &m->writefd);
+ thread->u.fd = fd;
+ thread_list_add (&m->write, thread);
+
+ return thread;
+}
+
+/* Add timer event thread. */
+struct thread *
+thread_add_timer (struct thread_master *m,
+ int (*func) (struct thread *), void *arg, long timer)
+{
+ struct timeval timer_now;
+ struct thread *thread;
+#ifndef TIMER_NO_SORT
+ struct thread *tt;
+#endif /* TIMER_NO_SORT */
+
+ assert (m != NULL);
+
+ thread = thread_get (m, THREAD_TIMER, func, arg);
+
+ /* Do we need jitter here? */
+ gettimeofday (&timer_now, NULL);
+ timer_now.tv_sec += timer;
+ thread->u.sands = timer_now;
+
+ /* Sort by timeval. */
+#ifdef TIMER_NO_SORT
+ thread_list_add (&m->timer, thread);
+#else
+ for (tt = m->timer.head; tt; tt = tt->next)
+ if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0)
+ break;
+
+ if (tt)
+ thread_list_add_before (&m->timer, tt, thread);
+ else
+ thread_list_add (&m->timer, thread);
+#endif /* TIMER_NO_SORT */
+
+ return thread;
+}
+
+/* Add 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 <zebra.h>
+
+#include "vector.h"
+#include "memory.h"
+
+/* Initialize vector : allocate memory and return vector. */
+vector
+vector_init (unsigned int size)
+{
+ vector v = XCALLOC (MTYPE_VECTOR, sizeof (struct _vector));
+
+ /* allocate at least one slot */
+ if (size == 0)
+ size = 1;
+
+ v->alloced = size;
+ v->max = 0;
+ v->index = XCALLOC (MTYPE_VECTOR_INDEX, sizeof (void *) * size);
+ return v;
+}
+
+void
+vector_only_wrapper_free (vector v)
+{
+ XFREE (MTYPE_VECTOR, v);
+}
+
+void
+vector_only_index_free (void *index)
+{
+ XFREE (MTYPE_VECTOR_INDEX, index);
+}
+
+void
+vector_free (vector v)
+{
+ XFREE (MTYPE_VECTOR_INDEX, v->index);
+ XFREE (MTYPE_VECTOR, v);
+}
+
+vector
+vector_copy (vector v)
+{
+ unsigned int size;
+ vector new = XCALLOC (MTYPE_VECTOR, sizeof (struct _vector));
+
+ new->max = v->max;
+ new->alloced = v->alloced;
+
+ size = sizeof (void *) * (v->alloced);
+ new->index = XCALLOC (MTYPE_VECTOR_INDEX, size);
+ memcpy (new->index, v->index, size);
+
+ return new;
+}
+
+/* Check assigned index, and if it runs short double index pointer */
+void
+vector_ensure (vector v, unsigned int num)
+{
+ if (v->alloced > num)
+ return;
+
+ v->index = XREALLOC (MTYPE_VECTOR_INDEX,
+ v->index, sizeof (void *) * (v->alloced * 2));
+ memset (&v->index[v->alloced], 0, sizeof (void *) * v->alloced);
+ v->alloced *= 2;
+
+ if (v->alloced <= num)
+ vector_ensure (v, num);
+}
+
+/* This function only returns next empty slot index. It dose not mean
+ the slot's index memory is assigned, please call vector_ensure()
+ after calling this function. */
+int
+vector_empty_slot (vector v)
+{
+ unsigned int i;
+
+ if (v->max == 0)
+ return 0;
+
+ for (i = 0; i < v->max; i++)
+ if (v->index[i] == 0)
+ return i;
+
+ return i;
+}
+
+/* Set value to the smallest empty slot. */
+int
+vector_set (vector v, void *val)
+{
+ unsigned int i;
+
+ i = vector_empty_slot (v);
+ vector_ensure (v, i);
+
+ v->index[i] = val;
+
+ if (v->max <= i)
+ v->max = i + 1;
+
+ return i;
+}
+
+/* Set value to specified index slot. */
+int
+vector_set_index (vector v, unsigned int i, void *val)
+{
+ vector_ensure (v, i);
+
+ v->index[i] = val;
+
+ if (v->max <= i)
+ v->max = i + 1;
+
+ return i;
+}
+
+/* Look up vector. */
+void *
+vector_lookup (vector v, unsigned int i)
+{
+ if (i >= v->max)
+ return NULL;
+ return v->index[i];
+}
+
+/* Lookup vector, ensure it. */
+void *
+vector_lookup_ensure (vector v, unsigned int i)
+{
+ vector_ensure (v, i);
+ return v->index[i];
+}
+
+/* Unset value at specified index slot. */
+void
+vector_unset (vector v, unsigned int i)
+{
+ if (i >= v->alloced)
+ return;
+
+ v->index[i] = NULL;
+
+ if (i + 1 == v->max)
+ {
+ v->max--;
+ while (i && v->index[--i] == NULL && v->max--)
+ ; /* Is this ugly ? */
+ }
+}
+
+/* Count the number of not emplty slot. */
+unsigned int
+vector_count (vector v)
+{
+ unsigned int i;
+ unsigned count = 0;
+
+ for (i = 0; i < v->max; i++)
+ if (v->index[i] != NULL)
+ count++;
+
+ return count;
+}
diff --git a/lib/vector.h b/lib/vector.h
new file mode 100644
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 <zebra.h>
+
+#include "linklist.h"
+#include "buffer.h"
+#include "version.h"
+#include "command.h"
+#include "sockunion.h"
+#include "thread.h"
+#include "memory.h"
+#include "str.h"
+#include "log.h"
+#include "prefix.h"
+#include "filter.h"
+
+/* Vty events */
+enum event
+{
+ VTY_SERV,
+ VTY_READ,
+ VTY_WRITE,
+ VTY_TIMEOUT_RESET,
+#ifdef VTYSH
+ VTYSH_SERV,
+ VTYSH_READ
+#endif /* VTYSH */
+};
+
+static void vty_event (enum event, int, struct vty *);
+
+/* Extern host structure from command.c */
+extern struct host host;
+
+/* Vector which store each vty structure. */
+static vector vtyvec;
+
+/* Vty timeout value. */
+static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT;
+
+/* Vty access-class command */
+static char *vty_accesslist_name = NULL;
+
+/* Vty access-calss for IPv6. */
+static char *vty_ipv6_accesslist_name = NULL;
+
+/* VTY server thread. */
+vector Vvty_serv_thread;
+
+/* Current directory. */
+char *vty_cwd = NULL;
+
+/* Configure lock. */
+static int vty_config;
+
+/* Login password check. */
+static int no_password_check = 0;
+
+/* Integrated configuration file path */
+char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
+
+
+/* VTY standard output function. */
+int
+vty_out (struct vty *vty, const char *format, ...)
+{
+ va_list args;
+ int len = 0;
+ int size = 1024;
+ char buf[1024];
+ char *p = NULL;
+
+ va_start (args, format);
+
+ if (vty_shell (vty))
+ vprintf (format, args);
+ else
+ {
+ /* Try to write to initial buffer. */
+ len = vsnprintf (buf, sizeof buf, format, args);
+
+ /* Initial buffer is not enough. */
+ if (len < 0 || len >= size)
+ {
+ while (1)
+ {
+ if (len > -1)
+ size = len + 1;
+ else
+ size = size * 2;
+
+ p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size);
+ if (! p)
+ return -1;
+
+ len = vsnprintf (p, size, format, args);
+
+ if (len > -1 && len < size)
+ break;
+ }
+ }
+
+ /* When initial buffer is enough to store all output. */
+ if (! p)
+ p = buf;
+
+ /* Pointer p must point out buffer. */
+ if (vty_shell_serv (vty))
+ write (vty->fd, (u_char *) p, len);
+ else
+ buffer_write (vty->obuf, (u_char *) p, len);
+
+ /* If p is not different with buf, it is allocated buffer. */
+ if (p != buf)
+ XFREE (MTYPE_VTY_OUT_BUF, p);
+ }
+
+ va_end (args);
+
+ return len;
+}
+
+int
+vty_log_out (struct vty *vty, const char *proto_str, const char *format,
+ va_list va)
+{
+ int len;
+ char buf[1024];
+
+ snprintf (buf, sizeof buf, "%s: ", proto_str);
+ write (vty->fd, buf, strlen (proto_str) + 2);
+
+ len = vsnprintf (buf, sizeof buf, format, va);
+ if (len < 0)
+ return -1;
+ write (vty->fd, (u_char *)buf, len);
+
+ snprintf (buf, sizeof buf, "\r\n");
+ write (vty->fd, buf, 2);
+
+ return len;
+}
+
+/* Output current time to the vty. */
+void
+vty_time_print (struct vty *vty, int cr)
+{
+ time_t clock;
+ struct tm *tm;
+#define TIME_BUF 25
+ char buf [TIME_BUF];
+ int ret;
+
+ time (&clock);
+ tm = localtime (&clock);
+
+ ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm);
+ if (ret == 0)
+ {
+ zlog (NULL, LOG_INFO, "strftime error");
+ return;
+ }
+ if (cr)
+ vty_out (vty, "%s\n", buf);
+ else
+ vty_out (vty, "%s ", buf);
+
+ return;
+}
+
+/* Say hello to vty interface. */
+void
+vty_hello (struct vty *vty)
+{
+ if (host.motd)
+ vty_out (vty, host.motd);
+}
+
+/* Put out prompt and wait input from user. */
+static void
+vty_prompt (struct vty *vty)
+{
+ struct utsname names;
+ const char*hostname;
+
+ if (vty->type == VTY_TERM)
+ {
+ hostname = host.name;
+ if (!hostname)
+ {
+ uname (&names);
+ hostname = names.nodename;
+ }
+ vty_out (vty, cmd_prompt (vty->node), hostname);
+ }
+}
+
+/* Send WILL TELOPT_ECHO to remote server. */
+void
+vty_will_echo (struct vty *vty)
+{
+ char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
+ vty_out (vty, "%s", cmd);
+}
+
+/* Make suppress Go-Ahead telnet option. */
+static void
+vty_will_suppress_go_ahead (struct vty *vty)
+{
+ char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
+ vty_out (vty, "%s", cmd);
+}
+
+/* Make don't use linemode over telnet. */
+static void
+vty_dont_linemode (struct vty *vty)
+{
+ char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
+ vty_out (vty, "%s", cmd);
+}
+
+/* Use window size. */
+static void
+vty_do_window_size (struct vty *vty)
+{
+ char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
+ vty_out (vty, "%s", cmd);
+}
+
+#if 0 /* Currently not used. */
+/* Make don't use lflow vty interface. */
+static void
+vty_dont_lflow_ahead (struct vty *vty)
+{
+ char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' };
+ vty_out (vty, "%s", cmd);
+}
+#endif /* 0 */
+
+/* Allocate new vty struct. */
+struct vty *
+vty_new ()
+{
+ struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty));
+
+ new->obuf = (struct buffer *) buffer_new (100);
+ new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
+ new->max = VTY_BUFSIZ;
+ new->sb_buffer = NULL;
+
+ return new;
+}
+
+/* Authentication of vty */
+static void
+vty_auth (struct vty *vty, char *buf)
+{
+ char *passwd = NULL;
+ enum node_type next_node = 0;
+ int fail;
+ char *crypt (const char *, const char *);
+
+ switch (vty->node)
+ {
+ case AUTH_NODE:
+ if (host.encrypt)
+ passwd = host.password_encrypt;
+ else
+ passwd = host.password;
+ if (host.advanced)
+ next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
+ else
+ next_node = VIEW_NODE;
+ break;
+ case AUTH_ENABLE_NODE:
+ if (host.encrypt)
+ passwd = host.enable_encrypt;
+ else
+ passwd = host.enable;
+ next_node = ENABLE_NODE;
+ break;
+ }
+
+ if (passwd)
+ {
+ if (host.encrypt)
+ fail = strcmp (crypt(buf, passwd), passwd);
+ else
+ fail = strcmp (buf, passwd);
+ }
+ else
+ fail = 1;
+
+ if (! fail)
+ {
+ vty->fail = 0;
+ vty->node = next_node; /* Success ! */
+ }
+ else
+ {
+ vty->fail++;
+ if (vty->fail >= 3)
+ {
+ if (vty->node == AUTH_NODE)
+ {
+ vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
+ vty->status = VTY_CLOSE;
+ }
+ else
+ {
+ /* AUTH_ENABLE_NODE */
+ vty->fail = 0;
+ vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
+ vty->node = VIEW_NODE;
+ }
+ }
+ }
+}
+
+/* Command execution over the vty interface. */
+int
+vty_command (struct vty *vty, char *buf)
+{
+ int ret;
+ vector vline;
+
+ /* Split readline string up into the vector */
+ vline = cmd_make_strvec (buf);
+
+ if (vline == NULL)
+ return CMD_SUCCESS;
+
+ ret = cmd_execute_command (vline, vty, NULL);
+
+ if (ret != CMD_SUCCESS)
+ switch (ret)
+ {
+ case CMD_WARNING:
+ if (vty->type == VTY_FILE)
+ vty_out (vty, "Warning...%s", VTY_NEWLINE);
+ break;
+ case CMD_ERR_AMBIGUOUS:
+ vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
+ break;
+ case CMD_ERR_NO_MATCH:
+ vty_out (vty, "%% Unknown command.%s", VTY_NEWLINE);
+ break;
+ case CMD_ERR_INCOMPLETE:
+ vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
+ break;
+ }
+ cmd_free_strvec (vline);
+
+ return ret;
+}
+
+char telnet_backward_char = 0x08;
+char telnet_space_char = ' ';
+
+/* Basic function to write buffer to vty. */
+static void
+vty_write (struct vty *vty, char *buf, size_t nbytes)
+{
+ if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
+ return;
+
+ /* Should we do buffering here ? And make vty_flush (vty) ? */
+ buffer_write (vty->obuf, (u_char *)buf, nbytes);
+}
+
+/* Ensure length of input buffer. Is buffer is short, double it. */
+static void
+vty_ensure (struct vty *vty, int length)
+{
+ if (vty->max <= length)
+ {
+ vty->max *= 2;
+ vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max);
+ }
+}
+
+/* Basic function to insert character into vty. */
+static void
+vty_self_insert (struct vty *vty, char c)
+{
+ int i;
+ int length;
+
+ vty_ensure (vty, vty->length + 1);
+ length = vty->length - vty->cp;
+ memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
+ vty->buf[vty->cp] = c;
+
+ vty_write (vty, &vty->buf[vty->cp], length + 1);
+ for (i = 0; i < length; i++)
+ vty_write (vty, &telnet_backward_char, 1);
+
+ vty->cp++;
+ vty->length++;
+}
+
+/* Self insert character 'c' in overwrite mode. */
+static void
+vty_self_insert_overwrite (struct vty *vty, char c)
+{
+ vty_ensure (vty, vty->length + 1);
+ vty->buf[vty->cp++] = c;
+
+ if (vty->cp > vty->length)
+ vty->length++;
+
+ if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
+ return;
+
+ vty_write (vty, &c, 1);
+}
+
+/* Insert a word into vty interface with overwrite mode. */
+static void
+vty_insert_word_overwrite (struct vty *vty, char *str)
+{
+ int len = strlen (str);
+ vty_write (vty, str, len);
+ strcpy (&vty->buf[vty->cp], str);
+ vty->cp += len;
+ vty->length = vty->cp;
+}
+
+/* Forward character. */
+static void
+vty_forward_char (struct vty *vty)
+{
+ if (vty->cp < vty->length)
+ {
+ vty_write (vty, &vty->buf[vty->cp], 1);
+ vty->cp++;
+ }
+}
+
+/* Backward character. */
+static void
+vty_backward_char (struct vty *vty)
+{
+ if (vty->cp > 0)
+ {
+ vty->cp--;
+ vty_write (vty, &telnet_backward_char, 1);
+ }
+}
+
+/* Move to the beginning of the line. */
+static void
+vty_beginning_of_line (struct vty *vty)
+{
+ while (vty->cp)
+ vty_backward_char (vty);
+}
+
+/* Move to the end of the line. */
+static void
+vty_end_of_line (struct vty *vty)
+{
+ while (vty->cp < vty->length)
+ vty_forward_char (vty);
+}
+
+static void vty_kill_line_from_beginning (struct vty *);
+static void vty_redraw_line (struct vty *);
+
+/* Print command line history. This function is called from
+ vty_next_line and vty_previous_line. */
+static void
+vty_history_print (struct vty *vty)
+{
+ int length;
+
+ vty_kill_line_from_beginning (vty);
+
+ /* Get previous line from history buffer */
+ length = strlen (vty->hist[vty->hp]);
+ memcpy (vty->buf, vty->hist[vty->hp], length);
+ vty->cp = vty->length = length;
+
+ /* Redraw current line */
+ vty_redraw_line (vty);
+}
+
+/* Show next command line history. */
+void
+vty_next_line (struct vty *vty)
+{
+ int try_index;
+
+ if (vty->hp == vty->hindex)
+ return;
+
+ /* Try is there history exist or not. */
+ try_index = vty->hp;
+ if (try_index == (VTY_MAXHIST - 1))
+ try_index = 0;
+ else
+ try_index++;
+
+ /* If there is not history return. */
+ if (vty->hist[try_index] == NULL)
+ return;
+ else
+ vty->hp = try_index;
+
+ vty_history_print (vty);
+}
+
+/* Show previous command line history. */
+void
+vty_previous_line (struct vty *vty)
+{
+ int try_index;
+
+ try_index = vty->hp;
+ if (try_index == 0)
+ try_index = VTY_MAXHIST - 1;
+ else
+ try_index--;
+
+ if (vty->hist[try_index] == NULL)
+ return;
+ else
+ vty->hp = try_index;
+
+ vty_history_print (vty);
+}
+
+/* This function redraw all of the command line character. */
+static void
+vty_redraw_line (struct vty *vty)
+{
+ vty_write (vty, vty->buf, vty->length);
+ vty->cp = vty->length;
+}
+
+/* Forward word. */
+static void
+vty_forward_word (struct vty *vty)
+{
+ while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
+ vty_forward_char (vty);
+
+ while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
+ vty_forward_char (vty);
+}
+
+/* Backward word without skipping training space. */
+static void
+vty_backward_pure_word (struct vty *vty)
+{
+ while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
+ vty_backward_char (vty);
+}
+
+/* Backward word. */
+static void
+vty_backward_word (struct vty *vty)
+{
+ while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
+ vty_backward_char (vty);
+
+ while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
+ vty_backward_char (vty);
+}
+
+/* When '^D' is typed at the beginning of the line we move to the down
+ level. */
+static void
+vty_down_level (struct vty *vty)
+{
+ vty_out (vty, "%s", VTY_NEWLINE);
+ config_exit (NULL, vty, 0, NULL);
+ vty_prompt (vty);
+ vty->cp = 0;
+}
+
+/* When '^Z' is received from vty, move down to the enable mode. */
+void
+vty_end_config (struct vty *vty)
+{
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ switch (vty->node)
+ {
+ case VIEW_NODE:
+ case ENABLE_NODE:
+ /* Nothing to do. */
+ break;
+ case CONFIG_NODE:
+ case INTERFACE_NODE:
+ case ZEBRA_NODE:
+ case RIP_NODE:
+ case RIPNG_NODE:
+ case BGP_NODE:
+ case BGP_VPNV4_NODE:
+ case BGP_IPV4_NODE:
+ case BGP_IPV4M_NODE:
+ case BGP_IPV6_NODE:
+ case RMAP_NODE:
+ case OSPF_NODE:
+ case OSPF6_NODE:
+ case KEYCHAIN_NODE:
+ case KEYCHAIN_KEY_NODE:
+ case MASC_NODE:
+ case VTY_NODE:
+ vty_config_unlock (vty);
+ vty->node = ENABLE_NODE;
+ break;
+ default:
+ /* Unknown node, we have to ignore it. */
+ break;
+ }
+
+ vty_prompt (vty);
+ vty->cp = 0;
+}
+
+/* Delete a charcter at the current point. */
+static void
+vty_delete_char (struct vty *vty)
+{
+ int i;
+ int size;
+
+ if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
+ return;
+
+ if (vty->length == 0)
+ {
+ vty_down_level (vty);
+ return;
+ }
+
+ if (vty->cp == vty->length)
+ return; /* completion need here? */
+
+ size = vty->length - vty->cp;
+
+ vty->length--;
+ memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
+ vty->buf[vty->length] = '\0';
+
+ vty_write (vty, &vty->buf[vty->cp], size - 1);
+ vty_write (vty, &telnet_space_char, 1);
+
+ for (i = 0; i < size; i++)
+ vty_write (vty, &telnet_backward_char, 1);
+}
+
+/* Delete a character before the point. */
+static void
+vty_delete_backward_char (struct vty *vty)
+{
+ if (vty->cp == 0)
+ return;
+
+ vty_backward_char (vty);
+ vty_delete_char (vty);
+}
+
+/* Kill rest of line from current point. */
+static void
+vty_kill_line (struct vty *vty)
+{
+ int i;
+ int size;
+
+ size = vty->length - vty->cp;
+
+ if (size == 0)
+ return;
+
+ for (i = 0; i < size; i++)
+ vty_write (vty, &telnet_space_char, 1);
+ for (i = 0; i < size; i++)
+ vty_write (vty, &telnet_backward_char, 1);
+
+ memset (&vty->buf[vty->cp], 0, size);
+ vty->length = vty->cp;
+}
+
+/* Kill line from the beginning. */
+static void
+vty_kill_line_from_beginning (struct vty *vty)
+{
+ vty_beginning_of_line (vty);
+ vty_kill_line (vty);
+}
+
+/* Delete a word before the point. */
+static void
+vty_forward_kill_word (struct vty *vty)
+{
+ while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
+ vty_delete_char (vty);
+ while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
+ vty_delete_char (vty);
+}
+
+/* Delete a word before the point. */
+static void
+vty_backward_kill_word (struct vty *vty)
+{
+ while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
+ vty_delete_backward_char (vty);
+ while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
+ vty_delete_backward_char (vty);
+}
+
+/* Transpose chars before or at the point. */
+static void
+vty_transpose_chars (struct vty *vty)
+{
+ char c1, c2;
+
+ /* If length is short or point is near by the beginning of line then
+ return. */
+ if (vty->length < 2 || vty->cp < 1)
+ return;
+
+ /* In case of point is located at the end of the line. */
+ if (vty->cp == vty->length)
+ {
+ c1 = vty->buf[vty->cp - 1];
+ c2 = vty->buf[vty->cp - 2];
+
+ vty_backward_char (vty);
+ vty_backward_char (vty);
+ vty_self_insert_overwrite (vty, c1);
+ vty_self_insert_overwrite (vty, c2);
+ }
+ else
+ {
+ c1 = vty->buf[vty->cp];
+ c2 = vty->buf[vty->cp - 1];
+
+ vty_backward_char (vty);
+ vty_self_insert_overwrite (vty, c1);
+ vty_self_insert_overwrite (vty, c2);
+ }
+}
+
+/* Do completion at vty interface. */
+static void
+vty_complete_command (struct vty *vty)
+{
+ int i;
+ int ret;
+ char **matched = NULL;
+ vector vline;
+
+ if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
+ return;
+
+ vline = cmd_make_strvec (vty->buf);
+ if (vline == NULL)
+ return;
+
+ /* In case of 'help \t'. */
+ if (isspace ((int) vty->buf[vty->length - 1]))
+ vector_set (vline, '\0');
+
+ matched = cmd_complete_command (vline, vty, &ret);
+
+ cmd_free_strvec (vline);
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+ switch (ret)
+ {
+ case CMD_ERR_AMBIGUOUS:
+ vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+ break;
+ case CMD_ERR_NO_MATCH:
+ /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+ break;
+ case CMD_COMPLETE_FULL_MATCH:
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+ vty_backward_pure_word (vty);
+ vty_insert_word_overwrite (vty, matched[0]);
+ vty_self_insert (vty, ' ');
+ XFREE (MTYPE_TMP, matched[0]);
+ break;
+ case CMD_COMPLETE_MATCH:
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+ vty_backward_pure_word (vty);
+ vty_insert_word_overwrite (vty, matched[0]);
+ XFREE (MTYPE_TMP, matched[0]);
+ vector_only_index_free (matched);
+ return;
+ break;
+ case CMD_COMPLETE_LIST_MATCH:
+ for (i = 0; matched[i] != NULL; i++)
+ {
+ if (i != 0 && ((i % 6) == 0))
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "%-10s ", matched[i]);
+ XFREE (MTYPE_TMP, matched[i]);
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+ break;
+ case CMD_ERR_NOTHING_TODO:
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+ break;
+ default:
+ break;
+ }
+ if (matched)
+ vector_only_index_free (matched);
+}
+
+void
+vty_describe_fold (struct vty *vty, int cmd_width,
+ int desc_width, struct desc *desc)
+{
+ char *buf, *cmd, *p;
+ int pos;
+
+ cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
+
+ if (desc_width <= 0)
+ {
+ vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
+ return;
+ }
+
+ buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1);
+
+ for (p = desc->str; strlen (p) > desc_width; p += pos + 1)
+ {
+ for (pos = desc_width; pos > 0; pos--)
+ if (*(p + pos) == ' ')
+ break;
+
+ if (pos == 0)
+ break;
+
+ strncpy (buf, p, pos);
+ buf[pos] = '\0';
+ vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
+
+ cmd = "";
+ }
+
+ vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
+
+ XFREE (MTYPE_TMP, buf);
+}
+
+/* Describe matched command function. */
+static void
+vty_describe_command (struct vty *vty)
+{
+ int ret;
+ vector vline;
+ vector describe;
+ int i, width, desc_width;
+ struct desc *desc, *desc_cr = NULL;
+
+ vline = cmd_make_strvec (vty->buf);
+
+ /* In case of '> ?'. */
+ if (vline == NULL)
+ {
+ vline = vector_init (1);
+ vector_set (vline, '\0');
+ }
+ else
+ if (isspace ((int) vty->buf[vty->length - 1]))
+ vector_set (vline, '\0');
+
+ describe = cmd_describe_command (vline, vty, &ret);
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ /* Ambiguous error. */
+ switch (ret)
+ {
+ case CMD_ERR_AMBIGUOUS:
+ cmd_free_strvec (vline);
+ vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+ return;
+ break;
+ case CMD_ERR_NO_MATCH:
+ cmd_free_strvec (vline);
+ vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+ return;
+ break;
+ }
+
+ /* Get width of command string. */
+ width = 0;
+ for (i = 0; i < vector_max (describe); i++)
+ if ((desc = vector_slot (describe, i)) != NULL)
+ {
+ int len;
+
+ if (desc->cmd[0] == '\0')
+ continue;
+
+ len = strlen (desc->cmd);
+ if (desc->cmd[0] == '.')
+ len--;
+
+ if (width < len)
+ width = len;
+ }
+
+ /* Get width of description string. */
+ desc_width = vty->width - (width + 6);
+
+ /* Print out description. */
+ for (i = 0; i < vector_max (describe); i++)
+ if ((desc = vector_slot (describe, i)) != NULL)
+ {
+ if (desc->cmd[0] == '\0')
+ continue;
+
+ if (strcmp (desc->cmd, "<cr>") == 0)
+ {
+ desc_cr = desc;
+ continue;
+ }
+
+ if (!desc->str)
+ vty_out (vty, " %-s%s",
+ desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+ VTY_NEWLINE);
+ else if (desc_width >= strlen (desc->str))
+ vty_out (vty, " %-*s %s%s", width,
+ desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+ desc->str, VTY_NEWLINE);
+ else
+ vty_describe_fold (vty, width, desc_width, desc);
+
+#if 0
+ vty_out (vty, " %-*s %s%s", width
+ desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+ desc->str ? desc->str : "", VTY_NEWLINE);
+#endif /* 0 */
+ }
+
+ if ((desc = desc_cr))
+ {
+ if (!desc->str)
+ vty_out (vty, " %-s%s",
+ desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+ VTY_NEWLINE);
+ else if (desc_width >= strlen (desc->str))
+ vty_out (vty, " %-*s %s%s", width,
+ desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+ desc->str, VTY_NEWLINE);
+ else
+ vty_describe_fold (vty, width, desc_width, desc);
+ }
+
+ cmd_free_strvec (vline);
+ vector_free (describe);
+
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+}
+
+void
+vty_clear_buf (struct vty *vty)
+{
+ memset (vty->buf, 0, vty->max);
+}
+
+/* ^C stop current input and do not add command line to the history. */
+static void
+vty_stop_input (struct vty *vty)
+{
+ vty->cp = vty->length = 0;
+ vty_clear_buf (vty);
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ switch (vty->node)
+ {
+ case VIEW_NODE:
+ case ENABLE_NODE:
+ /* Nothing to do. */
+ break;
+ case CONFIG_NODE:
+ case INTERFACE_NODE:
+ case ZEBRA_NODE:
+ case RIP_NODE:
+ case RIPNG_NODE:
+ case BGP_NODE:
+ case RMAP_NODE:
+ case OSPF_NODE:
+ case OSPF6_NODE:
+ case KEYCHAIN_NODE:
+ case KEYCHAIN_KEY_NODE:
+ case MASC_NODE:
+ case VTY_NODE:
+ vty_config_unlock (vty);
+ vty->node = ENABLE_NODE;
+ break;
+ default:
+ /* Unknown node, we have to ignore it. */
+ break;
+ }
+ vty_prompt (vty);
+
+ /* Set history pointer to the latest one. */
+ vty->hp = vty->hindex;
+}
+
+/* Add current command line to the history buffer. */
+static void
+vty_hist_add (struct vty *vty)
+{
+ int index;
+
+ if (vty->length == 0)
+ return;
+
+ index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
+
+ /* Ignore the same string as previous one. */
+ if (vty->hist[index])
+ if (strcmp (vty->buf, vty->hist[index]) == 0)
+ {
+ vty->hp = vty->hindex;
+ return;
+ }
+
+ /* Insert history entry. */
+ if (vty->hist[vty->hindex])
+ XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
+ vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
+
+ /* History index rotation. */
+ vty->hindex++;
+ if (vty->hindex == VTY_MAXHIST)
+ vty->hindex = 0;
+
+ vty->hp = vty->hindex;
+}
+
+/* #define TELNET_OPTION_DEBUG */
+
+/* Get telnet window size. */
+static int
+vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
+{
+#ifdef TELNET_OPTION_DEBUG
+ int i;
+
+ for (i = 0; i < nbytes; i++)
+ {
+ switch (buf[i])
+ {
+ case IAC:
+ vty_out (vty, "IAC ");
+ break;
+ case WILL:
+ vty_out (vty, "WILL ");
+ break;
+ case WONT:
+ vty_out (vty, "WONT ");
+ break;
+ case DO:
+ vty_out (vty, "DO ");
+ break;
+ case DONT:
+ vty_out (vty, "DONT ");
+ break;
+ case SB:
+ vty_out (vty, "SB ");
+ break;
+ case SE:
+ vty_out (vty, "SE ");
+ break;
+ case TELOPT_ECHO:
+ vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
+ break;
+ case TELOPT_SGA:
+ vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
+ break;
+ case TELOPT_NAWS:
+ vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
+ break;
+ default:
+ vty_out (vty, "%x ", buf[i]);
+ break;
+ }
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+#endif /* TELNET_OPTION_DEBUG */
+
+ switch (buf[0])
+ {
+ case SB:
+ buffer_reset(vty->sb_buffer);
+ vty->iac_sb_in_progress = 1;
+ return 0;
+ break;
+ case SE:
+ {
+ char *buffer = (char *)vty->sb_buffer->head->data;
+ int length = vty->sb_buffer->length;
+
+ if (buffer == NULL)
+ return 0;
+
+ if (!vty->iac_sb_in_progress)
+ return 0;
+
+ if (buffer[0] == '\0')
+ {
+ vty->iac_sb_in_progress = 0;
+ return 0;
+ }
+ switch (buffer[0])
+ {
+ case TELOPT_NAWS:
+ if (length < 5)
+ break;
+ vty->width = buffer[2];
+ vty->height = vty->lines >= 0 ? vty->lines : buffer[4];
+ break;
+ }
+ vty->iac_sb_in_progress = 0;
+ return 0;
+ break;
+ }
+ default:
+ break;
+ }
+ return 1;
+}
+
+/* Execute current command line. */
+static int
+vty_execute (struct vty *vty)
+{
+ int ret;
+
+ ret = CMD_SUCCESS;
+
+ switch (vty->node)
+ {
+ case AUTH_NODE:
+ case AUTH_ENABLE_NODE:
+ vty_auth (vty, vty->buf);
+ break;
+ default:
+ ret = vty_command (vty, vty->buf);
+ if (vty->type == VTY_TERM)
+ vty_hist_add (vty);
+ break;
+ }
+
+ /* Clear command line buffer. */
+ vty->cp = vty->length = 0;
+ vty_clear_buf (vty);
+
+ if (vty->status != VTY_CLOSE
+ && vty->status != VTY_START
+ && vty->status != VTY_CONTINUE)
+ vty_prompt (vty);
+
+ return ret;
+}
+
+#define CONTROL(X) ((X) - '@')
+#define VTY_NORMAL 0
+#define VTY_PRE_ESCAPE 1
+#define VTY_ESCAPE 2
+
+/* Escape character command map. */
+static void
+vty_escape_map (unsigned char c, struct vty *vty)
+{
+ switch (c)
+ {
+ case ('A'):
+ vty_previous_line (vty);
+ break;
+ case ('B'):
+ vty_next_line (vty);
+ break;
+ case ('C'):
+ vty_forward_char (vty);
+ break;
+ case ('D'):
+ vty_backward_char (vty);
+ break;
+ default:
+ break;
+ }
+
+ /* Go back to normal mode. */
+ vty->escape = VTY_NORMAL;
+}
+
+/* Quit print out to the buffer. */
+static void
+vty_buffer_reset (struct vty *vty)
+{
+ buffer_reset (vty->obuf);
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+}
+
+/* Read data via vty socket. */
+static int
+vty_read (struct thread *thread)
+{
+ int i;
+ int ret;
+ int nbytes;
+ unsigned char buf[VTY_READ_BUFSIZ];
+
+ int vty_sock = THREAD_FD (thread);
+ struct vty *vty = THREAD_ARG (thread);
+ vty->t_read = NULL;
+
+ /* Read raw data from socket */
+ nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ);
+ if (nbytes <= 0)
+ vty->status = VTY_CLOSE;
+
+ for (i = 0; i < nbytes; i++)
+ {
+ if (buf[i] == IAC)
+ {
+ if (!vty->iac)
+ {
+ vty->iac = 1;
+ continue;
+ }
+ else
+ {
+ vty->iac = 0;
+ }
+ }
+
+ if (vty->iac_sb_in_progress && !vty->iac)
+ {
+ buffer_putc(vty->sb_buffer, buf[i]);
+ continue;
+ }
+
+ if (vty->iac)
+ {
+ /* In case of telnet command */
+ ret = vty_telnet_option (vty, buf + i, nbytes - i);
+ vty->iac = 0;
+ i += ret;
+ continue;
+ }
+
+ if (vty->status == VTY_MORE)
+ {
+ switch (buf[i])
+ {
+ case CONTROL('C'):
+ case 'q':
+ case 'Q':
+ if (vty->output_func)
+ (*vty->output_func) (vty, 1);
+ vty_buffer_reset (vty);
+ break;
+#if 0 /* More line does not work for "show ip bgp". */
+ case '\n':
+ case '\r':
+ vty->status = VTY_MORELINE;
+ break;
+#endif
+ default:
+ if (vty->output_func)
+ (*vty->output_func) (vty, 0);
+ break;
+ }
+ continue;
+ }
+
+ /* Escape character. */
+ if (vty->escape == VTY_ESCAPE)
+ {
+ vty_escape_map (buf[i], vty);
+ continue;
+ }
+
+ /* Pre-escape status. */
+ if (vty->escape == VTY_PRE_ESCAPE)
+ {
+ switch (buf[i])
+ {
+ case '[':
+ vty->escape = VTY_ESCAPE;
+ break;
+ case 'b':
+ vty_backward_word (vty);
+ vty->escape = VTY_NORMAL;
+ break;
+ case 'f':
+ vty_forward_word (vty);
+ vty->escape = VTY_NORMAL;
+ break;
+ case 'd':
+ vty_forward_kill_word (vty);
+ vty->escape = VTY_NORMAL;
+ break;
+ case CONTROL('H'):
+ case 0x7f:
+ vty_backward_kill_word (vty);
+ vty->escape = VTY_NORMAL;
+ break;
+ default:
+ vty->escape = VTY_NORMAL;
+ break;
+ }
+ continue;
+ }
+
+ switch (buf[i])
+ {
+ case CONTROL('A'):
+ vty_beginning_of_line (vty);
+ break;
+ case CONTROL('B'):
+ vty_backward_char (vty);
+ break;
+ case CONTROL('C'):
+ vty_stop_input (vty);
+ break;
+ case CONTROL('D'):
+ vty_delete_char (vty);
+ break;
+ case CONTROL('E'):
+ vty_end_of_line (vty);
+ break;
+ case CONTROL('F'):
+ vty_forward_char (vty);
+ break;
+ case CONTROL('H'):
+ case 0x7f:
+ vty_delete_backward_char (vty);
+ break;
+ case CONTROL('K'):
+ vty_kill_line (vty);
+ break;
+ case CONTROL('N'):
+ vty_next_line (vty);
+ break;
+ case CONTROL('P'):
+ vty_previous_line (vty);
+ break;
+ case CONTROL('T'):
+ vty_transpose_chars (vty);
+ break;
+ case CONTROL('U'):
+ vty_kill_line_from_beginning (vty);
+ break;
+ case CONTROL('W'):
+ vty_backward_kill_word (vty);
+ break;
+ case CONTROL('Z'):
+ vty_end_config (vty);
+ break;
+ case '\n':
+ case '\r':
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_execute (vty);
+ break;
+ case '\t':
+ vty_complete_command (vty);
+ break;
+ case '?':
+ if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
+ vty_self_insert (vty, buf[i]);
+ else
+ vty_describe_command (vty);
+ break;
+ case '\033':
+ if (i + 1 < nbytes && buf[i + 1] == '[')
+ {
+ vty->escape = VTY_ESCAPE;
+ i++;
+ }
+ else
+ vty->escape = VTY_PRE_ESCAPE;
+ break;
+ default:
+ if (buf[i] > 31 && buf[i] < 127)
+ vty_self_insert (vty, buf[i]);
+ break;
+ }
+ }
+
+ /* Check status. */
+ if (vty->status == VTY_CLOSE)
+ vty_close (vty);
+ else
+ {
+ vty_event (VTY_WRITE, vty_sock, vty);
+ vty_event (VTY_READ, vty_sock, vty);
+ }
+ return 0;
+}
+
+/* Flush buffer to the vty. */
+static int
+vty_flush (struct thread *thread)
+{
+ int erase;
+ int dont_more;
+ int vty_sock = THREAD_FD (thread);
+ struct vty *vty = THREAD_ARG (thread);
+ vty->t_write = NULL;
+
+ /* Tempolary disable read thread. */
+ if (vty->lines == 0)
+ if (vty->t_read)
+ {
+ thread_cancel (vty->t_read);
+ vty->t_read = NULL;
+ }
+
+ /* Function execution continue. */
+ if (vty->status == VTY_START || vty->status == VTY_CONTINUE)
+ {
+ if (vty->status == VTY_CONTINUE)
+ erase = 1;
+ else
+ erase = 0;
+
+ if (vty->output_func == NULL)
+ dont_more = 1;
+ else
+ dont_more = 0;
+
+ if (vty->lines == 0)
+ {
+ erase = 0;
+ dont_more = 1;
+ }
+
+ buffer_flush_vty_all (vty->obuf, vty->fd, erase, dont_more);
+
+ if (vty->status == VTY_CLOSE)
+ {
+ vty_close (vty);
+ return 0;
+ }
+
+ if (vty->output_func == NULL)
+ {
+ vty->status = VTY_NORMAL;
+ vty_prompt (vty);
+ vty_event (VTY_WRITE, vty_sock, vty);
+ }
+ else
+ vty->status = VTY_MORE;
+
+ if (vty->lines == 0)
+ {
+ if (vty->output_func == NULL)
+ vty_event (VTY_READ, vty_sock, vty);
+ else
+ {
+ if (vty->output_func)
+ (*vty->output_func) (vty, 0);
+ vty_event (VTY_WRITE, vty_sock, vty);
+ }
+ }
+ }
+ else
+ {
+ if (vty->status == VTY_MORE || vty->status == VTY_MORELINE)
+ erase = 1;
+ else
+ erase = 0;
+
+ if (vty->lines == 0)
+ buffer_flush_window (vty->obuf, vty->fd, vty->width, 25, 0, 1);
+ else if (vty->status == VTY_MORELINE)
+ buffer_flush_window (vty->obuf, vty->fd, vty->width, 1, erase, 0);
+ else
+ buffer_flush_window (vty->obuf, vty->fd, vty->width,
+ vty->lines >= 0 ? vty->lines : vty->height,
+ erase, 0);
+
+ if (buffer_empty (vty->obuf))
+ {
+ if (vty->status == VTY_CLOSE)
+ vty_close (vty);
+ else
+ {
+ vty->status = VTY_NORMAL;
+
+ if (vty->lines == 0)
+ vty_event (VTY_READ, vty_sock, vty);
+ }
+ }
+ else
+ {
+ vty->status = VTY_MORE;
+
+ if (vty->lines == 0)
+ vty_event (VTY_WRITE, vty_sock, vty);
+ }
+ }
+
+ return 0;
+}
+
+/* Create new vty structure. */
+struct vty *
+vty_create (int vty_sock, union sockunion *su)
+{
+ struct vty *vty;
+
+ /* Allocate new vty structure and set up default values. */
+ vty = vty_new ();
+ vty->fd = vty_sock;
+ vty->type = VTY_TERM;
+ vty->address = sockunion_su2str (su);
+ if (no_password_check)
+ {
+ if (host.advanced)
+ vty->node = ENABLE_NODE;
+ else
+ vty->node = VIEW_NODE;
+ }
+ else
+ vty->node = AUTH_NODE;
+ vty->fail = 0;
+ vty->cp = 0;
+ vty_clear_buf (vty);
+ vty->length = 0;
+ memset (vty->hist, 0, sizeof (vty->hist));
+ vty->hp = 0;
+ vty->hindex = 0;
+ vector_set_index (vtyvec, vty_sock, vty);
+ vty->status = VTY_NORMAL;
+ vty->v_timeout = vty_timeout_val;
+ if (host.lines >= 0)
+ vty->lines = host.lines;
+ else
+ vty->lines = -1;
+ vty->iac = 0;
+ vty->iac_sb_in_progress = 0;
+ vty->sb_buffer = buffer_new (1024);
+
+ if (! no_password_check)
+ {
+ /* Vty is not available if password isn't set. */
+ if (host.password == NULL && host.password_encrypt == NULL)
+ {
+ vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
+ vty->status = VTY_CLOSE;
+ vty_close (vty);
+ return NULL;
+ }
+ }
+
+ /* Say hello to the world. */
+ vty_hello (vty);
+ if (! no_password_check)
+ vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+
+ /* Setting up terminal. */
+ vty_will_echo (vty);
+ vty_will_suppress_go_ahead (vty);
+
+ vty_dont_linemode (vty);
+ vty_do_window_size (vty);
+ /* vty_dont_lflow_ahead (vty); */
+
+ vty_prompt (vty);
+
+ /* Add read/write thread. */
+ vty_event (VTY_WRITE, vty_sock, vty);
+ vty_event (VTY_READ, vty_sock, vty);
+
+ return vty;
+}
+
+/* Accept connection from the network. */
+static int
+vty_accept (struct thread *thread)
+{
+ int vty_sock;
+ struct vty *vty;
+ union sockunion su;
+ int ret;
+ unsigned int on;
+ int accept_sock;
+ struct prefix *p = NULL;
+ struct access_list *acl = NULL;
+
+ accept_sock = THREAD_FD (thread);
+
+ /* We continue hearing vty socket. */
+ vty_event (VTY_SERV, accept_sock, NULL);
+
+ memset (&su, 0, sizeof (union sockunion));
+
+ /* We can handle IPv4 or IPv6 socket. */
+ vty_sock = sockunion_accept (accept_sock, &su);
+ if (vty_sock < 0)
+ {
+ zlog_warn ("can't accept vty socket : %s", strerror (errno));
+ return -1;
+ }
+
+ p = sockunion2hostprefix (&su);
+
+ /* VTY's accesslist apply. */
+ if (p->family == AF_INET && vty_accesslist_name)
+ {
+ if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
+ (access_list_apply (acl, p) == FILTER_DENY))
+ {
+ char *buf;
+ zlog (NULL, LOG_INFO, "Vty connection refused from %s",
+ (buf = sockunion_su2str (&su)));
+ free (buf);
+ close (vty_sock);
+
+ /* continue accepting connections */
+ vty_event (VTY_SERV, accept_sock, NULL);
+
+ prefix_free (p);
+
+ return 0;
+ }
+ }
+
+#ifdef HAVE_IPV6
+ /* VTY's ipv6 accesslist apply. */
+ if (p->family == AF_INET6 && vty_ipv6_accesslist_name)
+ {
+ if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
+ (access_list_apply (acl, p) == FILTER_DENY))
+ {
+ char *buf;
+ zlog (NULL, LOG_INFO, "Vty connection refused from %s",
+ (buf = sockunion_su2str (&su)));
+ free (buf);
+ close (vty_sock);
+
+ /* continue accepting connections */
+ vty_event (VTY_SERV, accept_sock, NULL);
+
+ prefix_free (p);
+
+ return 0;
+ }
+ }
+#endif /* HAVE_IPV6 */
+
+ prefix_free (p);
+
+ on = 1;
+ ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
+ (char *) &on, sizeof (on));
+ if (ret < 0)
+ zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
+ strerror (errno));
+
+ vty = vty_create (vty_sock, &su);
+
+ return 0;
+}
+
+#if defined(HAVE_IPV6) && !defined(NRL)
+void
+vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
+{
+ int ret;
+ struct addrinfo req;
+ struct addrinfo *ainfo;
+ struct addrinfo *ainfo_save;
+ int sock;
+ char port_str[BUFSIZ];
+
+ memset (&req, 0, sizeof (struct addrinfo));
+ req.ai_flags = AI_PASSIVE;
+ req.ai_family = AF_UNSPEC;
+ req.ai_socktype = SOCK_STREAM;
+ sprintf (port_str, "%d", port);
+ port_str[sizeof (port_str) - 1] = '\0';
+
+ ret = getaddrinfo (hostname, port_str, &req, &ainfo);
+
+ if (ret != 0)
+ {
+ fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
+ exit (1);
+ }
+
+ ainfo_save = ainfo;
+
+ do
+ {
+ if (ainfo->ai_family != AF_INET
+#ifdef HAVE_IPV6
+ && ainfo->ai_family != AF_INET6
+#endif /* HAVE_IPV6 */
+ )
+ continue;
+
+ sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
+ if (sock < 0)
+ continue;
+
+ sockopt_reuseaddr (sock);
+ sockopt_reuseport (sock);
+
+ ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
+ if (ret < 0)
+ {
+ close (sock); /* Avoid sd leak. */
+ continue;
+ }
+
+ ret = listen (sock, 3);
+ if (ret < 0)
+ {
+ close (sock); /* Avoid sd leak. */
+ continue;
+ }
+
+ vty_event (VTY_SERV, sock, NULL);
+ }
+ while ((ainfo = ainfo->ai_next) != NULL);
+
+ freeaddrinfo (ainfo_save);
+}
+#endif /* HAVE_IPV6 && ! NRL */
+
+/* Make vty server socket. */
+void
+vty_serv_sock_family (unsigned short port, int family)
+{
+ int ret;
+ union sockunion su;
+ int accept_sock;
+
+ memset (&su, 0, sizeof (union sockunion));
+ su.sa.sa_family = family;
+
+ /* Make new socket. */
+ accept_sock = sockunion_stream_socket (&su);
+ if (accept_sock < 0)
+ return;
+
+ /* This is server, so reuse address. */
+ sockopt_reuseaddr (accept_sock);
+ sockopt_reuseport (accept_sock);
+
+ /* Bind socket to universal address and given port. */
+ ret = sockunion_bind (accept_sock, &su, port, NULL);
+ if (ret < 0)
+ {
+ close (accept_sock); /* Avoid sd leak. */
+ return;
+ }
+
+ /* Listen socket under queue 3. */
+ ret = listen (accept_sock, 3);
+ if (ret < 0)
+ {
+ zlog (NULL, LOG_WARNING, "can't listen socket");
+ close (accept_sock); /* Avoid sd leak. */
+ return;
+ }
+
+ /* Add vty server event. */
+ vty_event (VTY_SERV, accept_sock, NULL);
+}
+
+#ifdef VTYSH
+/* For sockaddr_un. */
+#include <sys/un.h>
+
+/* VTY shell UNIX domain socket. */
+void
+vty_serv_un (char *path)
+{
+ int ret;
+ int sock, len;
+ struct sockaddr_un serv;
+ mode_t old_mask;
+
+ /* First of all, unlink existing socket */
+ unlink (path);
+
+ /* Set umask */
+ old_mask = umask (0077);
+
+ /* Make UNIX domain socket. */
+ sock = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0)
+ {
+ perror ("sock");
+ return;
+ }
+
+ /* Make server socket. */
+ memset (&serv, 0, sizeof (struct sockaddr_un));
+ serv.sun_family = AF_UNIX;
+ strncpy (serv.sun_path, path, strlen (path));
+#ifdef HAVE_SUN_LEN
+ len = serv.sun_len = SUN_LEN(&serv);
+#else
+ len = sizeof (serv.sun_family) + strlen (serv.sun_path);
+#endif /* HAVE_SUN_LEN */
+
+ ret = bind (sock, (struct sockaddr *) &serv, len);
+ if (ret < 0)
+ {
+ perror ("bind");
+ close (sock); /* Avoid sd leak. */
+ return;
+ }
+
+ ret = listen (sock, 5);
+ if (ret < 0)
+ {
+ perror ("listen");
+ close (sock); /* Avoid sd leak. */
+ return;
+ }
+
+ umask (old_mask);
+
+ vty_event (VTYSH_SERV, sock, NULL);
+}
+
+/* #define VTYSH_DEBUG 1 */
+
+static int
+vtysh_accept (struct thread *thread)
+{
+ int accept_sock;
+ int sock;
+ int client_len;
+ struct sockaddr_un client;
+ struct vty *vty;
+
+ accept_sock = THREAD_FD (thread);
+
+ vty_event (VTYSH_SERV, accept_sock, NULL);
+
+ memset (&client, 0, sizeof (struct sockaddr_un));
+ client_len = sizeof (struct sockaddr_un);
+
+ sock = accept (accept_sock, (struct sockaddr *) &client, &client_len);
+
+ if (sock < 0)
+ {
+ zlog_warn ("can't accept vty socket : %s", strerror (errno));
+ return -1;
+ }
+
+#ifdef VTYSH_DEBUG
+ printf ("VTY shell accept\n");
+#endif /* VTYSH_DEBUG */
+
+ vty = vty_new ();
+ vty->fd = sock;
+ vty->type = VTY_SHELL_SERV;
+ vty->node = VIEW_NODE;
+
+ vty_event (VTYSH_READ, sock, vty);
+
+ return 0;
+}
+
+static int
+vtysh_read (struct thread *thread)
+{
+ int ret;
+ int sock;
+ int nbytes;
+ struct vty *vty;
+ unsigned char buf[VTY_READ_BUFSIZ];
+ u_char header[4] = {0, 0, 0, 0};
+
+ sock = THREAD_FD (thread);
+ vty = THREAD_ARG (thread);
+ vty->t_read = NULL;
+
+ nbytes = read (sock, buf, VTY_READ_BUFSIZ);
+ if (nbytes <= 0)
+ {
+ vty_close (vty);
+#ifdef VTYSH_DEBUG
+ printf ("close vtysh\n");
+#endif /* VTYSH_DEBUG */
+ return 0;
+ }
+
+#ifdef VTYSH_DEBUG
+ printf ("line: %s\n", buf);
+#endif /* VTYSH_DEBUG */
+
+ vty_ensure (vty, nbytes);
+ memcpy (vty->buf, buf, nbytes);
+
+ /* Pass this line to parser. */
+ ret = vty_execute (vty);
+
+ vty_clear_buf (vty);
+
+ /* Return result. */
+#ifdef VTYSH_DEBUG
+ printf ("result: %d\n", ret);
+ printf ("vtysh node: %d\n", vty->node);
+#endif /* VTYSH_DEBUG */
+
+ header[3] = ret;
+ write (vty->fd, header, 4);
+
+ vty_event (VTYSH_READ, sock, vty);
+
+ return 0;
+}
+#endif /* VTYSH */
+
+/* Determine address family to bind. */
+void
+vty_serv_sock (const char *hostname, unsigned short port, char *path)
+{
+ /* If port is set to 0, do not listen on TCP/IP at all! */
+ if (port)
+ {
+
+#ifdef HAVE_IPV6
+#ifdef NRL
+ vty_serv_sock_family (port, AF_INET);
+ vty_serv_sock_family (port, AF_INET6);
+#else /* ! NRL */
+ vty_serv_sock_addrinfo (hostname, port);
+#endif /* NRL*/
+#else /* ! HAVE_IPV6 */
+ vty_serv_sock_family (port, AF_INET);
+#endif /* HAVE_IPV6 */
+ }
+
+#ifdef VTYSH
+ vty_serv_un (path);
+#endif /* VTYSH */
+}
+
+/* Close vty interface. */
+void
+vty_close (struct vty *vty)
+{
+ int i;
+
+ /* Cancel threads.*/
+ if (vty->t_read)
+ thread_cancel (vty->t_read);
+ if (vty->t_write)
+ thread_cancel (vty->t_write);
+ if (vty->t_timeout)
+ thread_cancel (vty->t_timeout);
+ if (vty->t_output)
+ thread_cancel (vty->t_output);
+
+ /* Flush buffer. */
+ if (! buffer_empty (vty->obuf))
+ buffer_flush_all (vty->obuf, vty->fd);
+
+ /* Free input buffer. */
+ buffer_free (vty->obuf);
+
+ /* Free SB buffer. */
+ if (vty->sb_buffer)
+ buffer_free (vty->sb_buffer);
+
+ /* Free command history. */
+ for (i = 0; i < VTY_MAXHIST; i++)
+ if (vty->hist[i])
+ XFREE (MTYPE_VTY_HIST, vty->hist[i]);
+
+ /* Unset vector. */
+ vector_unset (vtyvec, vty->fd);
+
+ /* Close socket. */
+ if (vty->fd > 0)
+ close (vty->fd);
+
+ if (vty->address)
+ XFREE (0, vty->address);
+ if (vty->buf)
+ XFREE (MTYPE_VTY, vty->buf);
+
+ /* Check configure. */
+ vty_config_unlock (vty);
+
+ /* OK free vty. */
+ XFREE (MTYPE_VTY, vty);
+}
+
+/* When time out occur output message then close connection. */
+static int
+vty_timeout (struct thread *thread)
+{
+ struct vty *vty;
+
+ vty = THREAD_ARG (thread);
+ vty->t_timeout = NULL;
+ vty->v_timeout = 0;
+
+ /* Clear buffer*/
+ buffer_reset (vty->obuf);
+ vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
+
+ /* Close connection. */
+ vty->status = VTY_CLOSE;
+ vty_close (vty);
+
+ return 0;
+}
+
+/* Read up configuration file from file_name. */
+static void
+vty_read_file (FILE *confp)
+{
+ int ret;
+ struct vty *vty;
+
+ vty = vty_new ();
+ vty->fd = 0; /* stdout */
+ vty->type = VTY_TERM;
+ vty->node = CONFIG_NODE;
+
+ /* Execute configuration file */
+ ret = config_from_file (vty, confp);
+
+ if (ret != CMD_SUCCESS)
+ {
+ switch (ret)
+ {
+ case CMD_ERR_AMBIGUOUS:
+ fprintf (stderr, "Ambiguous command.\n");
+ break;
+ case CMD_ERR_NO_MATCH:
+ fprintf (stderr, "There is no such command.\n");
+ break;
+ }
+ fprintf (stderr, "Error occured during reading below line.\n%s\n",
+ vty->buf);
+ vty_close (vty);
+ exit (1);
+ }
+
+ vty_close (vty);
+}
+
+FILE *
+vty_use_backup_config (char *fullpath)
+{
+ char *fullpath_sav, *fullpath_tmp;
+ FILE *ret = NULL;
+ struct stat buf;
+ int tmp, sav;
+ int c;
+ char buffer[512];
+
+ fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
+ strcpy (fullpath_sav, fullpath);
+ strcat (fullpath_sav, CONF_BACKUP_EXT);
+ if (stat (fullpath_sav, &buf) == -1)
+ {
+ free (fullpath_sav);
+ return NULL;
+ }
+
+ fullpath_tmp = malloc (strlen (fullpath) + 8);
+ sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
+
+ /* Open file to configuration write. */
+ tmp = mkstemp (fullpath_tmp);
+ if (tmp < 0)
+ {
+ free (fullpath_sav);
+ free (fullpath_tmp);
+ return NULL;
+ }
+
+ sav = open (fullpath_sav, O_RDONLY);
+ if (sav < 0)
+ {
+ free (fullpath_sav);
+ free (fullpath_tmp);
+ unlink (fullpath_tmp);
+ return NULL;
+ }
+
+ while((c = read (sav, buffer, 512)) > 0)
+ write (tmp, buffer, c);
+
+ close (sav);
+ close (tmp);
+
+ if (link (fullpath_tmp, fullpath) == 0)
+ ret = fopen (fullpath, "r");
+
+ unlink (fullpath_tmp);
+
+ free (fullpath_sav);
+ free (fullpath_tmp);
+ return fopen (fullpath, "r");
+}
+
+/* Read up configuration file from file_name. */
+void
+vty_read_config (char *config_file,
+ char *config_current_dir,
+ char *config_default_dir)
+{
+ char *cwd;
+ FILE *confp = NULL;
+ char *fullpath;
+
+ /* If -f flag specified. */
+ if (config_file != NULL)
+ {
+ if (! IS_DIRECTORY_SEP (config_file[0]))
+ {
+ cwd = getcwd (NULL, MAXPATHLEN);
+ fullpath = XMALLOC (MTYPE_TMP,
+ strlen (cwd) + strlen (config_file) + 2);
+ sprintf (fullpath, "%s/%s", cwd, config_file);
+ }
+ else
+ fullpath = config_file;
+
+ confp = fopen (fullpath, "r");
+
+ if (confp == NULL)
+ {
+ confp = vty_use_backup_config (fullpath);
+ if (confp)
+ fprintf (stderr, "WARNING: using backup configuration file!\n");
+ else
+ {
+ fprintf (stderr, "can't open configuration file [%s]\n",
+ config_file);
+ exit(1);
+ }
+ }
+ }
+ else
+ {
+ /* Relative path configuration file open. */
+ if (config_current_dir)
+ {
+ confp = fopen (config_current_dir, "r");
+ if (confp == NULL)
+ {
+ confp = vty_use_backup_config (config_current_dir);
+ if (confp)
+ fprintf (stderr, "WARNING: using backup configuration file!\n");
+ }
+ }
+
+ /* If there is no relative path exists, open system default file. */
+ if (confp == NULL)
+ {
+#ifdef VTYSH
+ int ret;
+ struct stat conf_stat;
+
+ /* !!!!PLEASE LEAVE!!!!
+ This is NEEDED for use with vtysh -b, or else you can get
+ a real configuration food fight with a lot garbage in the
+ merged configuration file it creates coming from the per
+ daemon configuration files. This also allows the daemons
+ to start if there default configuration file is not
+ present or ignore them, as needed when using vtysh -b to
+ configure the daemons at boot - MAG */
+
+ /* Stat for vtysh Zebra.conf, if found startup and wait for
+ boot configuration */
+
+ if ( strstr(config_default_dir, "vtysh") == NULL)
+ {
+ ret = stat (integrate_default, &conf_stat);
+ if (ret >= 0)
+ {
+ return;
+ }
+ }
+#endif /* VTYSH */
+
+ confp = fopen (config_default_dir, "r");
+ if (confp == NULL)
+ {
+ confp = vty_use_backup_config (config_default_dir);
+ if (confp)
+ {
+ fprintf (stderr, "WARNING: using backup configuration file!\n");
+ fullpath = config_default_dir;
+ }
+ else
+ {
+ fprintf (stderr, "can't open configuration file [%s]\n",
+ config_default_dir);
+ exit (1);
+ }
+ }
+ else
+ fullpath = config_default_dir;
+ }
+ else
+ {
+ /* Rleative path configuration file. */
+ cwd = getcwd (NULL, MAXPATHLEN);
+ fullpath = XMALLOC (MTYPE_TMP,
+ strlen (cwd) + strlen (config_current_dir) + 2);
+ sprintf (fullpath, "%s/%s", cwd, config_current_dir);
+ }
+ }
+ vty_read_file (confp);
+
+ fclose (confp);
+
+ host_config_set (fullpath);
+}
+
+/* Small utility function which output log to the VTY. */
+void
+vty_log (const char *proto_str, const char *format, va_list va)
+{
+ int i;
+ struct vty *vty;
+
+ for (i = 0; i < vector_max (vtyvec); i++)
+ if ((vty = vector_slot (vtyvec, i)) != NULL)
+ if (vty->monitor)
+ vty_log_out (vty, proto_str, format, va);
+}
+
+int
+vty_config_lock (struct vty *vty)
+{
+ if (vty_config == 0)
+ {
+ vty->config = 1;
+ vty_config = 1;
+ }
+ return vty->config;
+}
+
+int
+vty_config_unlock (struct vty *vty)
+{
+ if (vty_config == 1 && vty->config == 1)
+ {
+ vty->config = 0;
+ vty_config = 0;
+ }
+ return vty->config;
+}
+
+/* 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 <zebra.h>
+
+#include "prefix.h"
+#include "stream.h"
+#include "network.h"
+#include "if.h"
+#include "log.h"
+#include "thread.h"
+#include "zclient.h"
+#include "memory.h"
+#include "table.h"
+
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+
+/* 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 <sys/un.h>
+
+int
+zclient_socket_un (char *path)
+{
+ int ret;
+ int sock, len;
+ struct sockaddr_un addr;
+
+ sock = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0)
+ return -1;
+
+ /* Make server socket. */
+ memset (&addr, 0, sizeof (struct sockaddr_un));
+ addr.sun_family = AF_UNIX;
+ strncpy (addr.sun_path, path, strlen (path));
+#ifdef HAVE_SUN_LEN
+ len = addr.sun_len = SUN_LEN(&addr);
+#else
+ len = sizeof (addr.sun_family) + strlen (addr.sun_path);
+#endif /* HAVE_SUN_LEN */
+
+ ret = connect (sock, (struct sockaddr *) &addr, len);
+ if (ret < 0)
+ {
+ close (sock);
+ return -1;
+ }
+ return sock;
+}
+
+/* Send simple Zebra message. */
+int
+zebra_message_send (struct zclient *zclient, int command)
+{
+ struct stream *s;
+
+ /* Get zclient output buffer. */
+ s = zclient->obuf;
+ stream_reset (s);
+
+ /* Send very simple command only Zebra message. */
+ stream_putw (s, 3);
+ stream_putc (s, command);
+
+ return writen (zclient->sock, s->data, 3);
+}
+
+/* Make connection to zebra daemon. */
+int
+zclient_start (struct zclient *zclient)
+{
+ int i;
+
+ if (zclient_debug)
+ zlog_info ("zclient_start is called");
+
+ /* zclient is disabled. */
+ if (! zclient->enable)
+ return 0;
+
+ /* If already connected to the zebra. */
+ if (zclient->sock >= 0)
+ return 0;
+
+ /* Check connect thread. */
+ if (zclient->t_connect)
+ return 0;
+
+ /* Make socket. */
+#ifdef HAVE_TCP_ZEBRA
+ zclient->sock = zclient_socket ();
+#else
+ zclient->sock = zclient_socket_un (ZEBRA_SERV_PATH);
+#endif /* HAVE_TCP_ZEBRA */
+ if (zclient->sock < 0)
+ {
+ if (zclient_debug)
+ zlog_info ("zclient connection fail");
+ zclient->fail++;
+ zclient_event (ZCLIENT_CONNECT, zclient);
+ return -1;
+ }
+
+ /* Clear fail count. */
+ zclient->fail = 0;
+ if (zclient_debug)
+ zlog_info ("zclient connect success with socket [%d]", zclient->sock);
+
+ /* Create read thread. */
+ zclient_event (ZCLIENT_READ, zclient);
+
+ /* We need interface information. */
+ zebra_message_send (zclient, ZEBRA_INTERFACE_ADD);
+
+ /* Flush all redistribute request. */
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ if (i != zclient->redist_default && zclient->redist[i])
+ zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, i);
+
+ /* If default information is needed. */
+ if (zclient->default_information)
+ zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_ADD);
+
+ return 0;
+}
+
+/* This function is a wrapper function for calling zclient_start from
+ timer or event thread. */
+int
+zclient_connect (struct thread *t)
+{
+ struct zclient *zclient;
+
+ zclient = THREAD_ARG (t);
+ zclient->t_connect = NULL;
+
+ if (zclient_debug)
+ zlog_info ("zclient_connect is called");
+
+ return zclient_start (zclient);
+}
+
+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 <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#ifdef HAVE_STROPTS_H
+#include <stropts.h>
+#endif /* HAVE_STROPTS_H */
+#include <sys/fcntl.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif /* HAVE_SYS_SELECT_H */
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif /* HAVE_SYS_SYSCTL_H */
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_CONF_H
+#include <sys/conf.h>
+#endif /* HAVE_SYS_CONF_H */
+#ifdef HAVE_SYS_KSYM_H
+#include <sys/ksym.h>
+#endif /* HAVE_SYS_KSYM_H */
+#include <syslog.h>
+#include <time.h>
+#include <sys/uio.h>
+#include <sys/utsname.h>
+#ifdef HAVE_RUSAGE
+#include <sys/resource.h>
+#endif /* HAVE_RUSAGE */
+
+/* machine dependent includes */
+#ifdef SUNOS_5
+#include <limits.h>
+#include <strings.h>
+#endif /* SUNOS_5 */
+
+/* machine dependent includes */
+#ifdef HAVE_LINUX_VERSION_H
+#include <linux/version.h>
+#endif /* HAVE_LINUX_VERSION_H */
+
+#ifdef HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif /* HAVE_ASM_TYPES_H */
+
+/* misc include group */
+#include <stdarg.h>
+#include <assert.h>
+
+/* network include group */
+
+#include <sys/socket.h>
+
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif /* HAVE_SYS_SOCKIO_H */
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif /* HAVE_NETINET_IN_H */
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#ifdef HAVE_NET_NETOPT_H
+#include <net/netopt.h>
+#endif /* HAVE_NET_NETOPT_H */
+
+#include <net/if.h>
+
+#ifdef HAVE_NET_IF_DL_H
+#include <net/if_dl.h>
+#endif /* HAVE_NET_IF_DL_H */
+
+#ifdef HAVE_NET_IF_VAR_H
+#include <net/if_var.h>
+#endif /* HAVE_NET_IF_VAR_H */
+
+#include <net/route.h>
+
+#ifdef HAVE_NETLINK
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#else
+#define RT_TABLE_MAIN 0
+#endif /* HAVE_NETLINK */
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif /* HAVE_NETDB_H */
+
+#include <arpa/inet.h>
+#include <arpa/telnet.h>
+
+#ifdef HAVE_INET_ND_H
+#include <inet/nd.h>
+#endif /* HAVE_INET_ND_H */
+
+#ifdef HAVE_NETINET_IN_VAR_H
+#include <netinet/in_var.h>
+#endif /* HAVE_NETINET_IN_VAR_H */
+
+#ifdef HAVE_NETINET_IN6_VAR_H
+#include <netinet/in6_var.h>
+#endif /* HAVE_NETINET_IN6_VAR_H */
+
+#ifdef HAVE_NETINET6_IN_H
+#include <netinet6/in.h>
+#endif /* HAVE_NETINET6_IN_H */
+
+
+#ifdef HAVE_NETINET6_IP6_H
+#include <netinet6/ip6.h>
+#endif /* HAVE_NETINET6_IP6_H */
+
+#ifdef HAVE_NETINET_ICMP6_H
+#include <netinet/icmp6.h>
+#endif /* HAVE_NETINET_ICMP6_H */
+
+#ifdef HAVE_NETINET6_ND6_H
+#include <netinet6/nd6.h>
+#endif /* HAVE_NETINET6_ND6_H */
+
+#ifdef HAVE_LIBUTIL_H
+#include <libutil.h>
+#endif /* HAVE_LIBUTIL_H */
+
+#ifdef BSDI_NRL
+
+#ifdef HAVE_NETINET6_IN6_H
+#include <netinet6/in6.h>
+#endif /* HAVE_NETINET6_IN6_H */
+
+#ifdef NRL
+#include <netinet6/in6.h>
+#endif /* NRL */
+
+#define IN6_ARE_ADDR_EQUAL IN6_IS_ADDR_EQUAL
+
+/* BSD/OS 4.0 has lost belows defines, it should appear at
+ /usr/include/sys/socket.h. */
+#define CMSG_ALIGN(n) (((n) + 3) & ~3)
+#define CMSG_SPACE(l) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(l))
+#define CMSG_LEN(l) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (l))
+
+#endif /* BSDI_NRL */
+
+/* The definition of struct in_pktinfo is missing in old version of
+ GLIBC 2.1 (Redhat 6.1). */
+#if defined (GNU_LINUX) && ! defined (HAVE_INPKTINFO)
+struct in_pktinfo
+{
+ int ipi_ifindex;
+ struct in_addr ipi_spec_dst;
+ struct in_addr ipi_addr;
+};
+#endif
+
+/* For old definition. */
+#ifndef IN6_ARE_ADDR_EQUAL
+#define IN6_ARE_ADDR_EQUAL IN6_IS_ADDR_EQUAL
+#endif /* IN6_ARE_ADDR_EQUAL */
+
+/* Zebra message types. */
+#define ZEBRA_INTERFACE_ADD 1
+#define ZEBRA_INTERFACE_DELETE 2
+#define ZEBRA_INTERFACE_ADDRESS_ADD 3
+#define ZEBRA_INTERFACE_ADDRESS_DELETE 4
+#define ZEBRA_INTERFACE_UP 5
+#define ZEBRA_INTERFACE_DOWN 6
+#define ZEBRA_IPV4_ROUTE_ADD 7
+#define ZEBRA_IPV4_ROUTE_DELETE 8
+#define ZEBRA_IPV6_ROUTE_ADD 9
+#define ZEBRA_IPV6_ROUTE_DELETE 10
+#define ZEBRA_REDISTRIBUTE_ADD 11
+#define ZEBRA_REDISTRIBUTE_DELETE 12
+#define ZEBRA_REDISTRIBUTE_DEFAULT_ADD 13
+#define ZEBRA_REDISTRIBUTE_DEFAULT_DELETE 14
+#define ZEBRA_IPV4_NEXTHOP_LOOKUP 15
+#define ZEBRA_IPV6_NEXTHOP_LOOKUP 16
+#define ZEBRA_IPV4_IMPORT_LOOKUP 17
+#define ZEBRA_IPV6_IMPORT_LOOKUP 18
+#define ZEBRA_MESSAGE_MAX 19
+
+/* Zebra route's types. */
+#define ZEBRA_ROUTE_SYSTEM 0
+#define ZEBRA_ROUTE_KERNEL 1
+#define ZEBRA_ROUTE_CONNECT 2
+#define ZEBRA_ROUTE_STATIC 3
+#define ZEBRA_ROUTE_RIP 4
+#define ZEBRA_ROUTE_RIPNG 5
+#define ZEBRA_ROUTE_OSPF 6
+#define ZEBRA_ROUTE_OSPF6 7
+#define ZEBRA_ROUTE_BGP 8
+#define ZEBRA_ROUTE_MAX 9
+
+/* Zebra's family types. */
+#define ZEBRA_FAMILY_IPV4 1
+#define ZEBRA_FAMILY_IPV6 2
+#define ZEBRA_FAMILY_MAX 3
+
+/* Error codes of zebra. */
+#define ZEBRA_ERR_RTEXIST -1
+#define ZEBRA_ERR_RTUNREACH -2
+#define ZEBRA_ERR_EPERM -3
+#define ZEBRA_ERR_RTNOEXIST -4
+
+/* Zebra message flags */
+#define ZEBRA_FLAG_INTERNAL 0x01
+#define ZEBRA_FLAG_SELFROUTE 0x02
+#define ZEBRA_FLAG_BLACKHOLE 0x04
+#define ZEBRA_FLAG_IBGP 0x08
+#define ZEBRA_FLAG_SELECTED 0x10
+#define ZEBRA_FLAG_CHANGED 0x20
+#define ZEBRA_FLAG_STATIC 0x40
+
+/* Zebra nexthop flags. */
+#define ZEBRA_NEXTHOP_IFINDEX 1
+#define ZEBRA_NEXTHOP_IFNAME 2
+#define ZEBRA_NEXTHOP_IPV4 3
+#define ZEBRA_NEXTHOP_IPV4_IFINDEX 4
+#define ZEBRA_NEXTHOP_IPV4_IFNAME 5
+#define ZEBRA_NEXTHOP_IPV6 6
+#define ZEBRA_NEXTHOP_IPV6_IFINDEX 7
+#define ZEBRA_NEXTHOP_IPV6_IFNAME 8
+#define ZEBRA_NEXTHOP_BLACKHOLE 9
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */
+#endif
+
+/* Address family numbers from RFC1700. */
+#define AFI_IP 1
+#define AFI_IP6 2
+#define AFI_MAX 3
+
+/* Subsequent Address Family Identifier. */
+#define SAFI_UNICAST 1
+#define SAFI_MULTICAST 2
+#define SAFI_UNICAST_MULTICAST 3
+#define SAFI_MPLS_VPN 4
+#define SAFI_MAX 5
+
+/* Filter direction. */
+#define FILTER_IN 0
+#define FILTER_OUT 1
+#define FILTER_MAX 2
+
+/* Default Administrative Distance of each protocol. */
+#define ZEBRA_KERNEL_DISTANCE_DEFAULT 0
+#define ZEBRA_CONNECT_DISTANCE_DEFAULT 0
+#define ZEBRA_STATIC_DISTANCE_DEFAULT 1
+#define ZEBRA_RIP_DISTANCE_DEFAULT 120
+#define ZEBRA_RIPNG_DISTANCE_DEFAULT 120
+#define ZEBRA_OSPF_DISTANCE_DEFAULT 110
+#define ZEBRA_OSPF6_DISTANCE_DEFAULT 110
+#define ZEBRA_IBGP_DISTANCE_DEFAULT 200
+#define ZEBRA_EBGP_DISTANCE_DEFAULT 20
+
+/* Flag manipulation macros. */
+#define CHECK_FLAG(V,F) ((V) & (F))
+#define SET_FLAG(V,F) (V) = (V) | (F)
+#define UNSET_FLAG(V,F) (V) = (V) & ~(F)
+
+/* AFI and SAFI type. */
+typedef u_int16_t afi_t;
+typedef u_char safi_t;
+
+/* Zebra types. */
+typedef u_int16_t zebra_size_t;
+typedef u_int8_t zebra_command_t;
+
+#endif /* _ZEBRA_H */
diff --git a/missing b/missing
new file mode 100755
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 <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+run=:
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+ configure_ac=configure.ac
+else
+ configure_ac=configure.in
+fi
+
+case "$1" in
+--run)
+ # Try to run requested program, and just exit if it succeeds.
+ run=
+ shift
+ "$@" && exit 0
+ ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case "$1" in
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+ --run try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ help2man touch the output file
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ tar try tar, gnutar, gtar, then tar without non-portable flags
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]"
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing 0.4 - GNU automake"
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+ aclocal*)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acinclude.m4' or \`${configure_ac}'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`${configure_ac}'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acconfig.h' or \`${configure_ac}'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case "$f" in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake*)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ autom4te)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+ system. You might have modified some files without having the
+ proper tools for further handling them.
+ You can get \`$1Help2man' as part of \`Autoconf' from any GNU
+ archive site."
+
+ file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
+ test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo "#! /bin/sh"
+ echo "# Created by GNU Automake missing as a replacement of"
+ echo "# $ $@"
+ echo "exit 0"
+ chmod +x $file
+ exit 1
+ fi
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f y.tab.h ]; then
+ echo >y.tab.h
+ fi
+ if [ ! -f y.tab.c ]; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f lex.yy.c ]; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ help2man)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a dependency of a manual page. You may need the
+ \`Help2man' package in order for those modifications to take
+ effect. You can get \`Help2man' from any GNU archive site."
+
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
+ fi
+ if [ -f "$file" ]; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo ".ab help2man is required to generate this page"
+ exit 1
+ fi
+ ;;
+
+ makeinfo)
+ if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then
+ # We have makeinfo, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+ fi
+ touch $file
+ ;;
+
+ tar)
+ shift
+ if test -n "$run"; then
+ echo 1>&2 "ERROR: \`tar' requires --run"
+ exit 1
+ fi
+
+ # We have already tried tar in the generic part.
+ # Look for gnutar/gtar before invocation to avoid ugly error
+ # messages.
+ if (gnutar --version > /dev/null 2>&1); then
+ gnutar ${1+"$@"} && exit 0
+ fi
+ if (gtar --version > /dev/null 2>&1); then
+ gtar ${1+"$@"} && exit 0
+ fi
+ firstarg="$1"
+ if shift; then
+ case "$firstarg" in
+ *o*)
+ firstarg=`echo "$firstarg" | sed s/o//`
+ tar "$firstarg" ${1+"$@"} && exit 0
+ ;;
+ esac
+ case "$firstarg" in
+ *h*)
+ firstarg=`echo "$firstarg" | sed s/h//`
+ tar "$firstarg" ${1+"$@"} && exit 0
+ ;;
+ esac
+ fi
+
+ echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+ You may want to install GNU tar or Free paxutils, or check the
+ command line arguments."
+ exit 1
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+ system. You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequirements for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 100755
index 00000000..f20ccf3c
--- /dev/null
+++ b/mkinstalldirs
@@ -0,0 +1,101 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id: mkinstalldirs,v 1.1 2002/12/13 20:15:29 paul Exp $
+
+errstatus=0
+dirmode=""
+
+usage="\
+Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..."
+
+# process command line arguments
+while test $# -gt 0 ; do
+ case "${1}" in
+ -h | --help | --h* ) # -h for help
+ echo "${usage}" 1>&2; exit 0 ;;
+ -m ) # -m PERM arg
+ shift
+ test $# -eq 0 && { echo "${usage}" 1>&2; exit 1; }
+ dirmode="${1}"
+ shift ;;
+ -- ) shift; break ;; # stop option processing
+ -* ) echo "${usage}" 1>&2; exit 1 ;; # unknown option
+ * ) break ;; # first non-opt arg
+ esac
+done
+
+for file
+do
+ if test -d "$file"; then
+ shift
+ else
+ break
+ fi
+done
+
+case $# in
+0) exit 0 ;;
+esac
+
+case $dirmode in
+'')
+ if mkdir -p -- . 2>/dev/null; then
+ echo "mkdir -p -- $*"
+ exec mkdir -p -- "$@"
+ fi ;;
+*)
+ if mkdir -m "$dirmode" -p -- . 2>/dev/null; then
+ echo "mkdir -m $dirmode -p -- $*"
+ exec mkdir -m "$dirmode" -p -- "$@"
+ fi ;;
+esac
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp"
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ else
+ if test ! -z "$dirmode"; then
+ echo "chmod $dirmode $pathcomp"
+
+ lasterr=""
+ chmod "$dirmode" "$pathcomp" || lasterr=$?
+
+ if test ! -z "$lasterr"; then
+ errstatus=$lasterr
+ fi
+ fi
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 3
+# End:
+# mkinstalldirs ends here
diff --git a/ospf6d/.cvsignore b/ospf6d/.cvsignore
new file mode 100644
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 <jardin@6wind.com>
+
+ * ospf6_interface.c: update link-local address on interface creation.
+
+2002-11-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_asbr.c: apply MinLSInterval to AS-External-LSA origination.
+ * ospf6_lsa.c: change not to issue flooding caused by expire event
+ when the received LSA is (already) MaxAge.
+ * ospf6_spf.c: fix a bug which is that ospf6d calculates
+ wrong nexthop when failed to find Link-LSA for the neighbor.
+ * ospf6_damp.c ospf6_dbex.c ospf6_neighbor.c ospf6_spf.c:
+ some clean up
+ * version: 0.9.6o
+
+2002-10-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_asbr.c: bug of failing ASE lsa refresh fixed.
+ * version: 0.9.6n
+
+2002-10-01 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_asbr.c: AS-External-LSA origination function
+ is re-written.
+ * ospf6_damp.[ch]: New feature that damps flaps is added.
+ * version: 0.9.6m
+
+2002-07-14 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_spf.c: unwanted assert() in ospf6_spf_nexthop_calculation()
+ is deleted.
+ * version: 0.9.6l
+
+2002-07-14 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_dbex.c: bug that ospf6d fails to refresh self-originated
+ LSA if he have not the LSA before has been fixed.
+ * ospf6_asbr.c: bug of failing removing ASE LSA when remove
+ message arrived from zebra has been fixed.
+ * version: 0.9.6k
+
+2002-07-13 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_zebra.c: bug reported [zebra 14642] fixed.
+ The bug was related to the synchronization between zebra
+ and ospf6d. Now synchronization will be correctly done.
+ * version: 0.9.6j
+
+2002-07-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsdb.c: bug fixed in ospf6_lsdb_type_router ().
+ * ospf6_dbex.c: because of retrans list structure changed
+ due to LSDB change, removal of old instance from retrans-list
+ is not necessary anymore. this caused crash but now fixed.
+ * version: 0.9.6i
+
+2002-07-07 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.93 released.
+
+2002-07-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsdb.c: entirely rewritten. now ospf6d uses
+ radix tree by using lib/table.[ch] for LSDB lookup.
+ * ospf6_abr.c, ospf6_asbr.c, ospf6_intra.c: hook changed
+ due to rewriting of lsdb module.
+ * ospf6_neighbor.c: lack of check existence and find correct
+ instance of the LSA which is going to be removed from neighbor's
+ retransmission was filled.
+ * version: 0.9.6h
+
+2002-07-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_intra.c: bug fix for Intra-route deletion.
+ * ospf6_route.c: bug fix for path comparison.
+ * version: 0.9.6g
+
+2002-06-28 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_route.c: some logs trying to find the situation
+ when assert occur are added. route duration statistics
+ added.
+ * ospf6_zebra.c: trying to fix the problem reported by
+ [zebra 14318] but not yet sure.
+ * version: 0.9.6f
+
+2002-06-25 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_intra.c: new file for management of intra-prefix LSA.
+ * ospf6_abr.c: inter area route calculation code added.
+ * version: 0.9.6e
+
+2002-06-22 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_asbr.c: All AS-External route was removed when
+ one of the ASBR path was gone, but the route from other ASBR
+ path should stay remained. this bug is fixed.
+ * version: 0.9.6d
+
+2002-06-22 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_route.c: route table calculation bug fixed. [zebra 14105]
+ * ospf6_spf.c, ospf6_route.c, etc.: log message cleaned up.
+ * version: 0.9.6c
+
+2002-04-27 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_route.c: [zebra 13514] bug fix.
+ thanks to Harald Koch.
+ * version: 0.9.6b
+
+2002-04-22 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_dump.c: fix bug of log function
+ * ospf6_area.c: fix bug of intra route deletion
+ * version: 0.9.6a
+
+2002-04-20 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * merged with "current" version.
+ * version: 0.9.6
+
+2001-03-11 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsdb.c ospf6_spf.c: log message changed for debug.
+
+2001-02-20 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * version: 0.9.5i
+
+ * ospf6_asbr.c: Added code that finds alternative
+ AS-External route when remove AS-External route.
+ This is temporary fix ...
+
+ * ospf6_redistribute.c: remove redistributed routes
+ immediately when 'no redistribute ...'
+
+2001-02-20 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * version: 0.9.5h
+
+ * ospf6_spf.c, ospf6_lsa.c: Change to originate Link-LSA on
+ point-to-point links.
+
+ * ospf6_message.c: Bug of log messages of self-originated
+ Hello packet fixed.
+
+2001-02-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * version: 0.9.5g
+ * ospf6_asbr.c: fix for the bug that AS-External route
+ is not get removed.
+
+2001-02-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsdb.c: crash bug while receiving wrong LSA scope bit
+ has been temporarily fixed
+
+2001-12-20 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_asbr.[ch]: The byte order bug in encoding/decoding
+ the bits/metric field in AS-External-LSA fixed.
+ Fixed to update E-bit in Router-LSA of itself.
+ Reported by Taisuke Sasaki ([zebra 11548]).
+
+ * README: updated.
+
+ * version: 0.9.5f
+
+2001-11-21 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_prefix.c: Intra-prefix-LSA bug fixed.
+ * ospf6_abr.[ch]: added (only just placeholder yet)
+
+2001-11-20 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_route.c: fix to overwrite a prefix when another
+ addition to the prefix is given. freeze function changed
+ not to remove routes by default.
+
+ * version: 0.9.5e
+
+2001-11-19 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * version: 0.9.5d
+
+ * ospf6_lsa.c ospf6_spf.c: SPF Calculations are now
+ scheduled by hook.
+
+ * ospf6_route.c: ospf6_route_add bug fix,
+ ospf6_route_remove_all corrected.
+
+2001-11-15 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_hook.[ch]: added.
+ * Almost half of the code has been rewritten.
+ especially, ospf6_route.[ch]. Hook call has been injected
+ much.
+ * ospf6_asbr.[ch]: added.
+
+2001-10-17 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_dbex.c: ospf6d was wrong to omit reoriginating
+ of LSA when the self-originated LSA was received from others.
+ fixed.
+ * ospf6d.h: version: 0.9.5c
+
+2001-10-16 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsa.c: 'force-prefix' was not executed. fixed.
+ * ospf6d.h: version: 0.9.5b
+
+2001-10-13 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_interface.c: 'passive-interface' is now moved to
+ 'ipv6 ospf6 passive' in INTERFACE NODE. 'prefix-list' which
+ specifies the filter prefix for connected address prefix also
+ moved to INTERFACE NODE as 'ipv6 ospf6 advertise prefix-list WORD'.
+ The old obsoleted commands are still acceptable though. New command
+ 'ipv6 ospf6 advertise force-prefix' added, which which tells ospf6d
+ to advertise rather prefix than stub local-address even on loopback
+ or pointopoint interfaces.
+
+ * ospf6_dump.c: 'ospf6 debug hello' -> 'ospf6 debug message hello'.
+ same for other message type. The older is still acceptable.
+
+ * ospf6_lsa.c: Changed AS-External generation to new one which uses
+ LSA hooks. Delete old garbage.
+
+2001-10-02 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6d.c: turn off and turn on sequence with
+ 'no interface' 'interface' cmds was not work. fixed.
+
+ * ospf6_lsa.c: generating Intra-Area-Prefix-LSA for stub
+ did not care duplicate prefixes. fixed.
+
+2001-09-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_message.c: There was a bug that prevent LSDB
+ to syncronize. It was a DbDesc packet bug that Slave
+ sends two different DbDesc packet on the same sequence
+ number. This cause many LSAs are dropped when Exchanging
+ LSDB, because the latter DbDesc packet that have the same
+ sequence number will be ignored as duplicate packet.
+ This seems to be exist at least before 0.9.4 version.
+ Now this is the most stable candidate.
+
+ * ospf6d.h: version 0.9.5a
+
+2001-09-06 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_zebra.c ospf6_spf.c ospf6_lsa.c :
+ delete nexthop check to certify the nexthop is Link-local address.
+ Suppress Link-LSA origination on links other than Broadcast.
+ SPF's nexthop calculation first checks linklocal address
+ in Link-LSA, then checks source address of neighbor's packets.
+
+ * ospf6_interface.c ospf6_ism.c ospf6_lsa.c ospf6_nsm.c:
+ intra-area-prefix-lsa origination func moved to new one.
+
+ * ospf6_interface.h ospf6d.[ch] ospf6_lsa.c:
+ interface_area_cmd now changed to have 'passive'
+ and 'prefix-list' option.
+
+ * ospf6_prefix.c:
+ clean up.
+
+2001-09-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_dbex.c ospf6_interface.c ospf6_ism.c ospf6_lsa.[ch]:
+ clean up and new LSA origination functions added.
+
+ * ospf6_route.c ospf6_lsdb.c: make vty function more
+ clean/understandable.
+
+ * ospf6d.h: version 0.9.5
+
+2001-08-24 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * ospf6_lsdb.c: Use IS_LSA_MAXAGE macro instead of
+ ospf6_lsa_is_maxage.
+
+ * ospf6_lsa.h (IS_LSA_MAXAGE): Add new macro to check MaxAge.
+
+2001-08-21 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsdb.c: if There's no previous prefix
+ ospf6d was wrongly not calculate the prefix.
+ this reported by (v6 16029) is fixed.
+
+ * ospf6_neighbor.c: Instance of LSA Summary included
+ in DbDesc packet was wrongly freed. The bug cause
+ malformed DbDesc, ExChange <-> ExStart flapping,
+ and then crash.
+
+ * ospf6d.h: version 0.9.4
+
+2001-08-21 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_route.[ch]: Showing format is changed.
+ 'show ipv6 route ospf6' -> 'show ipv6 ospf6 route'
+ 'show ipv6 route ospf6 external' ->
+ 'show ipv6 ospf6 route redistribute'
+
+ * ospf6_lsdb.c ospf6_lsa.c ospf6_neighbor.c ospf6_interface.c:
+ memory leak in LS list fixed.
+
+ * all: clean up
+
+ * ospf6d.h: version 0.9.3
+
+2001-08-20 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * ospf6d.c (ospf6_timeval_sub_equal): Remove function.
+
+ * ospf6_spf.c (ospf6_timeval_cmp): Rewrite ospf6_timeval_cmp().
+ (ospf6_timeval_add_equal): Function moved from ospf6d.c
+
+2001-08-19 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92a released.
+
+2001-08-15 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92 released.
+
+2001-08-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsdb.c ospf6_neighbor.c:
+ LSDB function/structure and LS list function has been rewritten.
+ memory leak has been decreased.
+
+ * ospf6_lsa.[ch] ospf6_dbex.c: garbage code has been deleted.
+
+ * ospf6d.h: version 0.9.2
+
+2001-08-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_dbex.c ospf6_lsdb.c:
+ Retransmition list had a critical bug that breaks LSDB
+ synchronization. When new LSA be added to retrans-list,
+ old must be removed, but it was not. So new LSA dropped,
+ and LSA Acknowledgement did not work. The bug was fixed.
+
+ * ospf6d.h: version 0.9.1
+
+2001-06-20 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_spf.c: crash bug fix in temporary treat code for
+ Router-LSA whose LS-ID != 0
+
+ * ospf6_dbex.c: RFC2328 13.(4) was wrongly coded.
+ (4) Else if the LSA's LS age is equal to MaxAge, and there is
+ currently *NO* instance of the LSA in the router's link state
+ ...
+
+ * ospf6_lsa.c: RFC2328 13.1 checksum tie breaker
+ had been neglected, and has just added now.
+
+ * ospf6d.h: version 0.9.0
+ ospf6d expected to work with hitachi gr2000 from these fixes.
+
+2001-06-12 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsa.c: Fix bug in creating Intra-Area-Prefix-LSA.
+ DR was mis-include others prefixes advertised by their Link-LSA.
+
+ * ospf6_route.c: Fix bug in calculating intra area routes.
+ Not all prefixes in Intra-Area-Prefix-LSA was calculated.
+
+ * ospf6_spf.c:
+ Changed to quit when a error occured in calculating SPF tree.
+ Very messy hack for the bug reported by [zebra 8807]. This
+ is not tested yet.
+ Changed to quit SPF calculation when a nexthop calculation
+ errors.
+
+ * ospf6_zebra.c:
+ Support for interface address deletion.
+
+ * ospf6d.h:
+ version: 0.8.y
+
+2001-04-18 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6d.h
+ Due to previous change (DR Election algorithm changed),
+ backward compatibility will be lost from this version.
+ version: 0.8.x
+
+2001-04-18 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_message.c ospf6_ism.c:
+ Bug of router_id comparison
+
+2001-04-17 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_dbex.c: ospf6_dbex_is_maxage_to_be_dropped() had
+ some bug causing Loading state lasts long.
+ version: 0.8.v
+
+2001-04-08 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_route.c: BUG in AS-External route calculation fixed.
+ It was using OLD LSDB...
+ Version: 0.8.u-
+
+2001-04-08 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_area.c, ospf6_dbex.c, ospf6_interface.c,
+ ospf6_lsa.c, ospf6_lsdb.c, ospf6_lsdb.h, ospf6_message.c,
+ ospf6_neighbor.c, ospf6_neighbor.h, ospf6_nsm.c,
+ ospf6_redistribute.c, ospf6_route.c, ospf6_spf.c:
+ Delete old LSDB function.
+
+ * ospf6d.h:
+ Version: 0.8.u
+
+2001-04-05 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_area.c, ospf6_area.h, ospf6_dbex.c, ospf6_interface.c,
+ ospf6_interface.h, ospf6_lsa.c, ospf6_lsdb.c, ospf6_lsdb.h,
+ ospf6_message.c, ospf6_nsm.c, ospf6_redistribute.c, ospf6_route.c,
+ ospf6_spf.c, ospf6_top.c, ospf6_top.h, ospf6d.h:
+ Changed to use New LSDB.
+ Version: 0.8.t
+
+2001-04-02 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsa.c:
+ Interface stub check in Intra-Area-Prefix-LSA origination
+ was wrong. - fixed.
+
+ * ospf6_area.h, ospf6_dbex.c, ospf6_interface.c,
+ ospf6_interface.h, ospf6_lsa.c, ospf6_lsa.h, ospf6_lsdb.c,
+ ospf6_message.c, ospf6_neighbor.c, ospf6_nsm.c,
+ ospf6_redistribute.c, ospf6_top.c, ospf6_top.h, ospf6d.c:
+ New LSDB functions, but not changed to be used.
+
+ * ospf6d.h:
+ Version: 0.8.s
+
+2001-03-28 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_area.c ospf6_area.h ospf6_dbex.c ospf6_dump.c
+ ospf6_interface.c ospf6_interface.h ospf6_lsa.c
+ ospf6_message.c ospf6_redistribute.c ospf6_spf.c ospf6_top.c
+ ospf6_top.h ospf6_zebra.c ospf6d.c ospf6d.h: cleaning.
+
+2001-03-24 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6d.h:
+ version: 0.8.r
+
+ * ospf6_neighbor.[ch], ospf6_lsa.[ch]:
+ just clean up and log clearify.
+
+ * ospf6_message.[ch]:
+ Packet receiving function and dumping OSPFv3 packet has been
+ changed simple and clean.
+
+ * ospf6_dbex.[ch], ospf6_interface.[ch], ospf6_lsdb.[ch],
+ ospf6_neighbor.[ch], ospf6_nsm.[ch]:
+ LSList(i.e. summary list, request list, retrans list, etc) have
+ been rewritten based on new LSDB module. The main LSDB have not
+ yet shifted to this new module, but will shift eventually.
+ This change expected to resolve the problem that the ospf6d keeps
+ on sending redundant LSUpdate/LSAck.
+
+ * ospf6_interface.c: changed default MTU from 1500 to 1280.
+ It was possible that the ospf6d could not send packet (e.g.
+ LSUpdate in response to LSReq in my case) when the packet
+ size accidentally reached near 1500 (I was forget about IP
+ header :p). It is a bit illegal to set MTU 1280 constantly,
+ but I failed once with I/F MTU from kernel (through zebra),
+ and thinks that 1280 is more stable than kernel variable.
+ Comments will be appriciated.
+
+2001-03-15 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_dbex.c, ospf6_interface.c, ospf6_ism.c, ospf6_lsdb.[ch],
+ ospf6_neighbor.c, ospf6_spf.c, ospf6d.c:
+ Fix for crash. ospf6d has ever been crashing when
+ 'no interface' command executed, and when starting up with
+ the configuration which does not include 'router ospf6'.
+ these has been fixed.
+
+2001-02-24 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsa.c, ospf6_message.c:
+ LSA summary (exchanged while Adjacency bring up) may expire
+ (may reach MaxAge). Handling this has been added but
+ it's a little bit quick hack.
+
+ * ospf6_message.c:
+ Thread chain bug fixed. Read network thread chain has been cut
+ when receive packets on not-enabled interface. this was wrong
+ and fixed.
+
+2001-02-24 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_message.c:
+ I/F MTU check part on sending packet had some bug, and it's fixed.
+ Ospf6d has believed a value from zebra as I/F MTU, but from now
+ I/F MTU is set to constant 1500. This is workaround for ATM.
+
+2001-02-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.91 is released.
+
+2001-01-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * just code clean up of almost all module.
+ * ospf6_dump.c, ospf6_lsa.c: file dependency.
+ * ospf6_mesg.[ch]: changed filename to ospf6_message.[ch]
+
+2001-01-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.90 is released.
+
+2001-01-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_mesg.c,ospf6_lsa.c: doubly cancel thread bug fixed.
+ version 0.8.k CRASHed for this.
+ * ospf6_lsa.c: bug of logging fixed.
+ version: 0.8.l
+
+2001-01-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_neighbor.c: fix typo when trying to delete
+ MaxAge AS-External LSA. MaxAge LSA remaining bug is expected
+ to be fixed.
+ version: 0.8.k
+
+2001-01-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_mesg.c: add I/F Mtu check for sending LS Update.
+
+ * ospf6_dbex.c, ospf6_mesg.c, ospf6_neighbor.c, ospf6_neighbor.h,
+ ospf6_spf.c: Changed type of hisaddr field in ospf6_neighbor
+ structure, from sockaddr_in6 to in6_addr. No protocol/processing
+ changed.
+
+2001-01-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_mesg.c, ospf6_neighbor.[ch]: Speed up of
+ Database Exchange.
+ version: 0.8.j
+
+ Because the LS Request list was checked only when attempt
+ to send (retransmit) LS Request packet, Loading state lasted
+ long (for RxmtInterval) unexpectedly. This was fixed; LS Request
+ packet will be send as soon as one received a LS Update packet.
+
+2001-01-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6d.h (OSPF6_VTYSH_PATH): Change "/tmp/ospf6d" to
+ /tmp/.ospf6d".
+
+2000-12-29 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_dump.[ch]: simplified.
+
+2000-12-19 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_route.c: Fix bug of using unavailable route.
+ version: 0.8.d
+
+2000-11-30 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_spf.c: calculate statistics. version: 0.8.d
+
+2000-11-26 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_mesg.c, ospf6_nsm.c: LSDB sync bug fixed.
+ version: 0.8.c
+
+2000-11-26 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_dbex.c: Start debugging and cleaning.
+
+ * ospf6_area.c, ospf6_dbex.c, ospf6_interface.c, ospf6_lsa.c,
+ ospf6_proto.c, ospf6_top.c: add some function to clarify codes.
+
+2000-11-26 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_spf.c: Delete old garbage (which was enclosed by #if 0)
+
+ * ospf6_redistribute.c: "redistribute ospf6" was generated in
+ "router ospf6" in config file. It is a bug, and fixed.
+ wrong warning message was deleted.
+
+ * ospf6_main.c: If daemon mode, ospf6d was silent even if
+ the config file was wrong. It is a bug, and fixed.
+
+ * ospf6_route.c, ospf6_zebra.c: Zebra syncronization method
+ has been changed. delete garbages. allow nexthop of :: in case
+ of connected route.
+
+ * ospf6_dbex.c: Delete annoying log messages.
+
+ * ospf6_lsa.c: Changed string for LSA log.
+
+2000-11-21 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_spf.c: some careless bug fixed.
+
+ * ospf6_route.c: changed not to send garbage route
+ whose nexthop is not linklocal address.
+
+2000-11-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_rtable.c: renamed to ospf6_route.c
+ whole functionality has been rewritten as new code.
+ new functions not yet installs routes; the old
+ functions still remains. cleaning log messages.
+
+ * ospf6_spf.c: whole functionality has been rewritten
+ as new code. new command "show ipv6 ospf6 spf node",
+ "show ipv6 ospf6 spf tree", "show ipv6 ospf6 spf table"
+ has been added. Memory leak was fixed. cleaning log messages.
+
+ * ospf6d version: 0.7.c
+
+2000-10-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.89 is released.
+
+2000-09-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_lsdb.c (ospf6_lsdb_remove_maxage_lsa): Fix compile
+ warnings.
+
+2000-08-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.88 is released.
+
+2000-08-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_rtable.h (struct ospf6_nexthop): Change ifindex type from
+ unsigned long to unsigned int.
+
+2000-04-28 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6d.h: Include some headers for avoid warning.
+
+ * ospf6_routemap.h: Add newfile.
+
+1999-11-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_network.c: Respect IPV6_JOIN_GROUP and IPV6_LEAVE_GROUP
+ rather than RFC2133.
+
+1999-10-21 Jun-ichiro itojun Hagino <itojun@itojun.org>
+
+ * ospf6_network.c (ospf6_ipv6_decode_ipv4): Fix bug of conversion
+ from IPv4 Mapped Address to IPv4 address.
+
+1999-08-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_lsa.c (construct_link_lsa): Enclose KAME specific part by
+ #ifdef/#endif.
+
+1999-07-29 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_mesg.c: add new message process function.
+
+1999-07-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_main.c (sighup): Call of log_rotate() removed.
+
+1999-07-24 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ ospf6_dbex.{c,h}: variable "acknowledge" has been deleted.
+
+1999-07-22 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * *.{c,h}: lsa data structure has been drastically
+ changed.
+
+1999-07-16 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * *.{c,h}: bug of updating LSA's which is self
+ originated has been fixed.
+
+1999-07-14 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * *.{c,h} : log clean up.
+
+1999-07-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6d.c (ospf6_init): Change to use install_default.
+
+1999-07-03 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_rtable.c (nexthop_*): added some function that handles
+ new nexthop structure.
+
+1999-07-01 Rick Payne <rickp@rossfell.co.uk>
+
+ * ospf6_zebra.c (ospf6_zebra_init): Install standard commands to
+ ZEBRA_NODE.
+
+1999-06-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_rtable.h: added for new routing table of ospf6d
+
+1999-05-14 Stephen R. van den Berg <srb@cuci.nl>
+
+ * ospf6_main.c (signal_init): SIGTERM call sigint.
+ (sigint): Loggging more better message.
+
+1999-05-13 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ *ospf6_spf.c (get_prefix_lsa_of_vertex): bug fix about network vertex.
+
+1999-05-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_network.c (send_linkstate_ack): Check HAVE_SIN6_SCOPE_ID
+ is defined.
+ * ospf6_mesg.c (make_hello): Likewise.
+ * ospf6_lsa.c (lsa_flood): Likewise.
+
+1999-05-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_spf.c, etc: Many bug fix.
+ intra-area-prefix-LSA treatment changed.
+ network byte order of neighbor ifid changed.
+
+1999-05-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_zebra.h (struct zebra): Add hitory entry to structure.
+
+1999-05-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_main.c (main): Add KAME check for binding vty socket.
+ (main): Delete old interface get routine garbage.
+
+ * ospf6d.c: Change all `show ip6' statement to `show ipv6'.
+ (show_ipv6_ospf6_requestlist): Add description.
+
+1999-05-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsa.c, etc: Many bug fix, now two routers
+ on the same segment can become FULL neighbor state
+ each other.
+
+1999-05-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am: Add file dependency.
+ (depend): Add target.
+
+1999-05-02 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * Clean up and fix have been almost done. This code
+ now testing stage of Intra area routing.
+
+ * Configuration Vty become more similar to Cisco.
+
+1999-04-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Trim training newline from zlog format arguemnt.
+
+ * ospf6_dump.c (ospf6_err): Commented out ospf6_err and
+ ospf6_warn. Same kind of function should be implemented as
+ zlog_err or zlog_warn or someting.
+
+ * ospf6d.c: Change OSPF_NODE to OSPF6_NODE.
+ Change OSPF_DEFAULT_CONFIG to OSPF6_DEFAULT_CONFIG.
+
+
+1999-04-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_mesg.c (make_hello): Add check of SIN6_LEN
+
+1999-04-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_neighbor.c: Change list_clear_all to list_delete_all_node.
+ Remove list_delete_all fuction and use lib/linklist.c's one.
+
+1999-04-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * mcast_join(),mcast_leave()'s argument socket length is removed.
+
+1999-04-08 <kunihiro@zebra.org>
+
+ * ospf6_zebra.h (ospf_zebra_read): Fix typo.
+
+ * ospf6_interface.h: Tempolary add struct rt_addrinfo.
+
+1999-03-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Merge from ospfd-zebra-990303 codes.
+
+1999-02-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.in: add new file.
+
+ * Makefile.am: @INCLUDES@ is added for OS/library specific IPv6
+ directory search.
+
+ * Import files from Yasuhiro Ohara <yasu@sfc.wide.ad.jp>'s ospfd.
+ Impterted files are:
+ Makefile.am, ospf_area.h, ospf_dump.c, ospf_interface.c,
+ ospf_interface.h, ospf_lsa.c, ospf_lsa.h, ospf_main.c,
+ ospf_mesg.c, ospf_mesg.h, ospf_neighbor.c,
+ ospf_neighbor.h,ospf_network.c, ospf_network.h, ospf_proto.h,
+ ospf_spf.c, ospf_spf.h, ospf_types.h, ospfd.c, ospfd.h
diff --git a/ospf6d/Makefile.am b/ospf6d/Makefile.am
new file mode 100644
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
+<yasu@sfc.wide.ad.jp> by E-mail. Patches will be appriciated.
+
+ospf6d's vty port was default to 2606/tcp.
+Use commands below.
+
+VIEW NODE:
+ show ipv6 ospf6
+ To see Router-ID, uptime of ospf6d, some statistics.
+
+ show ipv6 ospf6 database ...
+ This command shows LSA database. You can specify
+ LS-type/LS-ID/Advertising-Router of LSAs. '*' is recognized.
+
+ show ipv6 ospf6 interface ...
+ To see the status of the OSPF interface, and the configuration
+ like interface costs.
+
+ show ipv6 ospf6 neighbor ...
+ Shows state of neighbors and choosed (Backup) DR on the I/F.
+
+ show ipv6 ospf6 route (X::X)
+ This command shows internal routing table of the ospf6d.
+ Routes not calculated by OSPFv3 (like connected routes)
+ are not shown. If Address is specified (X::X), shows the route
+ that the address matches.
+
+ show ipv6 ospf6 route redistribute (X::X)
+ Shows the routes advertised as AS-External routes by the router
+ itself. If Address is specified (X::X), shows the route
+ that the address matches.
+
+CONFIG NODE:
+ interface NAME
+ To enter INTERFACE NODE
+
+ router ospf6 ...
+ To enter OSPF6 NODE
+
+INTERFACE NODE:
+ ipv6 ospf6 cost COST
+ Sets the interface's output cost. default 1
+
+ ipv6 ospf6 hello-interval HELLOINTERVAL
+ Sets the interface's Hello Interval. default 10
+
+ ipv6 ospf6 dead-interval DEADINTERVAL
+ Sets the interface's Router Dead Interval. default 40
+
+ ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL
+ Sets the interface's Rxmt Interval. default 5
+
+ ipv6 ospf6 priority PRIORITY
+ Sets the interface's Router Priority. default 1
+
+ ipv6 ospf6 transmit-delay TRANSMITDELAY
+ Sets the interface's Inf-Trans-Delay. default 1
+
+OSPF6 NODE:
+ router-id A.B.C.D
+ Sets the router's Router-ID
+
+ interface NAME area AREA
+ Binds interface to specified Area, and start
+ sending OSPFv3 packets.
+
+Sample configuration is in ospf6d.conf.sample.
+
+--
+Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+Kunihiro Ishiguro <kunihiro@zebra.org>
+
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
new file mode 100644
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 <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "command.h"
+#include "vty.h"
+#include "routemap.h"
+#include "table.h"
+#include "plist.h"
+#include "thread.h"
+
+#include "ospf6_prefix.h" /* xxx for ospf6_asbr.h */
+#include "ospf6_lsa.h" /* xxx for ospf6_asbr.h */
+#include "ospf6_route.h" /* xxx for ospf6_asbr.h, ospf6_zebra.h */
+#include "ospf6_zebra.h"
+#include "ospf6_asbr.h"
+#include "ospf6_damp.h"
+#include "ospf6_top.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_proto.h"
+
+extern struct thread_master *master;
+
+struct route_table *external_table;
+struct
+{
+ char *name;
+ struct route_map *map;
+} rmap [ZEBRA_ROUTE_MAX];
+
+static u_int32_t link_state_id = 0;
+
+char *
+zroute_name[] =
+{
+ "system", "kernel", "connected", "static",
+ "rip", "ripng", "ospf", "ospf6", "bgp", "unknown"
+};
+char *
+zroute_abname[] =
+{
+ "X", "K", "C", "S", "R", "R", "O", "O", "B", "?"
+};
+
+#define ZROUTE_NAME(x) \
+ (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \
+ zroute_name[(x)] : zroute_name[ZEBRA_ROUTE_MAX])
+
+#define ZROUTE_ABNAME(x) \
+ (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \
+ zroute_abname[(x)] : zroute_abname[ZEBRA_ROUTE_MAX])
+
+/* redistribute function */
+void
+ospf6_asbr_routemap_set (int type, char *mapname)
+{
+ if (rmap[type].name)
+ free (rmap[type].name);
+
+ rmap[type].name = strdup (mapname);
+ rmap[type].map = route_map_lookup_by_name (mapname);
+}
+
+void
+ospf6_asbr_routemap_unset (int type)
+{
+ if (rmap[type].name)
+ free (rmap[type].name);
+ rmap[type].name = NULL;
+ rmap[type].map = NULL;
+}
+
+void
+ospf6_asbr_routemap_update ()
+{
+ int i;
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ {
+ if (rmap[i].name)
+ rmap[i].map = route_map_lookup_by_name (rmap[i].name);
+ else
+ rmap[i].map = NULL;
+ }
+}
+
+DEFUN (ospf6_redistribute,
+ ospf6_redistribute_cmd,
+ "redistribute (static|kernel|connected|ripng|bgp)",
+ "Redistribute\n"
+ "Static route\n"
+ "Kernel route\n"
+ "Connected route\n"
+ "RIPng route\n"
+ "BGP route\n"
+ )
+{
+ int type = 0;
+
+ if (strncmp (argv[0], "sta", 3) == 0)
+ type = ZEBRA_ROUTE_STATIC;
+ else if (strncmp (argv[0], "ker", 3) == 0)
+ type = ZEBRA_ROUTE_KERNEL;
+ else if (strncmp (argv[0], "con", 3) == 0)
+ type = ZEBRA_ROUTE_CONNECT;
+ else if (strncmp (argv[0], "rip", 3) == 0)
+ type = ZEBRA_ROUTE_RIPNG;
+ else if (strncmp (argv[0], "bgp", 3) == 0)
+ type = ZEBRA_ROUTE_BGP;
+
+ ospf6_zebra_no_redistribute (type);
+ ospf6_asbr_routemap_unset (type);
+ ospf6_zebra_redistribute (type);
+ return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_redistribute_routemap,
+ ospf6_redistribute_routemap_cmd,
+ "redistribute (static|kernel|connected|ripng|bgp) route-map WORD",
+ "Redistribute\n"
+ "Static routes\n"
+ "Kernel route\n"
+ "Connected route\n"
+ "RIPng route\n"
+ "BGP route\n"
+ "Route map reference\n"
+ "Route map name\n"
+ )
+{
+ int type = 0;
+
+ if (strncmp (argv[0], "sta", 3) == 0)
+ type = ZEBRA_ROUTE_STATIC;
+ else if (strncmp (argv[0], "ker", 3) == 0)
+ type = ZEBRA_ROUTE_KERNEL;
+ else if (strncmp (argv[0], "con", 3) == 0)
+ type = ZEBRA_ROUTE_CONNECT;
+ else if (strncmp (argv[0], "rip", 3) == 0)
+ type = ZEBRA_ROUTE_RIPNG;
+ else if (strncmp (argv[0], "bgp", 3) == 0)
+ type = ZEBRA_ROUTE_BGP;
+
+ ospf6_zebra_no_redistribute (type);
+ ospf6_asbr_routemap_set (type, argv[1]);
+ ospf6_zebra_redistribute (type);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf6_redistribute,
+ no_ospf6_redistribute_cmd,
+ "no redistribute (static|kernel|connected|ripng|bgp)",
+ NO_STR
+ "Redistribute\n"
+ "Static route\n"
+ "Kernel route\n"
+ "Connected route\n"
+ "RIPng route\n"
+ "BGP route\n"
+ )
+{
+ int type = 0;
+ struct route_node *node;
+ struct ospf6_external_route *route;
+ struct ospf6_external_info *info, *info_next = NULL;
+
+ if (strncmp (argv[0], "sta", 3) == 0)
+ type = ZEBRA_ROUTE_STATIC;
+ else if (strncmp (argv[0], "ker", 3) == 0)
+ type = ZEBRA_ROUTE_KERNEL;
+ else if (strncmp (argv[0], "con", 3) == 0)
+ type = ZEBRA_ROUTE_CONNECT;
+ else if (strncmp (argv[0], "rip", 3) == 0)
+ type = ZEBRA_ROUTE_RIPNG;
+ else if (strncmp (argv[0], "bgp", 3) == 0)
+ type = ZEBRA_ROUTE_BGP;
+
+ ospf6_zebra_no_redistribute (type);
+ ospf6_asbr_routemap_unset (type);
+
+ /* remove redistributed route */
+ for (node = route_top (external_table); node; node = route_next (node))
+ {
+ route = node->info;
+ if (! route)
+ continue;
+ for (info = route->info_head; info; info = info_next)
+ {
+ info_next = info->next;
+ if (info->type != type)
+ continue;
+ ospf6_asbr_route_remove (info->type, info->ifindex,
+ &route->prefix);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+
+int
+ospf6_redistribute_config_write (struct vty *vty)
+{
+ int i;
+
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ {
+ if (i == ZEBRA_ROUTE_OSPF6)
+ continue;
+
+ if (! ospf6_zebra_is_redistribute (i))
+ continue;
+
+ if (rmap[i].map)
+ vty_out (vty, " redistribute %s route-map %s%s",
+ ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE);
+ else
+ vty_out (vty, " redistribute %s%s",
+ ZROUTE_NAME(i), VTY_NEWLINE);
+ }
+
+ return 0;
+}
+
+void
+ospf6_redistribute_show_config (struct vty *vty)
+{
+ int i;
+
+ if (! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_SYSTEM) &&
+ ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_KERNEL) &&
+ ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_STATIC) &&
+ ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_RIPNG) &&
+ ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_BGP))
+ return;
+
+ vty_out (vty, " Redistributing External Routes from,%s", VTY_NEWLINE);
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ {
+ if (i == ZEBRA_ROUTE_OSPF6)
+ continue;
+ if (! ospf6_zebra_is_redistribute (i))
+ continue;
+
+ if (rmap[i].map)
+ vty_out (vty, " %s with route-map %s%s",
+ ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE);
+ else
+ vty_out (vty, " %s%s", ZROUTE_NAME(i), VTY_NEWLINE);
+ }
+}
+
+/* AS External LSA origination */
+int
+ospf6_asbr_external_lsa_originate (struct thread *thread)
+{
+ struct ospf6_external_info *info;
+ char buffer [MAXLSASIZE];
+ struct ospf6_lsa_as_external *e;
+ char *p;
+
+ info = THREAD_ARG (thread);
+
+ /* clear thread */
+ info->thread_originate = NULL;
+
+ if (info->is_removed)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char pbuf[64];
+ prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+ zlog_info ("ASBR: quit redistribution %s: state is down",
+ pbuf);
+ }
+ return 0;
+ }
+
+ /* prepare buffer */
+ memset (buffer, 0, sizeof (buffer));
+ e = (struct ospf6_lsa_as_external *) buffer;
+ p = (char *) (e + 1);
+
+ if (info->metric_type == 2)
+ SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type2 */
+ else
+ UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type1, default */
+
+ /* forwarding address */
+ if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding))
+ SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F);
+ else
+ UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F);
+
+ /* external route tag */
+ UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T);
+
+ /* set metric. note: related to E bit */
+ OSPF6_ASBR_METRIC_SET (e, info->metric);
+
+ /* prefixlen */
+ e->prefix.prefix_length = info->route->prefix.prefixlen;
+
+ /* PrefixOptions */
+ e->prefix.prefix_options = info->prefix_options;
+
+ /* don't use refer LS-type */
+ e->prefix.prefix_refer_lstype = htons (0);
+
+ /* set Prefix */
+ memcpy (p, &info->route->prefix.u.prefix6,
+ OSPF6_PREFIX_SPACE (info->route->prefix.prefixlen));
+ ospf6_prefix_apply_mask (&e->prefix);
+ p += OSPF6_PREFIX_SPACE (info->route->prefix.prefixlen);
+
+ /* Forwarding address */
+ if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F))
+ {
+ memcpy (p, &info->forwarding, sizeof (struct in6_addr));
+ p += sizeof (struct in6_addr);
+ }
+
+ /* External Route Tag */
+ if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T))
+ {
+ /* xxx */
+ }
+
+ ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+ htonl (info->id), ospf6->router_id,
+ (char *) buffer, p - buffer, ospf6);
+ return 0;
+}
+
+int
+ospf6_asbr_schedule_external (void *data)
+{
+ struct ospf6_external_info *info = data;
+ u_long elasped_time, time = 0;
+
+ if (info->thread_originate)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char pbuf[64];
+ prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+ zlog_info ("ASBR: schedule redistribution %s: another thread",
+ pbuf);
+ }
+ return 0;
+ }
+
+ elasped_time =
+ ospf6_lsa_has_elasped (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+ htonl (info->id), ospf6->router_id, ospf6);
+ if (elasped_time < OSPF6_MIN_LS_INTERVAL)
+ time = OSPF6_MIN_LS_INTERVAL - elasped_time;
+ else
+ time = 0;
+
+ //if (IS_OSPF6_DUMP_ASBR)
+ {
+ char pbuf[64];
+ prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+ zlog_info ("ASBR: schedule redistribution %s as LS-ID %ld after %lu sec",
+ pbuf, (u_long) info->id, time);
+ }
+
+ if (time)
+ info->thread_originate =
+ thread_add_timer (master, ospf6_asbr_external_lsa_originate, info, time);
+ else
+ info->thread_originate =
+ thread_add_timer (master, ospf6_asbr_external_lsa_originate, info, 0);
+
+ return 0;
+}
+
+int
+ospf6_asbr_external_lsa_flush (void *data)
+{
+ struct ospf6_lsa *lsa = data;
+ if (lsa)
+ ospf6_lsa_premature_aging (lsa);
+ return 0;
+}
+
+int
+ospf6_asbr_external_lsa_refresh (void *data)
+{
+ struct ospf6_lsa *lsa = data;
+ struct ospf6_lsa_as_external *e;
+ struct prefix prefix;
+ struct route_node *node;
+ struct ospf6_external_route *route;
+ struct ospf6_external_info *info;
+
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: refresh %s", lsa->str);
+
+ e = (struct ospf6_lsa_as_external *) (lsa->header + 1);
+ ospf6_prefix_in6_addr (&e->prefix, &prefix.u.prefix6);
+ prefix.prefixlen = e->prefix.prefix_length;
+ prefix.family = AF_INET6;
+ apply_mask_ipv6 ((struct prefix_ipv6 *) &prefix);
+
+ node = route_node_lookup (external_table, &prefix);
+ if (! node || ! node->info)
+ {
+ char pname[64];
+
+ prefix2str (&prefix, pname, sizeof (pname));
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: could not find %s: premature age", pname);
+ ospf6_lsa_premature_aging (lsa);
+ return 0;
+ }
+
+ /* find external_info */
+ route = node->info;
+ for (info = route->info_head; info; info = info->next)
+ {
+ if (lsa->header->id == htonl (info->id))
+ break;
+ }
+
+ if (info)
+ ospf6_asbr_schedule_external (info);
+ else
+ ospf6_lsa_premature_aging (lsa);
+
+ return 0;
+}
+
+void
+ospf6_asbr_route_add (int type, int ifindex, struct prefix *prefix,
+ u_int nexthop_num, struct in6_addr *nexthop)
+{
+ int ret;
+ struct route_node *node;
+ struct ospf6_external_route *route;
+ struct ospf6_external_info *info, tinfo;
+
+ if (! ospf6_zebra_is_redistribute (type))
+ return;
+
+ /* apply route-map */
+ memset (&tinfo, 0, sizeof (struct ospf6_external_info));
+ if (rmap[type].map)
+ {
+ ret = route_map_apply (rmap[type].map, prefix, RMAP_OSPF6, &tinfo);
+ if (ret == RMAP_DENYMATCH)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: denied by route-map %s", rmap[type].name);
+ return;
+ }
+ }
+
+ node = route_node_get (external_table, prefix);
+ route = node->info;
+
+ if (! route)
+ {
+ route = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
+ sizeof (struct ospf6_external_route));
+ memset (route, 0, sizeof (struct ospf6_external_route));
+
+ memcpy (&route->prefix, prefix, sizeof (struct prefix));
+
+ node->info = route;
+ route->node = node;
+ }
+
+ for (info = route->info_head; info; info = info->next)
+ {
+ if (info->type == type && info->ifindex == ifindex)
+ break;
+ }
+
+ if (! info)
+ {
+ info = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
+ sizeof (struct ospf6_external_info));
+ memset (info, 0, sizeof (struct ospf6_external_info));
+
+ info->route = route;
+ /* add tail */
+ info->prev = route->info_tail;
+ if (route->info_tail)
+ route->info_tail->next = info;
+ else
+ route->info_head = info;
+ route->info_tail = info;
+
+ info->id = link_state_id++;
+ }
+
+ /* copy result of route-map */
+ info->metric_type = tinfo.metric_type;
+ info->metric = tinfo.metric;
+ memcpy (&info->forwarding, &tinfo.forwarding,
+ sizeof (struct in6_addr));
+
+ info->type = type;
+ info->ifindex = ifindex;
+
+ if (nexthop_num && nexthop)
+ {
+ info->nexthop_num = nexthop_num;
+
+ if (info->nexthop)
+ XFREE (MTYPE_OSPF6_EXTERNAL_INFO, info->nexthop);
+
+ info->nexthop = (struct in6_addr *)
+ XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
+ nexthop_num * sizeof (struct in6_addr));
+ memcpy (info->nexthop, nexthop,
+ nexthop_num * sizeof (struct in6_addr));
+ }
+
+ info->is_removed = 0;
+
+ //if (IS_OSPF6_DUMP_ASBR)
+ {
+ char pbuf[64];
+ struct timeval now;
+ prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+ gettimeofday (&now, NULL);
+ zlog_info ("ASBR: start redistributing %s as LS-ID %ld: %ld.%06ld",
+ pbuf, (u_long) info->id, now.tv_sec, now.tv_usec);
+ }
+
+#ifdef HAVE_OSPF6_DAMP
+ ospf6_damp_event_up (OSPF6_DAMP_TYPE_ROUTE, prefix,
+ ospf6_asbr_schedule_external, info);
+#else /*HAVE_OSPF6_DAMP*/
+ ospf6_asbr_schedule_external (info);
+#endif /*HAVE_OSPF6_DAMP*/
+}
+
+void
+ospf6_asbr_route_remove (int type, int ifindex, struct prefix *prefix)
+{
+ struct route_node *node;
+ struct ospf6_external_route *route;
+ struct ospf6_external_info *info;
+ struct ospf6_lsa *lsa;
+
+ node = route_node_get (external_table, prefix);
+ route = node->info;
+
+ if (! route)
+ return;
+
+ for (info = route->info_head; info; info = info->next)
+ {
+ if (info->type == type && info->ifindex == ifindex)
+ break;
+ }
+
+ if (! info)
+ return;
+
+ //if (IS_OSPF6_DUMP_ASBR)
+ {
+ char pbuf[64];
+ struct timeval now;
+ prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+ gettimeofday (&now, NULL);
+ zlog_info ("ASBR: quit redistributing %s as LS-ID %ld: %ld.%06ld",
+ pbuf, (u_long) info->id, now.tv_sec, now.tv_usec);
+ }
+
+ if (info->thread_originate)
+ thread_cancel (info->thread_originate);
+ info->thread_originate = NULL;
+
+ lsa = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+ htonl (info->id), ospf6->router_id, ospf6);
+#ifdef HAVE_OSPF6_DAMP
+ ospf6_damp_event_down (OSPF6_DAMP_TYPE_ROUTE, &info->route->prefix,
+ ospf6_asbr_external_lsa_flush, lsa);
+#else /*HAVE_OSPF6_DAMP*/
+ ospf6_asbr_external_lsa_flush (lsa);
+#endif /*HAVE_OSPF6_DAMP*/
+
+#if 1
+ info->is_removed = 1;
+#else
+ /* remove from route */
+ if (info->prev)
+ info->prev->next = info->next;
+ else
+ info->route->info_head = info->next;
+ if (info->next)
+ info->next->prev = info->prev;
+ else
+ info->route->info_tail = info->prev;
+
+ /* if no info, free route */
+ if (! info->route->info_head && ! info->route->info_tail)
+ {
+ info->route->node->info = NULL;
+ free (info->route);
+ }
+
+ if (info->nexthop)
+ free (info->nexthop);
+ free (info);
+#endif /*0*/
+}
+
+void
+ospf6_asbr_external_lsa_add (struct ospf6_lsa *lsa)
+{
+ struct ospf6_lsa_as_external *external;
+ struct prefix_ls asbr_id;
+ struct ospf6_route_req asbr_entry;
+ struct ospf6_route_req request;
+
+ external = OSPF6_LSA_HEADER_END (lsa->header);
+
+ if (IS_LSA_MAXAGE (lsa))
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: maxage external lsa: %s seq: %lx",
+ lsa->str, (u_long)ntohl (lsa->header->seqnum));
+ ospf6_asbr_external_lsa_remove (lsa);
+ return;
+ }
+
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: new external lsa: %s seq: %lx",
+ lsa->str, (u_long)ntohl (lsa->header->seqnum));
+
+ if (lsa->header->adv_router == ospf6->router_id)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: my external LSA, ignore");
+ return;
+ }
+
+ if (OSPF6_ASBR_METRIC (external) == LS_INFINITY)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: metric is infinity, ignore");
+ return;
+ }
+
+ memset (&asbr_id, 0, sizeof (asbr_id));
+ asbr_id.family = AF_UNSPEC;
+ asbr_id.prefixlen = 64; /* xxx */
+ asbr_id.adv_router.s_addr = lsa->header->adv_router;
+
+ ospf6_route_lookup (&asbr_entry, (struct prefix *) &asbr_id,
+ ospf6->topology_table);
+
+ if (ospf6_route_end (&asbr_entry))
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char buf[64];
+ inet_ntop (AF_INET, &asbr_id.adv_router, buf, sizeof (buf));
+ zlog_info ("ASBR: router %s not found, ignore", buf);
+ }
+ return;
+ }
+
+ memset (&request, 0, sizeof (request));
+ request.route.type = OSPF6_DEST_TYPE_NETWORK;
+ request.route.prefix.family = AF_INET6;
+ request.route.prefix.prefixlen = external->prefix.prefix_length;
+ memcpy (&request.route.prefix.u.prefix6, (char *)(external + 1),
+ OSPF6_PREFIX_SPACE (request.route.prefix.prefixlen));
+
+ request.path.area_id = asbr_entry.path.area_id;
+ request.path.origin.type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL);
+ request.path.origin.id = lsa->header->id;
+ request.path.origin.adv_router = lsa->header->adv_router;
+ if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E))
+ {
+ request.path.type = OSPF6_PATH_TYPE_EXTERNAL2;
+ request.path.metric_type = 2;
+ request.path.cost = asbr_entry.path.cost;
+ request.path.cost_e2 = OSPF6_ASBR_METRIC (external);
+ }
+ else
+ {
+ request.path.type = OSPF6_PATH_TYPE_EXTERNAL1;
+ request.path.metric_type = 1;
+ request.path.cost = asbr_entry.path.cost
+ + OSPF6_ASBR_METRIC (external);
+ request.path.cost_e2 = 0;
+ }
+ request.path.prefix_options = external->prefix.prefix_options;
+
+ while (((struct prefix_ls *)&asbr_entry.route.prefix)->adv_router.s_addr ==
+ asbr_id.adv_router.s_addr &&
+ asbr_entry.route.type == OSPF6_DEST_TYPE_ROUTER)
+ {
+ memcpy (&request.nexthop, &asbr_entry.nexthop,
+ sizeof (struct ospf6_nexthop));
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char buf[64], nhop[64], ifname[IFNAMSIZ];
+ prefix2str (&request.route.prefix, buf, sizeof (buf));
+ inet_ntop (AF_INET6, &request.nexthop.address, nhop, sizeof (nhop));
+ if_indextoname (request.nexthop.ifindex, ifname);
+ zlog_info ("ASBR: add route: %s %s%%%s", buf, nhop, ifname);
+ }
+ ospf6_route_add (&request, ospf6->route_table);
+ ospf6_route_next (&asbr_entry);
+ }
+}
+
+void
+ospf6_asbr_external_lsa_remove (struct ospf6_lsa *lsa)
+{
+ struct ospf6_lsa_as_external *external;
+ struct prefix dest;
+ char buf[64];
+ struct ospf6_route_req request;
+
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: withdraw external lsa: %s seq: %lx",
+ lsa->str, (u_long)ntohl (lsa->header->seqnum));
+
+ if (lsa->header->adv_router == ospf6->router_id)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: my external LSA, ignore");
+ return;
+ }
+
+ external = OSPF6_LSA_HEADER_END (lsa->header);
+ memset (&dest, 0, sizeof (dest));
+ dest.family = AF_INET6;
+ dest.prefixlen = external->prefix.prefix_length;
+ memcpy (&dest.u.prefix6, (char *)(external + 1),
+ OSPF6_PREFIX_SPACE (dest.prefixlen));
+
+ ospf6_route_lookup (&request, &dest, ospf6->route_table);
+ if (ospf6_route_end (&request))
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ prefix2str (&dest, buf, sizeof (buf));
+ zlog_info ("ASBR: %s not found", buf);
+ }
+ return;
+ }
+
+ while (request.path.origin.id != lsa->header->id ||
+ request.path.origin.adv_router != lsa->header->adv_router)
+ {
+ if (prefix_same (&request.route.prefix, &dest) != 1)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: Can't find the entry matches the origin");
+ return;
+ }
+ ospf6_route_next (&request);
+ }
+ assert (request.path.origin.id == lsa->header->id);
+ assert (request.path.origin.adv_router == request.path.origin.adv_router);
+
+ while (request.path.origin.id == lsa->header->id &&
+ request.path.origin.adv_router == lsa->header->adv_router &&
+ prefix_same (&request.route.prefix, &dest) == 1)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char nhop[64], ifname[IFNAMSIZ];
+ prefix2str (&dest, buf, sizeof (buf));
+ inet_ntop (AF_INET6, &request.nexthop.address, nhop, sizeof (nhop));
+ if_indextoname (request.nexthop.ifindex, ifname);
+ zlog_info ("ASBR: remove route: %s %s%%%s", buf, nhop, ifname);
+ }
+
+ ospf6_route_remove (&request, ospf6->route_table);
+ ospf6_route_next (&request);
+ }
+}
+
+void
+ospf6_asbr_external_lsa_change (struct ospf6_lsa *old, struct ospf6_lsa *new)
+{
+ assert (old || new);
+
+ if (old == NULL)
+ ospf6_asbr_external_lsa_add (new);
+ else if (new == NULL)
+ ospf6_asbr_external_lsa_remove (old);
+ else
+ {
+ ospf6_route_table_freeze (ospf6->route_table);
+ ospf6_asbr_external_lsa_remove (old);
+ ospf6_asbr_external_lsa_add (new);
+ ospf6_route_table_thaw (ospf6->route_table);
+ }
+}
+
+void
+ospf6_asbr_asbr_entry_add (struct ospf6_route_req *topo_entry)
+{
+ struct ospf6_lsdb_node node;
+
+ struct prefix_ls *inter_router;
+ u_int32_t id, adv_router;
+
+ inter_router = (struct prefix_ls *) &topo_entry->route.prefix;
+ id = inter_router->id.s_addr;
+ adv_router = inter_router->adv_router.s_addr;
+
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char buf[64];
+ inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf));
+ zlog_info ("ASBR: new router found: %s", buf);
+ }
+
+ if (ntohl (id) != 0 ||
+ ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E))
+ {
+ zlog_warn ("ASBR: Inter topology table malformed");
+ return;
+ }
+
+ for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+ adv_router, ospf6->lsdb);
+ ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ ospf6_asbr_external_lsa_add (node.lsa);
+}
+
+void
+ospf6_asbr_asbr_entry_remove (struct ospf6_route_req *topo_entry)
+{
+ struct prefix_ls *inter_router;
+ u_int32_t id, adv_router;
+ struct ospf6_route_req request;
+
+ inter_router = (struct prefix_ls *) &topo_entry->route.prefix;
+ id = inter_router->id.s_addr;
+ adv_router = inter_router->adv_router.s_addr;
+
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char buf[64];
+ inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf));
+ zlog_info ("ASBR: router disappearing: %s", buf);
+ }
+
+ if (ntohl (id) != 0 ||
+ ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E))
+ {
+ zlog_warn ("ASBR: Inter topology table malformed");
+ }
+
+ for (ospf6_route_head (&request, ospf6->route_table);
+ ! ospf6_route_end (&request);
+ ospf6_route_next (&request))
+ {
+ if (request.path.type != OSPF6_PATH_TYPE_EXTERNAL1 &&
+ request.path.type != OSPF6_PATH_TYPE_EXTERNAL2)
+ continue;
+ if (request.path.area_id != topo_entry->path.area_id)
+ continue;
+ if (request.path.origin.adv_router != topo_entry->path.origin.adv_router)
+ continue;
+ if (memcmp (&topo_entry->nexthop, &request.nexthop,
+ sizeof (struct ospf6_nexthop)))
+ continue;
+
+ ospf6_route_remove (&request, ospf6->route_table);
+ }
+}
+
+int
+ospf6_asbr_external_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+ struct ospf6_lsa_as_external *external;
+ char buf[128], *ptr;
+ struct in6_addr in6;
+
+ assert (lsa->header);
+ external = (struct ospf6_lsa_as_external *)(lsa->header + 1);
+
+ /* bits */
+ snprintf (buf, sizeof (buf), "%s%s%s",
+ (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E) ?
+ "E" : "-"),
+ (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F) ?
+ "F" : "-"),
+ (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T) ?
+ "T" : "-"));
+
+ vty_out (vty, " Bits: %s%s", buf, VTY_NEWLINE);
+ vty_out (vty, " Metric: %5lu%s", (u_long)OSPF6_ASBR_METRIC (external),
+ VTY_NEWLINE);
+
+ ospf6_prefix_options_str (external->prefix.prefix_options,
+ buf, sizeof (buf));
+ vty_out (vty, " Prefix Options: %s%s", buf, VTY_NEWLINE);
+
+ vty_out (vty, " Referenced LSType: %d%s",
+ ntohs (external->prefix.prefix_refer_lstype), VTY_NEWLINE);
+
+ ospf6_prefix_in6_addr (&external->prefix, &in6);
+ inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
+ vty_out (vty, " Prefix: %s/%d%s",
+ buf, external->prefix.prefix_length, VTY_NEWLINE);
+
+ /* Forwarding-Address */
+ if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F))
+ {
+ ptr = ((char *)(external + 1))
+ + OSPF6_PREFIX_SPACE (external->prefix.prefix_length);
+ inet_ntop (AF_INET6, (struct in6_addr *) ptr, buf, sizeof (buf));
+ vty_out (vty, " Forwarding-Address: %s%s", buf, VTY_NEWLINE);
+ }
+
+ return 0;
+}
+
+void
+ospf6_asbr_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new)
+{
+ if (old)
+ ospf6_asbr_external_lsa_remove (old);
+ if (new && ! IS_LSA_MAXAGE (new))
+ ospf6_asbr_external_lsa_add (new);
+}
+
+void
+ospf6_asbr_register_as_external ()
+{
+ struct ospf6_lsa_slot slot;
+
+ memset (&slot, 0, sizeof (slot));
+ slot.type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL);
+ slot.name = "AS-External";
+ slot.func_show = ospf6_asbr_external_show;
+ slot.func_refresh = ospf6_asbr_external_lsa_refresh;
+ ospf6_lsa_slot_register (&slot);
+
+ ospf6_lsdb_hook[OSPF6_LSA_TYPE_AS_EXTERNAL & OSPF6_LSTYPE_CODE_MASK].hook =
+ ospf6_asbr_database_hook;
+}
+
+void
+ospf6_asbr_external_info_show (struct vty *vty,
+ struct ospf6_external_info *info)
+{
+ char prefix_buf[64], id_buf[16];
+ struct in_addr id;
+
+ if (info->is_removed)
+ return;
+
+ id.s_addr = ntohl (info->id);
+ inet_ntop (AF_INET, &id, id_buf, sizeof (id_buf));
+ prefix2str (&info->route->prefix, prefix_buf, sizeof (prefix_buf));
+ vty_out (vty, "%s %-32s %3d %-15s %3d %lu(type-%d)%s",
+ ZROUTE_ABNAME(info->type), prefix_buf, info->ifindex, id_buf,
+ info->nexthop_num, (u_long) info->metric, info->metric_type,
+ VTY_NEWLINE);
+}
+
+void
+ospf6_asbr_external_route_show (struct vty *vty,
+ struct ospf6_external_route *route)
+{
+ struct ospf6_external_info *info;
+ for (info = route->info_head; info; info = info->next)
+ ospf6_asbr_external_info_show (vty, info);
+}
+
+DEFUN (show_ipv6_route_ospf6_external,
+ show_ipv6_route_ospf6_external_cmd,
+ "show ipv6 ospf6 route redistribute",
+ SHOW_STR
+ IP6_STR
+ ROUTE_STR
+ OSPF6_STR
+ "redistributing External information\n"
+ )
+{
+ struct route_node *node;
+ struct ospf6_external_route *route;
+
+ vty_out (vty, "%s %-32s %3s %-15s %3s %s%s",
+ " ", "Prefix", "I/F", "LS-Id", "#NH", "Metric",
+ VTY_NEWLINE);
+ for (node = route_top (external_table); node; node = route_next (node))
+ {
+ route = node->info;
+ if (route)
+ ospf6_asbr_external_route_show (vty, route);
+ }
+ return CMD_SUCCESS;
+}
+
+void
+ospf6_asbr_init ()
+{
+ external_table = route_table_init ();
+ link_state_id = 0;
+
+ ospf6_asbr_register_as_external ();
+
+ install_element (VIEW_NODE, &show_ipv6_route_ospf6_external_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_route_ospf6_external_cmd);
+ install_element (OSPF6_NODE, &ospf6_redistribute_cmd);
+ install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd);
+ install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd);
+}
+
+
diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h
new file mode 100644
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 <zebra.h>
+#include "ospf6_bintree.h"
+
+static struct bintree_node *
+bintree_lookup_node_min (struct bintree_node *subroot)
+{
+ struct bintree_node *node;
+
+ if (subroot == NULL)
+ return NULL;
+
+ node = subroot;
+ while (node->bl_left)
+ node = node->bl_left;
+ return node;
+}
+
+static struct bintree_node *
+bintree_lookup_node_max (struct bintree_node *subroot)
+{
+ struct bintree_node *node;
+
+ assert (subroot != NULL);
+ node = subroot;
+ while (node->bl_right)
+ node = node->bl_right;
+ return node;
+}
+
+void *
+bintree_lookup (void *data, struct bintree *tree)
+{
+ int cmp;
+ struct bintree_node *node;
+
+ node = tree->root;
+
+ while (node)
+ {
+ if (tree->cmp)
+ cmp = (*tree->cmp) (node->data, data);
+ else
+ cmp = (node->data - data);
+
+ if (cmp == 0)
+ break;
+
+ if (cmp > 0)
+ node = node->bl_left;
+ else /* if (cmp < 0) */
+ node = node->bl_right;
+ }
+
+ if (node)
+ return node->data;
+
+ return NULL;
+}
+
+void *
+bintree_lookup_min (struct bintree *tree)
+{
+ struct bintree_node *node;
+ node = bintree_lookup_node_min (tree->root);
+ if (node == NULL)
+ return NULL;
+ return node->data;
+}
+
+void *
+bintree_lookup_max (struct bintree *tree)
+{
+ struct bintree_node *node;
+ node = bintree_lookup_node_max (tree->root);
+ if (node == NULL)
+ return NULL;
+ return node->data;
+}
+
+int
+bintree_add (void *data, struct bintree *tree)
+{
+ int cmp = 0;
+ struct bintree_node *node, *parent;
+
+ node = tree->root;
+ parent = NULL;
+
+ while (node)
+ {
+ if (tree->cmp)
+ cmp = (*tree->cmp) (node->data, data);
+ else
+ cmp = (node->data - data);
+
+ if (cmp == 0)
+ break;
+
+ parent = node;
+ if (cmp > 0)
+ node = node->bl_left;
+ else /* if (cmp < 0) */
+ node = node->bl_right;
+ }
+
+ if (node)
+ return -1;
+
+ node = malloc (sizeof (struct bintree_node));
+ memset (node, 0, sizeof (struct bintree_node));
+ node->tree = tree;
+ node->data = data;
+
+ if (parent)
+ {
+ node->parent = parent;
+
+ assert (cmp != 0);
+ if (cmp > 0)
+ {
+ node->parent_link = BL_LEFT;
+ parent->bl_left = node;
+ }
+ else /* if (cmp < 0) */
+ {
+ node->parent_link = BL_RIGHT;
+ parent->bl_right = node;
+ }
+ }
+ else
+ tree->root = node;
+
+ tree->count++;
+ return 0;
+}
+
+static void
+bintree_remove_nochild (struct bintree_node *node)
+{
+ assert (node->bl_left == NULL && node->bl_right == NULL);
+
+ if (node->parent == NULL)
+ node->tree->root = NULL;
+ else
+ node->parent->link[node->parent_link] = NULL;
+}
+
+static void
+bintree_remove_onechild (struct bintree_node *node)
+{
+ assert ((node->bl_left == NULL && node->bl_right != NULL) ||
+ (node->bl_left != NULL && node->bl_right == NULL));
+
+ if (node->bl_left)
+ {
+ if (node->parent == NULL)
+ {
+ node->tree->root = node->bl_left;
+ node->bl_left->parent = NULL;
+ }
+ else
+ {
+ node->parent->link[node->parent_link] = node->bl_left;
+ node->bl_left->parent = node->parent;
+ node->bl_left->parent_link = node->parent_link;
+ }
+ }
+ else if (node->bl_right)
+ {
+ if (node->parent == NULL)
+ {
+ node->tree->root = node->bl_right;
+ node->bl_right->parent = NULL;
+ }
+ else
+ {
+ node->parent->link[node->parent_link] = node->bl_right;
+ node->bl_right->parent = node->parent;
+ node->bl_right->parent_link = node->parent_link;
+ }
+ }
+ else
+ assert (0);
+}
+
+int
+bintree_remove (void *data, struct bintree *tree)
+{
+ int cmp;
+ struct bintree_node *node;
+
+ node = tree->root;
+
+ while (node)
+ {
+ if (tree->cmp)
+ cmp = (*tree->cmp) (node->data, data);
+ else
+ cmp = (node->data - data);
+
+ if (cmp == 0)
+ break;
+
+ if (cmp > 0)
+ node = node->bl_left;
+ else /* if (cmp < 0) */
+ node = node->bl_right;
+ }
+
+ if (node == NULL)
+ return -1;
+
+ if (node->bl_left == NULL && node->bl_right == NULL)
+ {
+ bintree_remove_nochild (node);
+ free (node);
+ tree->count--;
+ return 0;
+ }
+
+ if ((node->bl_left == NULL && node->bl_right != NULL) ||
+ (node->bl_left != NULL && node->bl_right == NULL))
+ {
+ bintree_remove_onechild (node);
+ free (node);
+ tree->count--;
+ return 0;
+ }
+
+ if (node->bl_left != NULL && node->bl_right != NULL)
+ {
+ struct bintree_node *successor;
+
+ /* find successor of the removing node */
+ successor = bintree_lookup_node_min (node->bl_right);
+
+ /* remove successor from tree */
+ if (successor->bl_right)
+ bintree_remove_onechild (successor);
+ else
+ bintree_remove_nochild (successor);
+
+ /* swap removing node with successor */
+ successor->parent = node->parent;
+ successor->parent_link = node->parent_link;
+ successor->bl_left = node->bl_left;
+ successor->bl_right = node->bl_right;
+
+ /* if the successor was the node->bl_right itself,
+ bintree_remove_**child may touch node->bl_right,
+ so only the successor->bl_right may be NULL
+ by above assignment */
+ successor->bl_left->parent = successor;
+ if (successor->bl_right)
+ successor->bl_right->parent = successor;
+
+ if (successor->parent == NULL)
+ tree->root = successor;
+ else
+ successor->parent->link[successor->parent_link] = successor;
+
+ free (node);
+ tree->count--;
+ return 0;
+ }
+
+ /* not reached */
+ return -1;
+}
+
+/* in-order traversal */
+
+void
+bintree_head (struct bintree *tree, struct bintree_node *node)
+{
+ struct bintree_node *head;
+
+ head = bintree_lookup_node_min (tree->root);
+ if (head == NULL)
+ {
+ node->parent = NULL;
+ node->bl_left = NULL;
+ node->bl_right = NULL;
+ node->data = NULL;
+ return;
+ }
+
+ node->tree = head->tree;
+ node->parent = head->parent;
+ node->parent_link = head->parent_link;
+ node->bl_left = head->bl_left;
+ node->bl_right = head->bl_right;
+ node->data = head->data;
+}
+
+int
+bintree_end (struct bintree_node *node)
+{
+ if (node->parent || node->bl_left || node->bl_right || node->data)
+ return 0;
+ return 1;
+}
+
+#define GOTO_PROCED_SUBTREE_TOP(node) \
+ while (node->parent && node->parent->bl_right && \
+ node->parent->bl_right->data == node->data) \
+ { \
+ node->data = node->parent->data; \
+ node->bl_left = node->parent->bl_left; \
+ node->bl_right = node->parent->bl_right; \
+ node->parent_link = node->parent->parent_link; \
+ node->parent = node->parent->parent; \
+ }
+
+void
+bintree_next (struct bintree_node *node)
+{
+ struct bintree_node *next = NULL;
+
+ /* if node have just been removed, current point should have just been
+ replaced with its successor. that certainly will not be processed
+ yet, so process it */
+ if (node->parent == NULL)
+ {
+ if (node->tree->root == NULL)
+ {
+ assert (node->tree->count == 0);
+ node->parent = NULL;
+ node->bl_left = NULL;
+ node->bl_right = NULL;
+ node->data = NULL;
+ return;
+ }
+ else if (node->tree->root->data != node->data)
+ next = node->tree->root;
+ }
+ else if (node->parent->link[node->parent_link] == NULL)
+ {
+ if (node->parent_link == BL_LEFT)
+ next = node->parent;
+ else
+ {
+ GOTO_PROCED_SUBTREE_TOP (node);
+ next = node->parent;
+ }
+ }
+ else if (node->parent->link[node->parent_link]->data != node->data)
+ next = node->parent->link[node->parent_link];
+
+ if (next == NULL)
+ {
+ if (node->bl_right)
+ next = bintree_lookup_node_min (node->bl_right);
+ else
+ {
+ GOTO_PROCED_SUBTREE_TOP (node);
+ next = node->parent;
+ }
+ }
+
+ if (next)
+ {
+ node->tree = next->tree;
+ node->parent = next->parent;
+ node->parent_link = next->parent_link;
+ node->bl_left = next->bl_left;
+ node->bl_right = next->bl_right;
+ node->data = next->data;
+ }
+ else
+ {
+ node->parent = NULL;
+ node->bl_left = NULL;
+ node->bl_right = NULL;
+ node->data = NULL;
+ }
+}
+
+struct bintree *
+bintree_create ()
+{
+ struct bintree *tree;
+
+ tree = malloc (sizeof (struct bintree));
+ memset (tree, 0, sizeof (struct bintree));
+
+ return tree;
+}
+
+void
+bintree_delete (struct bintree *tree)
+{
+ struct bintree_node node;
+
+ for (bintree_head (tree, &node); ! bintree_end (&node);
+ bintree_next (&node))
+ bintree_remove (node.data, tree);
+
+ assert (tree->count == 0);
+ free (tree);
+}
+
+int indent_num = 0;
+
+void
+bintree_print_sub (void (*print) (int, void *), struct bintree_node *subroot)
+{
+ if (subroot == NULL)
+ return;
+
+ if (subroot->bl_right)
+ {
+ indent_num++;
+ bintree_print_sub (print, subroot->bl_right);
+ indent_num--;
+ }
+
+ (*print) (indent_num, subroot->data);
+
+ if (subroot->bl_left)
+ {
+ indent_num++;
+ bintree_print_sub (print, subroot->bl_left);
+ indent_num--;
+ }
+}
+
+void
+bintree_print (void (*print) (int, void *), struct bintree *tree)
+{
+ indent_num = 0;
+ bintree_print_sub (print, tree->root);
+}
+
+
diff --git a/ospf6d/ospf6_bintree.h b/ospf6d/ospf6_bintree.h
new file mode 100644
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 <zebra.h>
+#include <math.h>
+
+#include "log.h"
+#include "prefix.h"
+#include "thread.h"
+#include "table.h"
+#include "command.h"
+#include "vty.h"
+
+extern struct thread_master *master;
+
+#include "ospf6_damp.h"
+
+#ifdef HAVE_OSPF6_DAMP
+
+#define DELTA_REUSE 10 /* Time granularity for reuse lists */
+#define DELTA_T 5 /* Time granularity for decay arrays */
+#define DEFAULT_HALF_LIFE 60 /* (sec) 1 min */
+
+#define DEFAULT_PENALTY 1000
+#define DEFAULT_REUSE 750
+#define DEFAULT_SUPPRESS 2000
+
+#define REUSE_LIST_SIZE 256
+#define REUSE_ARRAY_SIZE 1024
+
+/* Global variable to access damping configuration */
+struct ospf6_damp_config damp_config;
+struct ospf6_damp_config *dc = &damp_config;
+u_int reuse_array_offset = 0;
+struct route_table *damp_info_table[OSPF6_DAMP_TYPE_MAX];
+struct thread *ospf6_reuse_thread = NULL;
+
+int ospf6_damp_debug = 0;
+#define IS_OSPF6_DEBUG_DAMP (ospf6_damp_debug)
+
+static struct ospf6_damp_info *
+ospf6_damp_lookup (u_short type, struct prefix *name)
+{
+ struct route_node *node;
+
+ node = route_node_lookup (damp_info_table[type], name);
+ if (node && node->info)
+ return (struct ospf6_damp_info *) node->info;
+ return NULL;
+}
+
+static struct ospf6_damp_info *
+ospf6_damp_create (u_short type, struct prefix *name)
+{
+ struct route_node *node;
+ struct ospf6_damp_info *di;
+ char namebuf[64];
+
+ di = ospf6_damp_lookup (type, name);
+ if (di)
+ return di;
+
+ if (IS_OSPF6_DEBUG_DAMP)
+ {
+ prefix2str (name, namebuf, sizeof (namebuf));
+ zlog_info ("DAMP: create: type: %d, name: %s", type, namebuf);
+ }
+
+ di = (struct ospf6_damp_info *)
+ malloc (sizeof (struct ospf6_damp_info));
+ memset (di, 0, sizeof (struct ospf6_damp_info));
+ di->type = type;
+ prefix_copy (&di->name, name);
+
+ node = route_node_get (damp_info_table[type], name);
+ node->info = di;
+
+ return di;
+}
+
+static void
+ospf6_damp_delete (u_short type, struct prefix *name)
+{
+ struct route_node *node;
+ struct ospf6_damp_info *di;
+ char namebuf[64];
+
+ node = route_node_lookup (damp_info_table[type], name);
+ if (! node || ! node->info)
+ return;
+
+ di = node->info;
+
+ if (IS_OSPF6_DEBUG_DAMP)
+ {
+ prefix2str (&di->name, namebuf, sizeof (namebuf));
+ zlog_info ("DAMP: delete: type: %d, name: %s",
+ di->type, namebuf);
+ }
+
+ node->info = NULL;
+ free (di);
+}
+
+/* compute and fill the configuration parameter */
+void
+ospf6_damp_init_config (u_int half_life, u_int reuse,
+ u_int suppress, u_int t_hold)
+{
+ int i;
+ double max_ratio, max_ratio1, max_ratio2;
+
+ dc->half_life = half_life ? half_life : DEFAULT_HALF_LIFE;
+ dc->reuse = reuse ? reuse : DEFAULT_REUSE;
+ dc->suppress = suppress ? suppress : DEFAULT_SUPPRESS;
+ dc->t_hold = t_hold ? t_hold : 4 * dc->half_life;
+
+ /* Initialize system-wide params */
+ dc->delta_t = DELTA_T;
+ dc->delta_reuse = DELTA_REUSE;
+ dc->default_penalty = DEFAULT_PENALTY;
+ dc->reuse_index_array_size = REUSE_ARRAY_SIZE;
+
+ /* ceiling is the maximum penalty a route may attain */
+ /* ceiling = reuse * 2^(T-hold/half-life) */
+ dc->ceiling = (int)
+ (dc->reuse * (pow (2, (double) dc->t_hold / dc->half_life)));
+
+ /* Decay-array computations */
+ /* decay_array_size = decay memory/time granularity */
+ dc->decay_array_size = ceil ((double) dc->t_hold / dc->delta_t);
+ dc->decay_array = malloc (sizeof (double) * (dc->decay_array_size));
+
+ /* Each i-th element is per tick delay raised to the i-th power */
+ dc->decay_array[0] = 1.0;
+ dc->decay_array[1] = exp ((1.0 / (dc->half_life / dc->delta_t)) * log (0.5));
+ for (i = 2; i < dc->decay_array_size; i++)
+ dc->decay_array[i] = dc->decay_array[i - 1] * dc->decay_array[1];
+
+ /* Reuse-list computations (reuse queue head array ?) */
+ dc->reuse_list_size = ceil ((double) dc->t_hold / dc->delta_reuse) + 1;
+ if (dc->reuse_list_size == 0 || dc->reuse_list_size > REUSE_LIST_SIZE)
+ dc->reuse_list_size = REUSE_LIST_SIZE;
+ dc->reuse_list_array = (struct ospf6_damp_info **)
+ malloc (dc->reuse_list_size * sizeof (struct ospf6_reuse_list *));
+ memset (dc->reuse_list_array, 0x00,
+ dc->reuse_list_size * sizeof (struct ospf6_reuse_list *));
+
+ /* Reuse-array computations */
+ dc->reuse_index_array = malloc (sizeof (int) * dc->reuse_index_array_size);
+
+ /*
+ * This is the maximum ratio between the current value of the penalty and
+ * the reuse value which can be indexed by the reuse array. It will be
+ * limited by the ceiling or by the amount of time that the reuse list
+ * covers
+ */
+ max_ratio1 = (double) dc->ceiling / dc->reuse;
+ max_ratio2 = exp ((double) dc->t_hold / dc->half_life) * log10 (2.0);
+ max_ratio = (max_ratio2 != 0 && max_ratio2 < max_ratio1 ?
+ max_ratio2 : max_ratio1);
+
+ /*
+ * reuse array is just an estimator and we need something
+ * to use the full array
+ */
+ dc->scale_factor = (double) dc->reuse_index_array_size / (max_ratio - 1);
+
+ for (i = 0; i < dc->reuse_index_array_size; i++)
+ {
+ dc->reuse_index_array[i] = (int)
+ (((double) dc->half_life / dc->delta_reuse) *
+ log10 (1.0 / (dc->reuse * (1.0 + ((double) i / dc->scale_factor))))
+ / log10 (0.5));
+ }
+
+ dc->enabled = ON;
+}
+
+static double
+ospf6_damp_decay (time_t tdiff)
+{
+ int index = tdiff / dc->delta_t;
+
+ if (index >= dc->decay_array_size)
+ return 0;
+
+ return dc->decay_array[index];
+}
+
+static int
+ospf6_damp_reuse_index (int penalty)
+{
+ int index;
+
+ index = (int) (((double) penalty / dc->reuse - 1.0) * dc->scale_factor);
+
+ if (index >= dc->reuse_index_array_size)
+ index = dc->reuse_index_array_size - 1;
+
+ return (dc->reuse_index_array[index] - dc->reuse_index_array[0]);
+}
+
+static int
+ospf6_reuse_list_lookup (struct ospf6_damp_info *di)
+{
+ struct ospf6_damp_info *info;
+
+ for (info = dc->reuse_list_array[di->index]; info; info = info->next)
+ {
+ if (info == di)
+ return 1;
+ }
+ return 0;
+}
+
+static void
+ospf6_reuse_list_remove (struct ospf6_damp_info *di)
+{
+ if (di->prev)
+ di->prev->next = di->next;
+ else
+ dc->reuse_list_array[di->index] = di->next;
+ if (di->next)
+ di->next->prev = di->prev;
+
+ di->index = -1;
+ di->prev = NULL;
+ di->next = NULL;
+}
+
+static void
+ospf6_reuse_list_add (struct ospf6_damp_info *di)
+{
+ /* set the index of reuse-array */
+ di->index = (reuse_array_offset + (ospf6_damp_reuse_index (di->penalty)))
+ % dc->reuse_list_size;
+
+ /* insert to the head of the reuse list */
+ di->next = dc->reuse_list_array[di->index];
+ if (di->next)
+ di->next->prev = di;
+ di->prev = NULL;
+ dc->reuse_list_array[di->index] = di;
+}
+
+/* When we quit damping for a target, we should execute proper event
+ which have been postponed during damping */
+static void
+ospf6_damp_stop (struct ospf6_damp_info *di)
+{
+ time_t t_now;
+ char namebuf[64];
+ struct timeval now;
+
+ if (IS_OSPF6_DEBUG_DAMP)
+ {
+ t_now = time (NULL);
+ prefix2str (&di->name, namebuf, sizeof (namebuf));
+ gettimeofday (&now, NULL);
+ zlog_info ("DAMP: %lu.%06lu stop damping: %ld: type: %d, name: %s",
+ now.tv_sec, now.tv_usec,
+ t_now, di->type, namebuf);
+ }
+
+ /* set flag indicates that we're damping this target */
+ di->damping = OFF;
+
+ /* if the target's current status differ from that it should be,
+ execute the proper event to repair his status */
+ if (di->target_status != di->event_type)
+ {
+ (*(di->event)) (di->target);
+ di->target_status = di->event_type;
+
+ di->event = NULL;
+ di->event_type = event_none;
+ }
+}
+
+/* ospf6_reuse_timer is called every DELTA_REUSE seconds.
+ Each route in the current reuse-list is evaluated
+ and is used or requeued */
+int
+ospf6_damp_reuse_timer (struct thread *t)
+{
+ struct ospf6_damp_info *di, *next;
+ time_t t_now, t_diff;
+ char namebuf[64];
+ struct timeval now;
+
+ /* Restart the reuse timer */
+ ospf6_reuse_thread =
+ thread_add_timer (master, ospf6_damp_reuse_timer, NULL, dc->delta_reuse);
+
+ t_now = time (NULL);
+
+ /* get the damp info list head */
+ di = dc->reuse_list_array[reuse_array_offset];
+ dc->reuse_list_array[reuse_array_offset] = NULL;
+
+ /* rotate the circular reuse list head array */
+ reuse_array_offset = (reuse_array_offset + 1) % dc->reuse_list_size;
+
+ /* for each damp info */
+ while (di)
+ {
+ next = di->next;
+ di->next = NULL;
+
+ /* Update penalty */
+ t_diff = t_now - di->t_updated;
+ di->t_updated = t_now;
+ di->penalty = (int)
+ ((double) di->penalty * ospf6_damp_decay (t_diff));
+ /* configration of ceiling may be just changed */
+ if (di->penalty > dc->ceiling)
+ di->penalty = dc->ceiling;
+
+ if (IS_OSPF6_DEBUG_DAMP)
+ {
+ prefix2str (&di->name, namebuf, sizeof (namebuf));
+ gettimeofday (&now, NULL);
+ zlog_info ("DAMP: %lu.%06lu update penalty: type: %d, name: %s, penalty: %d",
+ now.tv_sec, now.tv_usec,
+ di->type, namebuf, di->penalty);
+ }
+
+ /* If the penalty becomes under reuse,
+ call real event that we have been postponed. */
+ if (di->penalty < dc->reuse && di->damping == ON)
+ ospf6_damp_stop (di);
+
+ /* If the penalty becomes less than the half of the
+ reuse value, this damp info will be freed from reuse-list,
+ by assuming that it is considered to be stable enough already,
+ and there's no need to maintain flapping history for this. */
+ if (di->penalty <= dc->reuse / 2)
+ {
+ ospf6_damp_delete (di->type, &di->name);
+ di = next;
+ continue;
+ }
+
+ /* re-insert to the reuse-list */
+ ospf6_reuse_list_add (di);
+
+ di = next;
+ }
+
+ return 0;
+}
+
+static void
+ospf6_damp_event (damp_event_t event_type,
+ u_short type, struct prefix *name,
+ int (*event) (void *), void *target)
+{
+ time_t t_now, t_diff;
+ struct ospf6_damp_info *di;
+ char namebuf[64];
+ struct timeval now;
+
+ if (dc->enabled == OFF)
+ {
+ (*event) (target);
+ return;
+ }
+
+ di = ospf6_damp_lookup (type, name);
+ if (! di)
+ di = ospf6_damp_create (type, name);
+
+ t_now = time (NULL);
+
+ di->event = event;
+ di->target = target;
+ di->event_type = event_type;
+
+ if (! ospf6_reuse_list_lookup (di))
+ di->t_start = t_now;
+ else
+ {
+ ospf6_reuse_list_remove (di);
+
+ t_diff = t_now - di->t_updated;
+ di->penalty = (int) (di->penalty * ospf6_damp_decay (t_diff));
+ }
+
+ /* penalty only on down event */
+ if (event_type == event_down)
+ {
+ di->flap++;
+ di->penalty += dc->default_penalty;
+ }
+
+ /* limit penalty up to ceiling */
+ if (di->penalty > dc->ceiling)
+ di->penalty = dc->ceiling;
+
+ if (IS_OSPF6_DEBUG_DAMP)
+ {
+ prefix2str (&di->name, namebuf, sizeof (namebuf));
+ gettimeofday (&now, NULL);
+ zlog_info ("DAMP: %lu.%06lu update penalty: type: %d, name: %s, penalty: %d",
+ now.tv_sec, now.tv_usec,
+ di->type, namebuf, di->penalty);
+ }
+
+ /* if penalty < reuse, stop damping here */
+ if (di->penalty < dc->reuse && di->damping == ON)
+ {
+ if (IS_OSPF6_DEBUG_DAMP)
+ {
+ prefix2str (&di->name, namebuf, sizeof (namebuf));
+ gettimeofday (&now, NULL);
+ zlog_info ("DAMP: %lu.%06lu stop damping: %ld: type: %d, name: %s",
+ now.tv_sec, now.tv_usec,
+ t_now, di->type, namebuf);
+ }
+ di->damping = OFF;
+ }
+
+ /* if event == up and if penalty >= suppress , start damping here */
+ if (di->event_type == event_up && di->penalty >= dc->suppress &&
+ di->damping == OFF)
+ {
+ if (IS_OSPF6_DEBUG_DAMP)
+ {
+ prefix2str (&di->name, namebuf, sizeof (namebuf));
+ gettimeofday (&now, NULL);
+ zlog_info ("DAMP: %lu.%06lu start damping: %ld: type: %d, name: %s",
+ now.tv_sec, now.tv_usec,
+ t_now, type, namebuf);
+ }
+ di->damping = ON;
+ }
+
+ /* execute event if we're not damping */
+ if (di->damping == OFF)
+ {
+ (*(di->event)) (di->target);
+ di->target_status = di->event_type;
+ }
+
+ /* if the penalty goes beyond suppress value, start damping */
+ if (di->penalty >= dc->suppress && di->damping == OFF)
+ {
+ if (IS_OSPF6_DEBUG_DAMP)
+ {
+ prefix2str (name, namebuf, sizeof (namebuf));
+ gettimeofday (&now, NULL);
+ zlog_info ("DAMP: %lu.%06lu start damping: %ld: type: %d, name: %s",
+ now.tv_sec, now.tv_usec,
+ t_now, type, namebuf);
+ }
+ di->damping = ON;
+ }
+
+ /* update last-updated-time field */
+ di->t_updated = t_now;
+
+ /* Insert it into the reuse list */
+ ospf6_reuse_list_add (di);
+}
+
+void
+ospf6_damp_event_up (u_short type, struct prefix *name,
+ int (*event) (void *), void *target)
+{
+ struct timeval now;
+
+ gettimeofday (&now, NULL);
+ if (IS_OSPF6_DEBUG_DAMP)
+ zlog_info ("DAMP: Up Event at %lu.%06lu", now.tv_sec, now.tv_usec);
+
+ ospf6_damp_event (event_up, type, name, event, target);
+}
+
+void
+ospf6_damp_event_down (u_short type, struct prefix *name,
+ int (*event) (void *), void *target)
+{
+ struct timeval now;
+
+ gettimeofday (&now, NULL);
+ if (IS_OSPF6_DEBUG_DAMP)
+ zlog_info ("DAMP: Down Event at %lu.%06lu", now.tv_sec, now.tv_usec);
+
+ ospf6_damp_event (event_down, type, name, event, target);
+}
+
+int
+ospf6_damp_debug_thread (struct thread *thread)
+{
+ int i;
+ struct ospf6_damp_info *di;
+ char buf[256];
+ time_t t_now;
+ struct timeval now;
+
+ for (i = 0; i < dc->reuse_list_size; i++)
+ {
+ for (di = dc->reuse_list_array[i]; di; di = di->next)
+ {
+ t_now = time (NULL);
+ gettimeofday (&now, NULL);
+ prefix2str (&di->name, buf, sizeof (buf));
+ zlog_info ("DAMP: %lu.%06lu %c %-32s penalty %7u",
+ now.tv_sec, now.tv_usec,
+ (di->damping == ON ? 'D' : 'A'), buf,
+ (u_int) (di->penalty *
+ ospf6_damp_decay (t_now - di->t_updated)));
+ }
+ }
+ thread_add_timer (master, ospf6_damp_debug_thread, NULL, 1);
+ return 0;
+}
+
+DEFUN (show_ipv6_ospf6_route_flapping,
+ show_ipv6_ospf6_route_flapping_cmd,
+ "show ipv6 ospf6 route flapping",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR)
+{
+ int i;
+ struct ospf6_damp_info *di;
+ char buf[256];
+ time_t t_now;
+
+ t_now = time (NULL);
+ vty_out (vty, "%c %-32s %7s%s", ' ', "Prefix", "penalty", VTY_NEWLINE);
+
+ for (i = 0; i < dc->reuse_list_size; i++)
+ {
+ for (di = dc->reuse_list_array[i]; di; di = di->next)
+ {
+ prefix2str (&di->name, buf, sizeof (buf));
+ vty_out (vty, "%c %-32s %7u%s",
+ (di->damping == ON ? 'D' : ' '), buf,
+ (u_int) (di->penalty *
+ ospf6_damp_decay (t_now - di->t_updated)),
+ VTY_NEWLINE);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (flap_damping_route,
+ flap_damping_route_cmd,
+ "flap-damping route <0-4294967295> <0-4294967295> "
+ "<0-4294967295> <0-4294967295>",
+ "enable flap dampening\n"
+ "enable route flap dampening\n"
+ "half-life in second\n"
+ "reuse value\n"
+ "suppress value\n"
+ "t-hold in second (maximum time that the target can be damped)\n"
+ )
+{
+ u_int half_life, reuse, suppress, t_hold;
+
+ if (argc)
+ {
+ half_life = (u_int) strtoul (argv[0], NULL, 10);
+ reuse = (u_int) strtoul (argv[1], NULL, 10);
+ suppress = (u_int) strtoul (argv[2], NULL, 10);
+ t_hold = (u_int) strtoul (argv[3], NULL, 10);
+ }
+ else
+ {
+ half_life = (u_int) DEFAULT_HALF_LIFE;
+ reuse = (u_int) DEFAULT_REUSE;
+ suppress = (u_int) DEFAULT_SUPPRESS;
+ t_hold = (u_int) DEFAULT_HALF_LIFE * 4;
+ }
+
+ if (reuse && suppress && reuse >= suppress)
+ {
+ vty_out (vty, "reuse value exceeded suppress value, failed%s\n",
+ VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ if (half_life && t_hold && half_life >= t_hold)
+ {
+ vty_out (vty, "half-life exceeded t-hold, failed%s\n", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ ospf6_damp_init_config (half_life, reuse, suppress, t_hold);
+
+ if (ospf6_reuse_thread == NULL)
+ ospf6_reuse_thread =
+ thread_add_timer (master, ospf6_damp_reuse_timer, NULL, dc->delta_reuse);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_damp_config,
+ show_ipv6_ospf6_camp_config_cmd,
+ "show ipv6 ospf6 damp config",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "Flap-dampening information\n"
+ "shows dampening configuration\n"
+ )
+{
+ int i;
+
+ vty_out (vty, "%10s %10s %10s %10s%s",
+ "Half life", "Suppress", "Reuse", "T-hold",
+ VTY_NEWLINE);
+ vty_out (vty, "%10u %10u %10u %10u%s",
+ dc->half_life, dc->suppress, dc->reuse, dc->t_hold,
+ VTY_NEWLINE);
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ vty_out (vty, "Delta-t = %u%s", dc->delta_t, VTY_NEWLINE);
+ vty_out (vty, "Delta-Reuse = %u%s", dc->delta_reuse, VTY_NEWLINE);
+ vty_out (vty, "Default-Penalty = %u%s", dc->default_penalty, VTY_NEWLINE);
+ vty_out (vty, "Ceiling = %u%s", dc->ceiling, VTY_NEWLINE);
+ vty_out (vty, "ScaleFactor = %f%s", dc->scale_factor, VTY_NEWLINE);
+
+ vty_out (vty, "DecayArray(%d) =%s", dc->decay_array_size, VTY_NEWLINE);
+ for (i = 0; i < dc->decay_array_size; i++)
+ {
+ if (i % 10 == 0)
+ vty_out (vty, " ");
+ vty_out (vty, " %f", dc->decay_array[i]);
+ if (i % 10 == 0)
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ vty_out (vty, "ReuseIndexArray(%d) =%s",
+ dc->reuse_index_array_size, VTY_NEWLINE);
+ for (i = 0; i < dc->reuse_index_array_size; i++)
+ {
+ if (i % 10 == 0)
+ vty_out (vty, " ");
+ vty_out (vty, " %d", dc->reuse_index_array[i]);
+ if (i % 10 == 0)
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+void
+ospf6_damp_config_write (struct vty *vty)
+{
+ if (dc->enabled == ON)
+ {
+ vty_out (vty, " flap-damping route %u %u %u %u%s",
+ dc->half_life, dc->reuse, dc->suppress, dc->t_hold,
+ VTY_NEWLINE);
+ }
+}
+
+DEFUN (debug_ospf6_damp,
+ debug_ospf6_damp_cmd,
+ "debug ospf6 damp",
+ DEBUG_STR
+ OSPF6_STR
+ "Flap-dampening information\n"
+ )
+{
+ ospf6_damp_debug = 1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ospf6_damp,
+ no_debug_ospf6_damp_cmd,
+ "no debug ospf6 damp",
+ NO_STR
+ DEBUG_STR
+ OSPF6_STR
+ "Flap-dampening information\n"
+ )
+{
+ ospf6_damp_debug = 0;
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_debug_ospf6_damp,
+ show_debug_ospf6_damp_cmd,
+ "show debugging ospf6 damp",
+ SHOW_STR
+ DEBUG_STR
+ OSPF6_STR
+ "Flap-dampening information\n"
+ )
+{
+ vty_out (vty, "debugging ospf6 damp is ");
+ if (IS_OSPF6_DEBUG_DAMP)
+ vty_out (vty, "enabled.");
+ else
+ vty_out (vty, "disabled.");
+ vty_out (vty, "%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+void
+ospf6_damp_init ()
+{
+ int i;
+ for (i = 0; i < OSPF6_DAMP_TYPE_MAX; i++)
+ damp_info_table[i] = route_table_init ();
+
+ install_element (VIEW_NODE, &show_ipv6_ospf6_route_flapping_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_route_flapping_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_camp_config_cmd);
+ install_element (OSPF6_NODE, &flap_damping_route_cmd);
+
+ install_element (ENABLE_NODE, &show_debug_ospf6_damp_cmd);
+ install_element (CONFIG_NODE, &debug_ospf6_damp_cmd);
+ install_element (CONFIG_NODE, &no_debug_ospf6_damp_cmd);
+
+ thread_add_event (master, ospf6_damp_debug_thread, NULL, 0);
+}
+
+#endif /* HAVE_OSPF6_DAMP */
+
+
diff --git a/ospf6d/ospf6_damp.h b/ospf6d/ospf6_damp.h
new file mode 100644
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 <zebra.h>
+
+/* Include other stuffs */
+#include "log.h"
+#include "command.h"
+#include "ospf6_dump.h"
+
+#define CMD_SHOW 0
+#define CMD_ENABLE 1
+#define CMD_DISABLE 2
+#define CMD_MAX 3
+
+struct ospf6_dump
+{
+ struct cmd_element cmd[CMD_MAX];
+ char *name;
+ int config;
+};
+
+#define DUMP_MAX 512
+struct ospf6_dump *ospf6_dump[DUMP_MAX];
+unsigned int dump_size = 0;
+
+static int
+ospf6_dump_index (struct cmd_element *cmd, int command)
+{
+ int i;
+
+ for (i = 0; i < DUMP_MAX; i++)
+ {
+ if (cmd != &ospf6_dump[i]->cmd[command])
+ continue;
+ break;
+ }
+
+ if (i == DUMP_MAX)
+ return -1;
+ return i;
+}
+
+int
+ospf6_dump_is_on (int index)
+{
+ if (ospf6_dump[index] == NULL)
+ return 0;
+
+ return ospf6_dump[index]->config;
+}
+
+int
+ospf6_dump_show (struct cmd_element *cmd,
+ struct vty *vty, int argc, char **argv)
+{
+ int index;
+
+ index = ospf6_dump_index (cmd, CMD_SHOW);
+ assert (index != -1);
+
+ vty_out (vty, " %-16s: %s%s", ospf6_dump[index]->name,
+ (ospf6_dump[index]->config ? "on" : "off"),
+ VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+int
+ospf6_dump_enable (struct cmd_element *cmd,
+ struct vty *vty, int argc, char **argv)
+{
+ int index;
+
+ index = ospf6_dump_index (cmd, CMD_ENABLE);
+ assert (index != -1);
+
+ ospf6_dump[index]->config = 1;
+ return CMD_SUCCESS;
+}
+
+int
+ospf6_dump_disable (struct cmd_element *cmd,
+ struct vty *vty, int argc, char **argv)
+{
+ int index;
+
+ index = ospf6_dump_index (cmd, CMD_DISABLE);
+ assert (index != -1);
+
+ ospf6_dump[index]->config = 0;
+ return CMD_SUCCESS;
+}
+
+int
+ospf6_dump_install (char *name, char *help)
+{
+ struct cmd_element *cmd;
+ char string[256];
+ char helpstring[256];
+
+ if (dump_size + 1 >= DUMP_MAX)
+ return -1;
+
+ ospf6_dump[dump_size] = malloc (sizeof (struct ospf6_dump));
+ if (ospf6_dump[dump_size] == NULL)
+ return -1;
+ memset (ospf6_dump[dump_size], 0, sizeof (struct ospf6_dump));
+
+ ospf6_dump[dump_size]->name = strdup (name);
+
+ cmd = &ospf6_dump[dump_size]->cmd[CMD_SHOW];
+ snprintf (string, sizeof (string), "show debugging ospf6 %s", name);
+ snprintf (helpstring, sizeof (helpstring), "%s%s%s%s",
+ SHOW_STR, DEBUG_STR, OSPF6_STR, help);
+ memset (cmd, 0, sizeof (struct cmd_element));
+ cmd->string = strdup (string);
+ cmd->func = ospf6_dump_show;
+ cmd->doc = strdup (helpstring);
+ install_element (VIEW_NODE, cmd);
+ install_element (ENABLE_NODE, cmd);
+
+ cmd = &ospf6_dump[dump_size]->cmd[CMD_ENABLE];
+ snprintf (string, sizeof (string), "debug ospf6 %s", name);
+ snprintf (helpstring, sizeof (helpstring), "%s%s%s",
+ DEBUG_STR, OSPF6_STR, help);
+ memset (cmd, 0, sizeof (struct cmd_element));
+ cmd->string = strdup (string);
+ cmd->func = ospf6_dump_enable;
+ cmd->doc = strdup (helpstring);
+ install_element (CONFIG_NODE, cmd);
+
+ cmd = &ospf6_dump[dump_size]->cmd[CMD_DISABLE];
+ snprintf (string, sizeof (string), "no debug ospf6 %s", name);
+ snprintf (helpstring, sizeof (helpstring), "%s%s%s%s",
+ NO_STR, DEBUG_STR, OSPF6_STR, help);
+ memset (cmd, 0, sizeof (struct cmd_element));
+ cmd->string = strdup (string);
+ cmd->func = ospf6_dump_disable;
+ cmd->doc = strdup (helpstring);
+ install_element (CONFIG_NODE, cmd);
+
+ return dump_size++;
+}
+
+DEFUN(show_debug_ospf6,
+ show_debug_ospf6_cmd,
+ "show debugging ospf6",
+ SHOW_STR
+ DEBUG_STR
+ OSPF6_STR)
+{
+ int i;
+
+ vty_out (vty, "OSPF6 debugging status:%s", VTY_NEWLINE);
+
+ for (i = 0; i < DUMP_MAX; i++)
+ {
+ if (ospf6_dump[i] == NULL)
+ continue;
+ ospf6_dump_show (&ospf6_dump[i]->cmd[CMD_SHOW], vty, 0, NULL);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_ospf6_all,
+ debug_ospf6_all_cmd,
+ "debug ospf6 all",
+ DEBUG_STR
+ OSPF6_STR
+ "Turn on ALL OSPFv3 debugging\n")
+{
+ int i;
+
+ for (i = 0; i < DUMP_MAX; i++)
+ {
+ if (ospf6_dump[i] == NULL)
+ continue;
+ ospf6_dump_enable (&ospf6_dump[i]->cmd[CMD_ENABLE], vty, 0, NULL);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ospf6_all,
+ no_debug_ospf6_all_cmd,
+ "no debug ospf6 all",
+ NO_STR
+ DEBUG_STR
+ OSPF6_STR
+ "Turn off ALL OSPFv3 debugging\n")
+{
+ int i;
+
+ for (i = 0; i < DUMP_MAX; i++)
+ {
+ if (ospf6_dump[i] == NULL)
+ continue;
+ ospf6_dump_disable (&ospf6_dump[i]->cmd[CMD_DISABLE], vty, 0, NULL);
+ }
+
+ return CMD_SUCCESS;
+}
+
+struct cmd_node debug_node =
+{
+ DEBUG_NODE,
+ ""
+};
+
+int
+ospf6_dump_config_write (struct vty *vty)
+{
+ int i;
+
+ for (i = 0; i < dump_size; i++)
+ {
+ if (ospf6_dump[i] == NULL)
+ continue;
+
+ if (ospf6_dump[i]->config == 0)
+ continue;
+
+ vty_out (vty, "debug ospf6 %s%s", ospf6_dump[i]->name, VTY_NEWLINE);
+ }
+
+ vty_out (vty, "!%s", VTY_NEWLINE);
+ return 0;
+}
+
+char dump_index[OSPF6_DUMP_MAX];
+
+void
+ospf6_dump_init ()
+{
+ memset (ospf6_dump, 0, sizeof (ospf6_dump));
+
+ install_node (&debug_node, ospf6_dump_config_write);
+
+ install_element (VIEW_NODE, &show_debug_ospf6_cmd);
+ install_element (ENABLE_NODE, &show_debug_ospf6_cmd);
+
+ install_element (CONFIG_NODE, &debug_ospf6_all_cmd);
+ install_element (CONFIG_NODE, &no_debug_ospf6_all_cmd);
+
+ /* bellow is for backward compatibility
+ should be moved to each modules */
+
+#define MESSAGE_STR "OSPFv3 Messages\n"
+
+ dump_index[OSPF6_DUMP_HELLO] =
+ ospf6_dump_install ("message hello",
+ MESSAGE_STR "Hello\n");
+ dump_index[OSPF6_DUMP_DBDESC] =
+ ospf6_dump_install ("message dbdesc",
+ MESSAGE_STR "Database Description\n");
+ dump_index[OSPF6_DUMP_LSREQ] =
+ ospf6_dump_install ("message lsreq",
+ MESSAGE_STR "Link State Request\n");
+ dump_index[OSPF6_DUMP_LSUPDATE] =
+ ospf6_dump_install ("message lsupdate",
+ MESSAGE_STR "Link State Update\n");
+ dump_index[OSPF6_DUMP_LSACK] =
+ ospf6_dump_install ("message lsack",
+ MESSAGE_STR "Link State Acknowledge\n");
+ dump_index[OSPF6_DUMP_NEIGHBOR] =
+ ospf6_dump_install ("neighbor", "Neighbors\n");
+ dump_index[OSPF6_DUMP_INTERFACE] =
+ ospf6_dump_install ("interface", "Interfaces\n");
+ dump_index[OSPF6_DUMP_LSA] =
+ ospf6_dump_install ("lsa", "Link State Advertisement\n");
+ dump_index[OSPF6_DUMP_ZEBRA] =
+ ospf6_dump_install ("zebra", "Communication with zebra\n");
+ dump_index[OSPF6_DUMP_CONFIG] =
+ ospf6_dump_install ("config", "Configuration Changes\n");
+ dump_index[OSPF6_DUMP_DBEX] =
+ ospf6_dump_install ("dbex", "Database Exchange/Flooding\n");
+ dump_index[OSPF6_DUMP_SPF] =
+ ospf6_dump_install ("spf", "SPF Calculation\n");
+ dump_index[OSPF6_DUMP_ROUTE] =
+ ospf6_dump_install ("route", "Route Calculation\n");
+ dump_index[OSPF6_DUMP_LSDB] =
+ ospf6_dump_install ("lsdb", "Link State Database\n");
+ dump_index[OSPF6_DUMP_REDISTRIBUTE] =
+ ospf6_dump_install ("redistribute",
+ "Route Exchange with other protocols\n");
+ dump_index[OSPF6_DUMP_HOOK] =
+ ospf6_dump_install ("hook", "Hooks\n");
+ dump_index[OSPF6_DUMP_ASBR] =
+ ospf6_dump_install ("asbr", "AS Boundary Router function\n");
+ dump_index[OSPF6_DUMP_PREFIX] =
+ ospf6_dump_install ("prefix", "Prefix\n");
+}
+
+
diff --git a/ospf6d/ospf6_dump.h b/ospf6d/ospf6_dump.h
new file mode 100644
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 <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+
+#include "ospf6_hook.h"
+
+struct ospf6_hook_master neighbor_hook;
+struct ospf6_hook_master interface_hook;
+struct ospf6_hook_master area_hook;
+struct ospf6_hook_master top_hook;
+struct ospf6_hook_master database_hook;
+struct ospf6_hook_master intra_topology_hook;
+struct ospf6_hook_master inter_topology_hook;
+struct ospf6_hook_master route_hook;
+struct ospf6_hook_master redistribute_hook;
+
+static struct ospf6_hook *
+ospf6_hook_create ()
+{
+ struct ospf6_hook *new;
+ new = XMALLOC (MTYPE_OSPF6_OTHER, sizeof (struct ospf6_hook));
+ if (new == NULL)
+ return NULL;
+ memset (new, 0, sizeof (struct ospf6_hook));
+ return new;
+}
+
+static void
+ospf6_hook_delete (struct ospf6_hook *hook)
+{
+ XFREE (MTYPE_OSPF6_OTHER, hook);
+}
+
+static int
+ospf6_hook_issame (struct ospf6_hook *hook1, struct ospf6_hook *hook2)
+{
+ if (hook1->name && hook2->name &&
+ strcmp (hook1->name, hook2->name) != 0)
+ return 0;
+ if (hook1->hook_add != hook2->hook_add)
+ return 0;
+ if (hook1->hook_change != hook2->hook_change)
+ return 0;
+ if (hook1->hook_remove != hook2->hook_remove)
+ return 0;
+ return 1;
+}
+
+void
+ospf6_hook_register (struct ospf6_hook *hook,
+ struct ospf6_hook_master *master)
+{
+ struct ospf6_hook *new;
+
+ new = ospf6_hook_create ();
+
+ if (hook->name)
+ new->name = strdup (hook->name);
+ new->hook_add = hook->hook_add;
+ new->hook_change = hook->hook_change;
+ new->hook_remove = hook->hook_remove;
+
+ new->prev = master->tail;
+ if (master->tail)
+ master->tail->next = new;
+
+ master->tail = new;
+ if (! master->head)
+ master->head = new;
+
+ master->count++;
+
+ if (IS_OSPF6_DUMP_HOOK)
+ {
+ zlog_info ("HOOK: Register hook%s%s%s%s",
+ (hook->name ? " " : ""),
+ (hook->name ? hook->name : ""),
+ (master->name ? " to " : ""),
+ (master->name ? master->name : ""));
+ }
+}
+
+void
+ospf6_hook_unregister (struct ospf6_hook *req,
+ struct ospf6_hook_master *master)
+{
+ struct ospf6_hook *hook;
+
+ for (hook = master->head; hook; hook = hook->next)
+ {
+ if (ospf6_hook_issame (hook, req))
+ break;
+ }
+ if (! hook)
+ return;
+
+ if (hook->prev)
+ hook->prev->next = hook->next;
+ if (hook->next)
+ hook->next->prev = hook->prev;
+ if (master->head == hook)
+ master->head = hook->next;
+ if (master->tail == hook)
+ master->tail = hook->prev;
+
+ master->count--;
+
+ if (IS_OSPF6_DUMP_HOOK)
+ {
+ zlog_info ("HOOK: Unregister hook%s%s%s%s",
+ (hook->name ? " " : ""),
+ (hook->name ? hook->name : ""),
+ (master->name ? " to " : ""),
+ (master->name ? master->name : ""));
+ }
+
+ if (hook->name)
+ free (hook->name);
+ ospf6_hook_delete (hook);
+}
+
+void
+ospf6_hook_unregister_all (struct ospf6_hook_master *master)
+{
+ struct ospf6_hook *hook, *next;
+
+ for (hook = master->head; hook; hook = next)
+ {
+ next = hook->next;
+ ospf6_hook_delete (hook);
+ }
+
+ master->head = NULL;
+ master->tail = NULL;
+ master->count = 0;
+}
+
+
+void
+ospf6_hook_init ()
+{
+ neighbor_hook.name = "Neighbor Hooklist";
+ interface_hook.name = "Interface Hooklist";
+ area_hook.name = "Area Hooklist";
+ top_hook.name = "Top Hooklist";
+ database_hook.name = "Database Hooklist";
+ intra_topology_hook.name = "IntraTopology Hooklist";
+ inter_topology_hook.name = "InterTopology Hooklist";
+ route_hook.name = "Route Hooklist";
+}
+
+
diff --git a/ospf6d/ospf6_hook.h b/ospf6d/ospf6_hook.h
new file mode 100644
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 <zebra.h>
+
+#include "ospf6_linklist.h"
+
+static struct linklist_node *
+linklist_lookup_node (void *data, struct linklist *linklist)
+{
+ struct linklist_node *node;
+
+ for (node = linklist->head; node; node = node->next)
+ {
+ if (linklist->cmp && (*linklist->cmp) (node->data, data) == 0)
+ return node;
+ if (node->data == data)
+ return node;
+ }
+
+ return NULL;
+}
+
+void *
+linklist_lookup (void *data, struct linklist *linklist)
+{
+ struct linklist_node *node;
+
+ node = linklist_lookup_node (data, linklist);
+ if (node)
+ return node->data;
+ return NULL;
+}
+
+int
+linklist_add (void *data, struct linklist *linklist)
+{
+ struct linklist_node *node = NULL, *add;
+
+ if (linklist_lookup_node (data, linklist))
+ return -1;
+
+ add = malloc (sizeof (struct linklist_node));
+ if (add == NULL)
+ return -1;
+ memset (add, 0, sizeof (struct linklist_node));
+ add->data = data;
+
+ if (linklist->cmp)
+ {
+ for (node = linklist->head; node; node = node->next)
+ {
+ if ((*linklist->cmp) (node->data, add->data) > 0)
+ break;
+ }
+ }
+
+ if (! node)
+ {
+ /* add to tail */
+ if (linklist->tail)
+ {
+ linklist->tail->next = add;
+ add->prev = linklist->tail;
+ }
+ else
+ {
+ linklist->head = add;
+ add->prev = NULL;
+ }
+
+ linklist->tail = add;
+ add->next = NULL;
+ }
+ else
+ {
+ /* insert just before 'node' */
+ if (node->prev)
+ {
+ node->prev->next = add;
+ add->prev = node->prev;
+ }
+ else
+ {
+ linklist->head = add;
+ add->prev = NULL;
+ }
+
+ add->next = node;
+ node->prev = add;
+ }
+
+ linklist->count++;
+ return 0;
+}
+
+int
+linklist_remove (void *data, struct linklist *linklist)
+{
+ struct linklist_node *rem;
+
+ rem = linklist_lookup_node (data, linklist);
+ if (rem == NULL)
+ return -1;
+
+ if (rem->prev)
+ rem->prev->next = rem->next;
+ else
+ linklist->head = rem->next;
+
+ if (rem->next)
+ rem->next->prev = rem->prev;
+ else
+ linklist->tail = rem->prev;
+
+ free (rem);
+ linklist->count--;
+ return 0;
+}
+
+void
+linklist_head (struct linklist *linklist, struct linklist_node *node)
+{
+ if (linklist->head == NULL)
+ {
+ node->prev = NULL;
+ node->next = NULL;
+ node->data = NULL;
+ return;
+ }
+
+ node->prev = linklist->head->prev;
+ node->next = linklist->head->next;
+ node->data = linklist->head->data;
+}
+
+int
+linklist_end (struct linklist_node *node)
+{
+ if (node->data == NULL && node->next == NULL)
+ return 1;
+ return 0;
+}
+
+void
+linklist_next (struct linklist_node *node)
+{
+ if (node->next == NULL)
+ {
+ node->prev = NULL;
+ node->next = NULL;
+ node->data = NULL;
+ return;
+ }
+
+ node->data = node->next->data;
+ node->prev = node->next->prev;
+ node->next = node->next->next;
+}
+
+struct linklist *
+linklist_create ()
+{
+ struct linklist *linklist;
+
+ linklist = malloc (sizeof (struct linklist));
+ if (linklist == NULL)
+ return NULL;
+ memset (linklist, 0, sizeof (struct linklist));
+
+ return linklist;
+}
+
+void
+linklist_remove_all (struct linklist *linklist)
+{
+ struct linklist_node node;
+
+ for (linklist_head (linklist, &node); ! linklist_end (&node);
+ linklist_next (&node))
+ linklist_remove (node.data, linklist);
+}
+
+void
+linklist_delete (struct linklist *linklist)
+{
+ linklist_remove_all (linklist);
+ assert (linklist->count == 0);
+ assert (linklist->head == NULL);
+ assert (linklist->tail == NULL);
+
+ free (linklist);
+}
+
+
diff --git a/ospf6d/ospf6_linklist.h b/ospf6d/ospf6_linklist.h
new file mode 100644
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 <zebra.h>
+
+/* Include other stuffs */
+#include "version.h"
+#include "log.h"
+#include "getopt.h"
+#include "linklist.h"
+#include "thread.h"
+#include "command.h"
+#include "memory.h"
+#include "sockunion.h"
+#include "if.h"
+#include "prefix.h"
+#include "stream.h"
+#include "thread.h"
+#include "filter.h"
+#include "zclient.h"
+#include "table.h"
+#include "plist.h"
+
+#include "ospf6_proto.h"
+#include "ospf6_prefix.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_message.h"
+#include "ospf6_dump.h"
+
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_ism.h"
+#include "ospf6_nsm.h"
+#include "ospf6_dbex.h"
+
+#define HEADER_DEPENDENCY
+#include "ospf6d.h"
+#undef HEADER_DEPENDENCY
+
+/* test LSAs identity */
+static int
+ospf6_lsa_issame (struct ospf6_lsa_header__ *lsh1,
+ struct ospf6_lsa_header__ *lsh2)
+{
+ assert (lsh1 && lsh2);
+
+ if (lsh1->adv_router != lsh2->adv_router)
+ return 0;
+
+ if (lsh1->id != lsh2->id)
+ return 0;
+
+ if (lsh1->type != lsh2->type)
+ return 0;
+
+ return 1;
+}
+
+/* RFC2328: Section 13.2 */
+int
+ospf6_lsa_differ (struct ospf6_lsa *lsa1,
+ struct ospf6_lsa *lsa2)
+{
+ int diff, cmplen;
+
+ if (! ospf6_lsa_issame (lsa1->header, lsa2->header))
+ return 1;
+
+ /* check Options field */
+ /* xxx */
+
+ ospf6_lsa_age_current (lsa1);
+ ospf6_lsa_age_current (lsa2);
+ if (ntohs (lsa1->header->age) == MAXAGE &&
+ ntohs (lsa2->header->age) != MAXAGE)
+ return 1;
+ if (ntohs (lsa1->header->age) != MAXAGE &&
+ ntohs (lsa2->header->age) == MAXAGE)
+ return 1;
+
+ /* compare body */
+ if (ntohs (lsa1->header->length) != ntohs (lsa2->header->length))
+ return 1;
+
+ cmplen = ntohs (lsa1->header->length) - sizeof (struct ospf6_lsa_header);
+ diff = memcmp (lsa1->header + 1, lsa2->header + 1, cmplen);
+
+ return diff;
+}
+
+int
+ospf6_lsa_match (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+ struct ospf6_lsa_header *lsh)
+{
+ if (lsh->advrtr != adv_router)
+ return 0;
+
+ if (lsh->ls_id != id)
+ return 0;
+
+ if (lsh->type != type)
+ return 0;
+
+ return 1;
+}
+
+/* ospf6 age functions */
+/* calculate birth and set expire timer */
+static void
+ospf6_lsa_age_set (struct ospf6_lsa *lsa)
+{
+ struct timeval now;
+
+ assert (lsa && lsa->header);
+
+ if (gettimeofday (&now, (struct timezone *)NULL) < 0)
+ zlog_warn ("LSA: gettimeofday failed, may fail LSA AGEs: %s",
+ strerror (errno));
+
+ lsa->birth.tv_sec = now.tv_sec - ntohs (lsa->header->age);
+ lsa->birth.tv_usec = now.tv_usec;
+ if (ntohs (lsa->header->age) != MAXAGE)
+ lsa->expire = thread_add_timer (master, ospf6_lsa_expire, lsa,
+ lsa->birth.tv_sec + MAXAGE - now.tv_sec);
+ else
+ lsa->expire = NULL;
+ return;
+}
+
+/* this function calculates current age from its birth,
+ then update age field of LSA header. return value is current age */
+u_int16_t
+ospf6_lsa_age_current (struct ospf6_lsa *lsa)
+{
+ struct timeval now;
+ u_int32_t ulage;
+ u_int16_t age;
+
+ assert (lsa);
+ assert (lsa->header);
+
+ /* current time */
+ if (gettimeofday (&now, (struct timezone *)NULL) < 0)
+ zlog_warn ("LSA: gettimeofday failed, may fail ages: %s",
+ strerror (errno));
+
+ /* calculate age */
+ ulage = now.tv_sec - lsa->birth.tv_sec;
+
+ /* if over MAXAGE, set to it */
+ if (ulage > MAXAGE)
+ age = MAXAGE;
+ else
+ age = ulage;
+
+ lsa->header->age = htons (age);
+ return age;
+}
+
+/* update age field of LSA header with adding InfTransDelay */
+void
+ospf6_lsa_age_update_to_send (struct ospf6_lsa *lsa, u_int32_t transdelay)
+{
+ unsigned short age;
+
+ age = ospf6_lsa_age_current (lsa) + transdelay;
+ if (age > MAXAGE)
+ age = MAXAGE;
+ lsa->header->age = htons (age);
+ return;
+}
+
+void
+ospf6_lsa_premature_aging (struct ospf6_lsa *lsa)
+{
+ /* log */
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("LSA: Premature aging: %s", lsa->str);
+
+ if (lsa->expire)
+ thread_cancel (lsa->expire);
+ lsa->expire = (struct thread *) NULL;
+ if (lsa->refresh)
+ thread_cancel (lsa->refresh);
+ lsa->refresh = (struct thread *) NULL;
+
+ memset (&lsa->birth, 0, sizeof (struct timeval));
+ thread_execute (master, ospf6_lsa_expire, lsa, 0);
+}
+
+/* check which is more recent. if a is more recent, return -1;
+ if the same, return 0; otherwise(b is more recent), return 1 */
+int
+ospf6_lsa_check_recent (struct ospf6_lsa *a, struct ospf6_lsa *b)
+{
+ signed long seqnuma, seqnumb;
+ u_int16_t cksuma, cksumb;
+ u_int16_t agea, ageb;
+
+ assert (a && a->header);
+ assert (b && b->header);
+ assert (ospf6_lsa_issame (a->header, b->header));
+
+ seqnuma = ((signed long) ntohl (a->header->seqnum))
+ - (signed long) INITIAL_SEQUENCE_NUMBER;
+ seqnumb = ((signed long) ntohl (b->header->seqnum))
+ - (signed long) INITIAL_SEQUENCE_NUMBER;
+
+ /* compare by sequence number */
+ /* xxx, care about LS sequence number wrapping */
+ recent_reason = "seqnum";
+ if (seqnuma > seqnumb)
+ return -1;
+ else if (seqnuma < seqnumb)
+ return 1;
+
+ /* Checksum */
+ cksuma = ntohs (a->header->checksum);
+ cksumb = ntohs (b->header->checksum);
+ if (cksuma > cksumb)
+ return -1;
+ if (cksuma < cksumb)
+ return 0;
+
+ /* Age check */
+ agea = ospf6_lsa_age_current (a);
+ ageb = ospf6_lsa_age_current (b);
+
+ /* MaxAge check */
+ recent_reason = "max age";
+ if (agea == OSPF6_LSA_MAXAGE && ageb != OSPF6_LSA_MAXAGE)
+ return -1;
+ else if (agea != OSPF6_LSA_MAXAGE && ageb == OSPF6_LSA_MAXAGE)
+ return 1;
+
+ recent_reason = "age differ";
+ if (agea > ageb && agea - ageb >= OSPF6_LSA_MAXAGEDIFF)
+ return 1;
+ else if (agea < ageb && ageb - agea >= OSPF6_LSA_MAXAGEDIFF)
+ return -1;
+
+ /* neither recent */
+ recent_reason = "the same instance";
+ return 0;
+}
+
+int
+ospf6_lsa_lsd_num (struct ospf6_lsa_header *lsa_header)
+{
+ int ldnum = 0;
+ u_int16_t len;
+
+ len = ntohs (lsa_header->length);
+ len -= sizeof (struct ospf6_lsa_header);
+ if (lsa_header->type == htons (OSPF6_LSA_TYPE_ROUTER))
+ {
+ len -= sizeof (struct ospf6_router_lsa);
+ ldnum = len / sizeof (struct ospf6_router_lsd);
+ }
+ else /* (lsa_header->type == htons (OSPF6_LSA_TYPE_NETWORK)) */
+ {
+ len -= sizeof (struct ospf6_network_lsa);
+ ldnum = len / sizeof (u_int32_t);
+ }
+
+ return ldnum;
+}
+
+void *
+ospf6_lsa_lsd_get (int index, struct ospf6_lsa_header *lsa_header)
+{
+ void *p;
+ struct ospf6_router_lsa *router_lsa;
+ struct ospf6_router_lsd *router_lsd;
+ struct ospf6_network_lsa *network_lsa;
+ struct ospf6_network_lsd *network_lsd;
+
+ if (lsa_header->type == htons (OSPF6_LSA_TYPE_ROUTER))
+ {
+ router_lsa = (struct ospf6_router_lsa *) (lsa_header + 1);
+ router_lsd = (struct ospf6_router_lsd *) (router_lsa + 1);
+ router_lsd += index;
+ p = (void *) router_lsd;
+ }
+ else if (lsa_header->type == htons (OSPF6_LSA_TYPE_NETWORK))
+ {
+ network_lsa = (struct ospf6_network_lsa *) (lsa_header + 1);
+ network_lsd = (struct ospf6_network_lsd *) (network_lsa + 1);
+ network_lsd += index;
+ p = (void *) network_lsd;
+ }
+ else
+ {
+ p = (void *) NULL;
+ }
+
+ return p;
+}
+
+/* network_lsd <-> router_lsd */
+static int
+ospf6_lsa_lsd_network_reference_match (struct ospf6_network_lsd *network_lsd1,
+ struct ospf6_lsa_header *lsa_header1,
+ struct ospf6_router_lsd *router_lsd2,
+ struct ospf6_lsa_header *lsa_header2)
+{
+ if (network_lsd1->adv_router != lsa_header2->advrtr)
+ return 0;
+ if (router_lsd2->type != OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK)
+ return 0;
+ if (router_lsd2->neighbor_router_id != lsa_header1->advrtr)
+ return 0;
+ if (router_lsd2->neighbor_interface_id != lsa_header1->ls_id)
+ return 0;
+ return 1;
+}
+
+/* router_lsd <-> router_lsd */
+static int
+ospf6_lsa_lsd_router_reference_match (struct ospf6_router_lsd *router_lsd1,
+ struct ospf6_lsa_header *lsa_header1,
+ struct ospf6_router_lsd *router_lsd2,
+ struct ospf6_lsa_header *lsa_header2)
+{
+ if (router_lsd1->type != OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT)
+ return 0;
+ if (router_lsd2->type != OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT)
+ return 0;
+ if (router_lsd1->neighbor_router_id != lsa_header2->advrtr)
+ return 0;
+ if (router_lsd2->neighbor_router_id != lsa_header1->advrtr)
+ return 0;
+ if (router_lsd1->neighbor_interface_id != router_lsd2->interface_id)
+ return 0;
+ if (router_lsd2->neighbor_interface_id != router_lsd1->interface_id)
+ return 0;
+ return 1;
+}
+
+int
+ospf6_lsa_lsd_is_refer_ok (int index1, struct ospf6_lsa_header *lsa_header1,
+ int index2, struct ospf6_lsa_header *lsa_header2)
+{
+ struct ospf6_router_lsd *r1, *r2;
+ struct ospf6_network_lsd *n;
+
+ r1 = (struct ospf6_router_lsd *) NULL;
+ r2 = (struct ospf6_router_lsd *) NULL;
+ n = (struct ospf6_network_lsd *) NULL;
+ if (lsa_header1->type == htons (OSPF6_LSA_TYPE_ROUTER))
+ r1 = (struct ospf6_router_lsd *) ospf6_lsa_lsd_get (index1, lsa_header1);
+ else
+ n = (struct ospf6_network_lsd *) ospf6_lsa_lsd_get (index1, lsa_header1);
+
+ if (lsa_header2->type == htons (OSPF6_LSA_TYPE_ROUTER))
+ r2 = (struct ospf6_router_lsd *) ospf6_lsa_lsd_get (index2, lsa_header2);
+ else
+ n = (struct ospf6_network_lsd *) ospf6_lsa_lsd_get (index2, lsa_header2);
+
+ if (r1 && r2)
+ return ospf6_lsa_lsd_router_reference_match (r1, lsa_header1,
+ r2, lsa_header2);
+ else if (r1 && n)
+ return ospf6_lsa_lsd_network_reference_match (n, lsa_header2,
+ r1, lsa_header1);
+ else if (n && r2)
+ return ospf6_lsa_lsd_network_reference_match (n, lsa_header1,
+ r2, lsa_header2);
+ return 0;
+}
+
+void
+ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+ char adv_router[64], id[64], type[32];
+
+ assert (lsa);
+ assert (lsa->header);
+
+ ospf6_lsa_type_string (lsa->header->type, type, sizeof (type));
+ inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id));
+ inet_ntop (AF_INET, &lsa->header->adv_router,
+ adv_router, sizeof (adv_router));
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "Age: %4hu Type: %s%s", ospf6_lsa_age_current (lsa),
+ type, VTY_NEWLINE);
+ vty_out (vty, "Link State ID: %s%s", id, VTY_NEWLINE);
+ vty_out (vty, "Advertising Router: %s%s", adv_router, VTY_NEWLINE);
+ vty_out (vty, "LS Sequence Number: %#lx%s", (u_long)ntohl (lsa->header->seqnum),
+ VTY_NEWLINE);
+ vty_out (vty, "CheckSum: %#hx Length: %hu%s", ntohs (lsa->header->checksum),
+ ntohs (lsa->header->length), VTY_NEWLINE);
+
+ {
+ struct ospf6_lsa_slot *slot;
+ slot = ospf6_lsa_slot_get (lsa->header->type);
+ if (slot)
+ {
+ (*slot->func_show) (vty, lsa);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ return;
+ }
+ }
+
+ vty_out (vty, "%sUnknown LSA type ...%s", VTY_NEWLINE, VTY_NEWLINE);
+}
+
+void
+ospf6_lsa_show_summary_header (struct vty *vty)
+{
+ vty_out (vty, "%-12s %-15s %-15s %4s %8s %4s %4s %-8s%s",
+ "Type", "LSId", "AdvRouter", "Age", "SeqNum",
+ "Cksm", "Len", "Duration", VTY_NEWLINE);
+}
+
+void
+ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa)
+{
+ char adv_router[16], id[16], type[16];
+ struct timeval now, res;
+ char duration[16];
+
+ assert (lsa);
+ assert (lsa->header);
+
+ memset (type, 0, sizeof (type));
+ ospf6_lsa_type_string (lsa->header->type, type, 13);
+ inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id));
+ inet_ntop (AF_INET, &lsa->header->adv_router, adv_router,
+ sizeof (adv_router));
+
+ gettimeofday (&now, NULL);
+ ospf6_timeval_sub (&now, &lsa->installed, &res);
+ ospf6_timeval_string_summary (&res, duration, sizeof (duration));
+
+ vty_out (vty, "%-12s %-15s %-15s %4hu %8lx %04hx %4hu %8s%s",
+ type, id, adv_router, ospf6_lsa_age_current (lsa),
+ (u_long) ntohl (lsa->header->seqnum),
+ ntohs (lsa->header->checksum), ntohs (lsa->header->length),
+ duration, VTY_NEWLINE);
+}
+
+void
+ospf6_lsa_show_dump (struct vty *vty, struct ospf6_lsa *lsa)
+{
+ u_char *start, *end, *current;
+ char byte[4];
+
+ start = (char *) lsa->header;
+ end = (char *) lsa->header + ntohs (lsa->header->length);
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "%s:%s", lsa->str, VTY_NEWLINE);
+
+ for (current = start; current < end; current ++)
+ {
+ if ((current - start) % 16 == 0)
+ vty_out (vty, "%s ", VTY_NEWLINE);
+ else if ((current - start) % 4 == 0)
+ vty_out (vty, " ");
+
+ snprintf (byte, sizeof (byte), "%02x", *current);
+ vty_out (vty, "%s", byte);
+ }
+
+ vty_out (vty, "%s%s", VTY_NEWLINE, VTY_NEWLINE);
+}
+
+/* OSPFv3 LSA creation/deletion function */
+
+/* calculate LS sequence number for my new LSA.
+ return value is network byte order */
+static signed long
+ospf6_lsa_seqnum_new (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+ void *scope)
+{
+ struct ospf6_lsa *lsa;
+ signed long seqnum;
+
+ /* get current database copy */
+ lsa = ospf6_lsdb_lookup (type, id, adv_router, scope);
+
+ /* if current database copy not found, return InitialSequenceNumber */
+ if (!lsa)
+ seqnum = INITIAL_SEQUENCE_NUMBER;
+ else
+ seqnum = (signed long) ntohl (lsa->header->seqnum) + 1;
+
+ return (htonl (seqnum));
+}
+
+#if 0
+static void
+ospf6_lsa_header_set (u_int16_t type, u_int32_t ls_id, u_int32_t advrtr,
+ struct ospf6_lsa_header *lsa_header, int bodysize)
+{
+ /* fill LSA header */
+ lsa_header->age = 0;
+ lsa_header->type = type;
+ lsa_header->ls_id = ls_id;
+ lsa_header->advrtr = advrtr;
+ lsa_header->seqnum =
+ ospf6_lsa_seqnum_new (lsa_header->type, lsa_header->ls_id,
+ lsa_header->advrtr);
+ lsa_header->length = htons (sizeof (struct ospf6_lsa_header) + bodysize);
+
+ /* LSA checksum */
+ ospf6_lsa_checksum (lsa_header);
+}
+#endif /*0*/
+
+struct ospf6_lsa *
+ospf6_lsa_create (struct ospf6_lsa_header *source)
+{
+ struct ospf6_lsa *lsa = NULL;
+ struct ospf6_lsa_header *lsa_header = NULL;
+ u_int16_t lsa_size = 0;
+ char buf_router[16], buf_id[16], typebuf[32];
+
+ /* whole length of this LSA */
+ lsa_size = ntohs (source->length);
+
+ /* allocate memory for this LSA */
+ lsa_header = (struct ospf6_lsa_header *)
+ XMALLOC (MTYPE_OSPF6_LSA, lsa_size);
+ if (! lsa_header)
+ {
+ zlog_err ("Can't allocate memory for LSA Header");
+ return (struct ospf6_lsa *) NULL;
+ }
+ memset (lsa_header, 0, lsa_size);
+
+ /* copy LSA from source */
+ memcpy (lsa_header, source, lsa_size);
+
+ /* LSA information structure */
+ /* allocate memory */
+ lsa = (struct ospf6_lsa *)
+ XMALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa));
+ memset (lsa, 0, sizeof (struct ospf6_lsa));
+
+ lsa->lsa_hdr = (struct ospf6_lsa_hdr *) lsa_header;
+ lsa->header = (struct ospf6_lsa_header__ *) lsa_header;
+
+ lsa->summary = 0; /* this is not LSA summary */
+
+ /* dump string */
+ inet_ntop (AF_INET, &lsa->header->id, buf_id, sizeof (buf_id));
+ inet_ntop (AF_INET, &lsa->header->adv_router, buf_router,
+ sizeof (buf_router));
+ snprintf (lsa->str, sizeof (lsa->str), "[%s ID=%s Adv=%s]",
+ ospf6_lsa_type_string (lsa_header->type, typebuf,
+ sizeof (typebuf)),
+ buf_id, buf_router);
+
+ /* calculate birth, expire and refresh of this lsa */
+ ospf6_lsa_age_set (lsa);
+
+#ifdef DEBUG
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("Create: %s (%p/%p)", lsa->str, lsa, lsa->header);
+#endif /*DEBUG*/
+
+ return lsa;
+}
+
+struct ospf6_lsa *
+ospf6_lsa_summary_create (struct ospf6_lsa_header__ *source)
+{
+ struct ospf6_lsa *lsa = NULL;
+ struct ospf6_lsa_header *lsa_header = NULL;
+ u_int16_t lsa_size = 0;
+ char buf_router[16], buf_id[16], typebuf[16];
+
+ /* LSA summary contains LSA Header only */
+ lsa_size = sizeof (struct ospf6_lsa_header);
+
+ /* allocate memory for this LSA */
+ lsa_header = (struct ospf6_lsa_header *)
+ XMALLOC (MTYPE_OSPF6_LSA_SUMMARY, lsa_size);
+ memset (lsa_header, 0, lsa_size);
+
+ /* copy LSA from source */
+ memcpy (lsa_header, source, lsa_size);
+
+ /* LSA information structure */
+ /* allocate memory */
+ lsa = (struct ospf6_lsa *)
+ XMALLOC (MTYPE_OSPF6_LSA_SUMMARY, sizeof (struct ospf6_lsa));
+ memset (lsa, 0, sizeof (struct ospf6_lsa));
+
+ lsa->lsa_hdr = (struct ospf6_lsa_hdr *) lsa_header;
+ lsa->header = (struct ospf6_lsa_header__ *) lsa_header;
+ lsa->summary = 1; /* this is LSA summary */
+
+ /* dump string */
+ inet_ntop (AF_INET, &lsa->header->id, buf_id, sizeof (buf_id));
+ inet_ntop (AF_INET, &lsa->header->adv_router, buf_router,
+ sizeof (buf_router));
+ snprintf (lsa->str, sizeof (lsa->str), "[%s Summary ID=%s Adv=%s]",
+ ospf6_lsa_type_string (lsa->header->type, typebuf,
+ sizeof (typebuf)),
+ buf_id, buf_router);
+
+ /* calculate birth, expire and refresh of this lsa */
+ ospf6_lsa_age_set (lsa);
+
+#ifdef DEBUG
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("Create: %s (%p/%p)", lsa->str, lsa, lsa->header);
+#endif /*DEBUG*/
+
+ return lsa;
+}
+
+void
+ospf6_lsa_delete (struct ospf6_lsa *lsa)
+{
+ /* just to make sure */
+ if (lsa->lock != 0)
+ {
+ zlog_err ("Can't delete %s: lock: %ld", lsa->str, lsa->lock);
+ return;
+ }
+
+ /* cancel threads */
+ if (lsa->expire)
+ thread_cancel (lsa->expire);
+ lsa->expire = (struct thread *) NULL;
+ if (lsa->refresh)
+ thread_cancel (lsa->refresh);
+ lsa->refresh = (struct thread *) NULL;
+
+#ifdef DEBUG
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("Delete %s (%p/%p)", lsa->str, lsa, lsa->header);
+#endif /*DEBUG*/
+
+ /* do free */
+ if (lsa->summary)
+ XFREE (MTYPE_OSPF6_LSA_SUMMARY, lsa->header);
+ else
+ XFREE (MTYPE_OSPF6_LSA, lsa->header);
+ lsa->header = NULL;
+
+ if (lsa->summary)
+ XFREE (MTYPE_OSPF6_LSA_SUMMARY, lsa);
+ else
+ XFREE (MTYPE_OSPF6_LSA, lsa);
+}
+
+/* increment reference counter of struct ospf6_lsa */
+void
+ospf6_lsa_lock (struct ospf6_lsa *lsa)
+{
+ lsa->lock++;
+ return;
+}
+
+/* decrement reference counter of struct ospf6_lsa */
+void
+ospf6_lsa_unlock (struct ospf6_lsa *lsa)
+{
+ /* decrement reference counter */
+ if (lsa->lock > 0)
+ lsa->lock--;
+ else
+ zlog_warn ("Can't unlock %s: already no lock", lsa->str);
+
+ if (lsa->lock == 0)
+ ospf6_lsa_delete (lsa);
+}
+
+void
+ospf6_lsa_originate (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+ char *data, int data_len, void *scope)
+{
+ char buffer[MAXLSASIZE];
+ struct ospf6_lsa_header *lsa_header;
+ struct ospf6_lsa *lsa;
+ struct ospf6_lsa *old;
+
+ assert (data_len <= sizeof (buffer) - sizeof (struct ospf6_lsa_header));
+
+ lsa_header = (struct ospf6_lsa_header *) buffer;
+
+ /* Copy LSA Body */
+ memcpy (buffer + sizeof (struct ospf6_lsa_header), data, data_len);
+
+ /* Fill LSA Header */
+ lsa_header->age = 0;
+ lsa_header->type = type;
+ lsa_header->ls_id = id;
+ lsa_header->advrtr = adv_router;
+ lsa_header->seqnum =
+ ospf6_lsa_seqnum_new (lsa_header->type, lsa_header->ls_id,
+ lsa_header->advrtr, scope);
+ lsa_header->length = htons (sizeof (struct ospf6_lsa_header) + data_len);
+
+ /* LSA checksum */
+ ospf6_lsa_checksum (lsa_header);
+
+ /* create LSA */
+ lsa = ospf6_lsa_create ((struct ospf6_lsa_header *) buffer);
+ lsa->scope = scope;
+
+ /* find previous LSA */
+ old = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id,
+ lsa->header->adv_router, lsa->scope);
+ if (old)
+ {
+ /* Check if this is neither different instance nor refresh, return */
+ if (! CHECK_FLAG (old->flag, OSPF6_LSA_FLAG_REFRESH) &&
+ ! ospf6_lsa_differ (lsa, old))
+ {
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("LSA: Suppress updating %s", lsa->str);
+ ospf6_lsa_delete (lsa);
+ return;
+ }
+ }
+
+ lsa->refresh = thread_add_timer (master, ospf6_lsa_refresh, lsa,
+ OSPF6_LS_REFRESH_TIME);
+ gettimeofday (&lsa->originated, NULL);
+
+ //if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("LSA: originate %s seq: %#x age: %hu %ld.%06ld",
+ lsa->str, ntohl (lsa->header->seqnum),
+ ospf6_lsa_age_current (lsa),
+ lsa->originated.tv_sec, lsa->originated.tv_usec);
+
+ ospf6_dbex_remove_from_all_retrans_list (lsa);
+ ospf6_dbex_flood (lsa, NULL);
+ ospf6_lsdb_install (lsa);
+}
+
+
+/* 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 <zebra.h>
+
+#include "memory.h"
+#include "log.h"
+#include "command.h"
+#include "if.h"
+
+#include "ospf6_dump.h"
+#include "ospf6_lsdb.h"
+
+#include "ospf6_interface.h"
+#include "ospf6_area.h"
+#include "ospf6_top.h"
+
+#define OSPF6_LSDB_MATCH_TYPE 0x01
+#define OSPF6_LSDB_MATCH_ID 0x02
+#define OSPF6_LSDB_MATCH_ADV_ROUTER 0x04
+#define OSPF6_LSDB_SHOW_DUMP 0x08
+#define OSPF6_LSDB_SHOW_DETAIL 0x10
+
+struct ospf6_lsdb_hook_t hooks[0x2000];
+struct ospf6_lsdb_hook_t *ospf6_lsdb_hook = hooks;
+
+struct ospf6_lsdb *
+ospf6_lsdb_create ()
+{
+ struct ospf6_lsdb *lsdb;
+
+ lsdb = XCALLOC (MTYPE_OSPF6_LSDB, sizeof (struct ospf6_lsdb));
+ if (lsdb == NULL)
+ {
+ zlog_warn ("Can't malloc lsdb");
+ return NULL;
+ }
+ memset (lsdb, 0, sizeof (struct ospf6_lsdb));
+
+ lsdb->table = route_table_init ();
+ return lsdb;
+}
+
+void
+ospf6_lsdb_delete (struct ospf6_lsdb *lsdb)
+{
+ ospf6_lsdb_remove_all (lsdb);
+ route_table_finish (lsdb->table);
+ XFREE (MTYPE_OSPF6_LSDB, lsdb);
+}
+
+static void
+ospf6_lsdb_set_key (struct prefix_ipv6 *key, int flag,
+ u_int16_t type, u_int32_t id, u_int32_t adv_router)
+{
+ int len = 0;
+ memset (key, 0, sizeof (struct prefix_ipv6));
+
+ if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_TYPE))
+ {
+ len += 2;
+ if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_ADV_ROUTER))
+ {
+ len += 4;
+ if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_ID))
+ len += 4;
+ }
+ }
+
+ if (len > 0)
+ memcpy ((char *)&key->prefix, &type, 2);
+ if (len > 2)
+ memcpy ((char *)&key->prefix + 2, &adv_router, 4);
+ if (len > 6)
+ memcpy ((char *)&key->prefix + 6, &id, 4);
+
+ key->family = AF_INET6;
+ key->prefixlen = len * 8;
+}
+
+void
+ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb)
+{
+ int flag;
+ struct prefix_ipv6 key;
+ struct route_node *rn;
+ struct ospf6_lsa *old = NULL;
+
+ flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ID |
+ OSPF6_LSDB_MATCH_ADV_ROUTER;
+ ospf6_lsdb_set_key (&key, flag, lsa->header->type, lsa->header->id,
+ lsa->header->adv_router);
+
+ rn = route_node_get (lsdb->table, (struct prefix *) &key);
+ if (rn->info)
+ old = rn->info;
+ rn->info = lsa;
+ ospf6_lsa_lock (lsa);
+
+ if (old)
+ ospf6_lsa_unlock (old);
+ else
+ lsdb->count++;
+}
+
+void
+ospf6_lsdb_remove (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb)
+{
+ int flag;
+ struct prefix_ipv6 key;
+ struct route_node *rn;
+ struct ospf6_lsa *old;
+
+ flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ID |
+ OSPF6_LSDB_MATCH_ADV_ROUTER;
+ ospf6_lsdb_set_key (&key, flag, lsa->header->type, lsa->header->id,
+ lsa->header->adv_router);
+
+ rn = route_node_lookup (lsdb->table, (struct prefix *) &key);
+ if (! rn || ! rn->info)
+ {
+ zlog_warn ("LSDB: Can't remove: no such LSA: %s", lsa->str);
+ return;
+ }
+
+ old = rn->info;
+ if (old != lsa)
+ {
+ zlog_warn ("LSDB: Can't remove: different instance: %s (%p <-> %p) %s",
+ lsa->str, lsa, old, old->str);
+ return;
+ }
+
+ rn->info = NULL;
+ ospf6_lsa_unlock (old);
+ lsdb->count--;
+}
+
+static void
+ospf6_lsdb_lookup_node (struct ospf6_lsdb_node *node,
+ u_int16_t type, u_int32_t id, u_int32_t adv_router,
+ struct ospf6_lsdb *lsdb)
+{
+ int flag;
+ struct route_node *rn;
+
+ memset (node, 0, sizeof (struct ospf6_lsdb_node));
+
+ flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ID |
+ OSPF6_LSDB_MATCH_ADV_ROUTER;
+ ospf6_lsdb_set_key (&node->key, flag, type, id, adv_router);
+
+ rn = route_node_lookup (lsdb->table, (struct prefix *) &node->key);
+ if (! rn || ! rn->info)
+ return;
+
+ node->node = rn;
+ node->next = route_next (rn);
+ node->lsa = rn->info;
+ if (node->next != NULL)
+ route_unlock_node (node->next);
+}
+
+struct ospf6_lsa *
+ospf6_lsdb_lookup_lsdb (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+ struct ospf6_lsdb *lsdb)
+{
+ struct ospf6_lsdb_node node;
+ ospf6_lsdb_lookup_node (&node, type, id, adv_router, lsdb);
+ return node.lsa;
+}
+
+/* Iteration function */
+void
+ospf6_lsdb_head (struct ospf6_lsdb_node *node, struct ospf6_lsdb *lsdb)
+{
+ struct route_node *rn;
+
+ memset (node, 0, sizeof (struct ospf6_lsdb_node));
+
+ rn = route_top (lsdb->table);
+ if (rn == NULL)
+ return;
+
+ while (rn && rn->info == NULL)
+ rn = route_next (rn);
+
+ if (rn && rn->info)
+ {
+ node->node = rn;
+ node->next = route_next (rn);
+ node->lsa = rn->info;
+ if (node->next != NULL)
+ route_unlock_node (node->next);
+ }
+}
+
+void
+ospf6_lsdb_type (struct ospf6_lsdb_node *node, u_int16_t type,
+ struct ospf6_lsdb *lsdb)
+{
+ int flag;
+ struct route_node *rn;
+
+ memset (node, 0, sizeof (struct ospf6_lsdb_node));
+
+ flag = OSPF6_LSDB_MATCH_TYPE;
+ ospf6_lsdb_set_key (&node->key, flag, type, 0, 0);
+
+ /* get the closest radix node */
+ rn = route_node_get (lsdb->table, (struct prefix *) &node->key);
+
+ /* skip to the real existing lsdb entry */
+ while (rn && rn->info == NULL && rn->p.prefixlen >= node->key.prefixlen &&
+ prefix_match ((struct prefix *) &node->key, &rn->p))
+ rn = route_next (rn);
+
+ if (rn && rn->info)
+ {
+ node->node = rn;
+ node->next = route_next (rn);
+ node->lsa = rn->info;
+ if (node->next != NULL)
+ route_unlock_node (node->next);
+ }
+}
+
+void
+ospf6_lsdb_type_router (struct ospf6_lsdb_node *node,
+ u_int16_t type, u_int32_t adv_router,
+ struct ospf6_lsdb *lsdb)
+{
+ int flag;
+ struct route_node *rn;
+
+ memset (node, 0, sizeof (struct ospf6_lsdb_node));
+
+ flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ADV_ROUTER;
+ ospf6_lsdb_set_key (&node->key, flag, type, 0, adv_router);
+
+ /* get the closest radix node */
+ rn = route_node_get (lsdb->table, (struct prefix *) &node->key);
+
+ /* skip to the real existing lsdb entry */
+ while (rn && rn->info == NULL && rn->p.prefixlen >= node->key.prefixlen &&
+ prefix_match ((struct prefix *) &node->key, &rn->p))
+ rn = route_next (rn);
+
+ if (rn && rn->info)
+ {
+ node->node = rn;
+ node->next = route_next (rn);
+ node->lsa = rn->info;
+ if (node->next != NULL)
+ route_unlock_node (node->next);
+ }
+}
+
+void
+ospf6_lsdb_next (struct ospf6_lsdb_node *node)
+{
+ struct route_node *rn;
+
+ route_lock_node (node->node);
+ rn = route_next (node->node);
+
+ /* skip to the real existing lsdb entry */
+ while (rn && rn->info == NULL && rn->p.prefixlen >= node->key.prefixlen &&
+ prefix_match ((struct prefix *) &node->key, &rn->p))
+ rn = route_next (rn);
+
+ if (rn && rn->info && rn->p.prefixlen >= node->key.prefixlen &&
+ prefix_match ((struct prefix *) &node->key, &rn->p))
+ {
+ node->node = rn;
+ node->next = route_next (rn);
+ node->lsa = rn->info;
+ if (node->next != NULL)
+ route_unlock_node (node->next);
+ }
+ else
+ {
+ node->node = NULL;
+ node->next = NULL;
+ node->lsa = NULL;
+ }
+}
+
+struct ospf6_lsa *
+ospf6_lsdb_lookup (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+ void *scope)
+{
+ struct ospf6_interface *o6i;
+ struct ospf6_area *o6a;
+ listnode i, j;
+
+ if (scope == (void *) ospf6)
+ return ospf6_lsdb_lookup_lsdb (type, id, adv_router, ospf6->lsdb);
+
+ for (i = listhead (ospf6->area_list); i; nextnode (i))
+ {
+ o6a = getdata (i);
+
+ if (scope == (void *) o6a)
+ return ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6a->lsdb);
+
+ for (j = listhead (o6a->if_list); j; nextnode (j))
+ {
+ o6i = getdata (j);
+
+ if (scope == (void *) o6i)
+ return ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6i->lsdb);
+ }
+ }
+
+ zlog_warn ("LSDB: Can't lookup: unknown scope, type %#hx", ntohs (type));
+ return NULL;
+}
+
+void
+ospf6_lsdb_install (struct ospf6_lsa *new)
+{
+ struct ospf6_lsdb *lsdb;
+ struct ospf6_lsa *old;
+ int need_hook = 0;
+ void (*hook) (struct ospf6_lsa *, struct ospf6_lsa *);
+
+ struct ospf6 *as = NULL;
+ struct ospf6_area *area = NULL;
+ struct ospf6_interface *linklocal = NULL;
+ hook = NULL;
+
+ switch (ntohs (new->header->type) & OSPF6_LSTYPE_SCOPE_MASK)
+ {
+ case OSPF6_LSA_SCOPE_LINKLOCAL:
+ linklocal = (struct ospf6_interface *) new->scope;
+ lsdb = linklocal->lsdb;
+ break;
+ case OSPF6_LSA_SCOPE_AREA:
+ area = (struct ospf6_area *) new->scope;
+ lsdb = area->lsdb;
+ break;
+ case OSPF6_LSA_SCOPE_AS:
+ as = (struct ospf6 *) new->scope;
+ lsdb = as->lsdb;
+ break;
+ default:
+ zlog_warn ("LSDB: Can't install: scope unknown: %s", new->str);
+ return;
+ }
+
+ /* whether schedule calculation or not */
+ old = ospf6_lsdb_lookup_lsdb (new->header->type, new->header->id,
+ new->header->adv_router, lsdb);
+
+ if (! old || ospf6_lsa_differ (old, new))
+ need_hook++;
+
+ /* log */
+ if (IS_OSPF6_DUMP_LSDB)
+ zlog_info ("LSDB: Install: %s %s", new->str,
+ ((IS_LSA_MAXAGE (new)) ? "(MaxAge)" : ""));
+
+ if (old)
+ ospf6_lsa_lock (old);
+
+ ospf6_lsdb_add (new, lsdb);
+ gettimeofday (&new->installed, NULL);
+
+ hook = ospf6_lsdb_hook[ntohs (new->header->type) &
+ OSPF6_LSTYPE_CODE_MASK].hook;
+ if (need_hook && hook)
+ (*hook) (old, new);
+
+ /* old LSA should be freed here */
+ if (old)
+ ospf6_lsa_unlock (old);
+}
+
+void
+ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb)
+{
+ struct ospf6_lsdb_node node;
+ for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ ospf6_lsdb_remove (node.lsa, lsdb);
+}
+
+void
+ospf6_lsdb_remove_maxage (struct ospf6_lsdb *lsdb)
+{
+ struct ospf6_lsdb_node node;
+ struct ospf6_lsa *lsa;
+
+ for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ {
+ lsa = node.lsa;
+
+ /* contiue if it's not MaxAge */
+ if (! IS_LSA_MAXAGE (lsa))
+ continue;
+
+ /* continue if it's referenced by some retrans-lists */
+ if (lsa->lock != 1)
+ continue;
+
+ if (IS_OSPF6_DUMP_LSDB)
+ zlog_info ("Remove MaxAge LSA: %s", lsa->str);
+
+ ospf6_lsdb_remove (lsa, lsdb);
+ }
+}
+
+
+
+/* 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 <zebra.h>
+#include "getopt.h"
+#include "thread.h"
+#include "log.h"
+#include "version.h"
+#include "command.h"
+#include "vty.h"
+#include "memory.h"
+
+#include "ospf6d.h"
+#include "ospf6_network.h"
+
+void ospf6_init ();
+void ospf6_terminate ();
+void nexthop_init ();
+int ospf6_receive (struct thread *);
+
+extern int ospf6_sock;
+
+/* Default configuration file name for ospf6d. */
+#define OSPF6_DEFAULT_CONFIG "ospf6d.conf"
+/* Default port values. */
+#define OSPF6_VTY_PORT 2606
+
+/* ospf6d options, we use GNU getopt library. */
+struct option longopts[] =
+{
+ { "daemon", no_argument, NULL, 'd'},
+ { "config_file", required_argument, NULL, 'f'},
+ { "pid_file", required_argument, NULL, 'i'},
+ { "vty_addr", required_argument, NULL, 'A'},
+ { "vty_port", required_argument, NULL, 'P'},
+ { "version", no_argument, NULL, 'v'},
+ { "help", no_argument, NULL, 'h'},
+ { 0 }
+};
+
+/* Configuration file and directory. */
+char config_current[] = OSPF6_DEFAULT_CONFIG;
+char config_default[] = SYSCONFDIR OSPF6_DEFAULT_CONFIG;
+
+/* ospf6d program name. */
+
+/* is daemon? */
+int daemon_mode = 0;
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* Process ID saved for use by init system */
+char *pid_file = PATH_OSPF6D_PID;
+
+/* for reload */
+char _cwd[64];
+char _progpath[64];
+int _argc;
+char **_argv;
+char **_envp;
+
+/* Help information display. */
+static void
+usage (char *progname, int status)
+{
+ if (status != 0)
+ fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+ else
+ {
+ printf ("Usage : %s [OPTION...]\n\n\
+Daemon which manages OSPF version 3.\n\n\
+-d, --daemon Runs in daemon mode\n\
+-f, --config_file Set configuration file name\n\
+-i, --pid_file Set process identifier file name\n\
+-A, --vty_addr Set vty's bind address\n\
+-P, --vty_port Set vty's port number\n\
+-v, --version Print program version\n\
+-h, --help Display this help and exit\n\
+\n\
+Report bugs to yasu@sfc.wide.ad.jp\n", progname);
+ }
+
+ exit (status);
+}
+
+
+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 <zebra.h>
+
+#include "log.h"
+#include "thread.h"
+#include "linklist.h"
+#include "vty.h"
+#include "command.h"
+
+#include "ospf6_lsa.h"
+#include "ospf6_message.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_nsm.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+
+char *ospf6_neighbor_state_string[] =
+{
+ "None", "Down", "Attempt", "Init", "Twoway",
+ "ExStart", "ExChange", "Loading", "Full", NULL
+};
+
+int
+ospf6_neighbor_last_dbdesc_release (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+ memset (&o6n->last_dd, 0, sizeof (struct ospf6_dbdesc));
+ return 0;
+}
+
+
+
+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 <zebra.h>
+#include "memory.h"
+#include "log.h"
+#include "sockunion.h"
+
+#include "ospf6d.h"
+#include "ospf6_proto.h"
+
+extern int errno;
+extern struct sockaddr_in6 allspfrouters6;
+extern struct sockaddr_in6 alldrouters6;
+extern int ospf6_sock;
+extern struct thread_master *master;
+
+/* iovec functions */
+void
+iov_clear (struct iovec *iov, size_t iovlen)
+{
+ int i;
+ for (i = 0; i < iovlen; i++)
+ {
+ iov[i].iov_base = NULL;
+ iov[i].iov_len = 0;
+ }
+}
+
+int
+iov_count (struct iovec *iov)
+{
+ int i;
+ for (i = 0; iov[i].iov_base; i++)
+ ;
+ return i;
+}
+
+int
+iov_totallen (struct iovec *iov)
+{
+ int i;
+ int totallen = 0;
+ for (i = 0; iov[i].iov_base; i++)
+ totallen += iov[i].iov_len;
+ return totallen;
+}
+
+void *
+iov_prepend (int mtype, struct iovec *iov, size_t len)
+{
+ int i, iovlen;
+ void *base;
+
+ base = (void *) XMALLOC (mtype, len);
+ if (!base)
+ {
+ zlog_warn ("Network: iov_prepend failed");
+ return NULL;
+ }
+ memset (base, 0, len);
+
+ iovlen = iov_count (iov);
+ for (i = iovlen; i; i--)
+ {
+ iov[i].iov_base = iov[i - 1].iov_base;
+ iov[i].iov_len = iov[i - 1].iov_len;
+ }
+ iov[0].iov_base = (char *)base;
+ iov[0].iov_len = len;
+
+ return base;
+}
+
+void *
+iov_append (int mtype, struct iovec *iov, size_t len)
+{
+ int i;
+ void *base;
+
+ base = (void *)XMALLOC (mtype, len);
+ if (!base)
+ {
+ zlog_warn ("Network: iov_append failed");
+ return NULL;
+ }
+ memset (base, 0, len);
+
+ /* proceed to the end */
+ i = iov_count (iov);
+
+ iov[i].iov_base = (char *)base;
+ iov[i].iov_len = len;
+
+ return base;
+}
+
+void *
+iov_attach_last (struct iovec *iov, void *base, size_t len)
+{
+ int i;
+ i = iov_count (iov);
+ iov[i].iov_base = (char *)base;
+ iov[i].iov_len = len;
+ return base;
+}
+
+void *
+iov_detach_first (struct iovec *iov)
+{
+ int i, iovlen;
+ void *base;
+ size_t len;
+
+ base = iov[0].iov_base;
+ len = iov[0].iov_len;
+ iovlen = iov_count (iov);
+ for (i = 0; i < iovlen; i++)
+ {
+ iov[i].iov_base = iov[i + 1].iov_base;
+ iov[i].iov_len = iov[i + 1].iov_len;
+ }
+ return base;
+}
+
+int
+iov_free (int mtype, struct iovec *iov, u_int begin, u_int end)
+{
+ int i;
+
+ for (i = begin; i < end; i++)
+ {
+ XFREE (mtype, iov[i].iov_base);
+ iov[i].iov_base = NULL;
+ iov[i].iov_len = 0;
+ }
+
+ return 0;
+}
+
+void
+iov_trim_head (int mtype, struct iovec *iov)
+{
+ void *base;
+
+ base = iov_detach_first (iov);
+ XFREE (mtype, base);
+ return;
+}
+
+void
+iov_free_all (int mtype, struct iovec *iov)
+{
+ int i, end = iov_count (iov);
+ for (i = 0; i < end; i++)
+ {
+ XFREE (mtype, iov[i].iov_base);
+ iov[i].iov_base = NULL;
+ iov[i].iov_len = 0;
+ }
+}
+
+void
+iov_copy_all (struct iovec *dst, struct iovec *src, size_t size)
+{
+ int i;
+ for (i = 0; i < size; i++)
+ {
+ dst[i].iov_base = src[i].iov_base;
+ dst[i].iov_len = src[i].iov_len;
+ }
+}
+
+
+/* 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 <zebra.h>
+
+#include "log.h"
+#include "prefix.h"
+#include "memory.h"
+#include "linklist.h"
+
+#include "ospf6_prefix.h"
+
+#else /*0*/
+
+#include "ospf6d.h"
+
+#endif /*0*/
+
+struct ospf6_prefix *
+ospf6_prefix_create (u_int8_t options, u_int16_t metric, struct prefix_ipv6 *p)
+{
+ struct prefix_ipv6 prefix;
+ struct ospf6_prefix *o6p;
+ size_t size;
+
+ /* copy prefix and apply mask */
+ prefix_copy ((struct prefix *) &prefix, (struct prefix *) p);
+ apply_mask_ipv6 (&prefix);
+
+ size = OSPF6_PREFIX_SPACE (prefix.prefixlen) + sizeof (struct ospf6_prefix);
+ o6p = (struct ospf6_prefix *) XMALLOC (MTYPE_OSPF6_PREFIX, size);
+ if (! o6p)
+ zlog_warn ("Can't allocate memory for ospf6 prefix: size: %d", size);
+ else
+ memset (o6p, 0, size);
+
+ o6p->prefix_length = prefix.prefixlen;
+ o6p->prefix_options = options;
+ o6p->prefix_metric = htons (metric);
+ memcpy (o6p + 1, &prefix.prefix, OSPF6_PREFIX_SPACE (prefix.prefixlen));
+
+ return o6p;
+}
+
+void
+ospf6_prefix_delete (struct ospf6_prefix *p)
+{
+ XFREE (MTYPE_OSPF6_PREFIX, p);
+}
+
+int
+ospf6_prefix_issame (struct ospf6_prefix *p1, struct ospf6_prefix *p2)
+{
+ if (p1->prefix_length != p2->prefix_length)
+ return 0;
+ if (memcmp (&p1->u, &p2->u, sizeof (p1->u)))
+ return 0;
+ if (memcmp (p1 + 1, p2 + 1, OSPF6_PREFIX_SPACE (p1->prefix_length)))
+ return 0;
+ return 1;
+}
+
+struct ospf6_prefix *
+ospf6_prefix_lookup (list l, struct ospf6_prefix *p1)
+{
+ listnode node;
+ struct ospf6_prefix *p2;
+ for (node = listhead (l); node; nextnode (node))
+ {
+ p2 = (struct ospf6_prefix *) getdata (node);
+ if (ospf6_prefix_issame (p1, p2))
+ return p2;
+ }
+ return NULL;
+}
+
+/* add a copy of given prefix to the list */
+void
+ospf6_prefix_add (list l, struct ospf6_prefix *p)
+{
+ struct ospf6_prefix *add;
+ add = (struct ospf6_prefix *) XMALLOC (MTYPE_OSPF6_PREFIX,
+ OSPF6_PREFIX_SIZE (p));
+ if (add == NULL)
+ {
+ zlog_warn ("Can't allocate memory for ospf6 prefix");
+ return;
+ }
+ else
+ memcpy (add, p, OSPF6_PREFIX_SIZE (p));
+
+ if (ospf6_prefix_lookup (l, add))
+ {
+ ospf6_prefix_delete (add);
+ return;
+ }
+ listnode_add (l, add);
+}
+
+void
+ospf6_prefix_remove (list l, struct ospf6_prefix *p)
+{
+ struct ospf6_prefix *rem;
+ rem = ospf6_prefix_lookup (l, p);
+ if (rem)
+ {
+ listnode_delete (l, rem);
+ ospf6_prefix_delete (rem);
+ }
+}
+
+void
+ospf6_prefix_in6_addr (struct ospf6_prefix *o6p, struct in6_addr *in6)
+{
+ memset (in6, 0, sizeof (struct in6_addr));
+ memcpy (in6, o6p + 1, OSPF6_PREFIX_SPACE (o6p->prefix_length));
+ return;
+}
+
+char *
+ospf6_prefix_options_str (u_int8_t opt, char *buf, size_t bufsize)
+{
+ char *p, *mc, *la, *nu;
+
+ p = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_P) ? "P" : "-");
+ mc = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_MC) ? "MC" : "--");
+ la = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_LA) ? "LA" : "--");
+ nu = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_NU) ? "NU" : "--");
+
+ snprintf (buf, bufsize, "%s|%s|%s|%s", p, mc, la, nu);
+ return buf;
+}
+
+char *
+ospf6_prefix_string (struct ospf6_prefix *prefix, char *buf, size_t size)
+{
+ struct in6_addr in6;
+ char s[64];
+
+ memset (&in6, 0, sizeof (in6));
+ memcpy (&in6, prefix + 1, OSPF6_PREFIX_SPACE (prefix->prefix_length));
+ inet_ntop (AF_INET6, &in6, s, sizeof (s));
+
+ snprintf (buf, size, "%s/%d", s, prefix->prefix_length);
+ return buf;
+}
+
+void
+ospf6_prefix_copy (struct ospf6_prefix *dst, struct ospf6_prefix *src,
+ size_t dstsize)
+{
+ size_t srcsize;
+
+ memset (dst, 0, dstsize);
+
+ srcsize = OSPF6_PREFIX_SIZE (src);
+ if (dstsize < srcsize)
+ memcpy (dst, src, dstsize);
+ else
+ memcpy (dst, src, srcsize);
+
+ return;
+}
+
+void
+ospf6_prefix_apply_mask (struct ospf6_prefix *o6p)
+{
+ u_char *pnt, mask;
+ int index, offset;
+
+ char buf[128];
+ struct in6_addr in6;
+ ospf6_prefix_in6_addr (o6p, &in6);
+ inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
+
+ pnt = (u_char *)(o6p + 1);
+ index = o6p->prefix_length / 8;
+ offset = o6p->prefix_length % 8;
+ mask = 0xff << (8 - offset);
+
+ if (index >= 16)
+ return;
+
+ pnt[index] &= mask;
+ index ++;
+
+ while (index < OSPF6_PREFIX_SPACE (o6p->prefix_length))
+ pnt[index++] = 0;
+
+ ospf6_prefix_in6_addr (o6p, &in6);
+ inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
+}
+
diff --git a/ospf6d/ospf6_prefix.h b/ospf6d/ospf6_prefix.h
new file mode 100644
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 <zebra.h>
+
+#include "ospf6_proto.h"
+
+char *
+ospf6_options_string (u_char opt_capability[3], char *buffer, int size)
+{
+ char *dc, *r, *n, *mc, *e, *v6;
+
+ dc = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_DC) ? "DC" : "--");
+ r = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_R) ? "R" : "-");
+ n = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_N) ? "N" : "-");
+ mc = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_MC) ? "MC" : "--");
+ e = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_E) ? "E" : "-");
+ v6 = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_V6) ? "V6" : "--");
+ snprintf (buffer, size, "%s|%s|%s|%s|%s|%s", dc, r, n, mc, e, v6);
+ return buffer;
+}
+
diff --git a/ospf6d/ospf6_proto.h b/ospf6d/ospf6_proto.h
new file mode 100644
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 <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "command.h"
+#include "vty.h"
+#include "routemap.h"
+#include "table.h"
+#include "plist.h"
+
+#include "ospf6_route.h"
+#include "ospf6_prefix.h"
+#include "ospf6_lsa.h"
+#include "ospf6_asbr.h"
+
+route_map_result_t
+ospf6_routemap_rule_match_address_prefixlist (void *rule,
+ struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
+{
+ struct prefix_list *plist;
+
+ if (type != RMAP_OSPF6)
+ return RMAP_NOMATCH;
+
+ plist = prefix_list_lookup (AFI_IP6, (char *) rule);
+
+ if (plist == NULL)
+ return RMAP_NOMATCH;
+
+ return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
+ RMAP_NOMATCH : RMAP_MATCH);
+}
+
+void *
+ospf6_routemap_rule_match_address_prefixlist_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+ospf6_routemap_rule_match_address_prefixlist_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd
+ospf6_routemap_rule_match_address_prefixlist_cmd =
+{
+ "ipv6 address prefix-list",
+ ospf6_routemap_rule_match_address_prefixlist,
+ ospf6_routemap_rule_match_address_prefixlist_compile,
+ ospf6_routemap_rule_match_address_prefixlist_free,
+};
+
+route_map_result_t
+ospf6_routemap_rule_set_metric_type (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ char *metric_type = rule;
+ struct ospf6_external_info *info = object;
+
+ if (type != RMAP_OSPF6)
+ return RMAP_OKAY;
+
+ if (strcmp (metric_type, "type-2") == 0)
+ info->metric_type = 2;
+ else
+ info->metric_type = 1;
+
+ return RMAP_OKAY;
+}
+
+void *
+ospf6_routemap_rule_set_metric_type_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+ospf6_routemap_rule_set_metric_type_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd
+ospf6_routemap_rule_set_metric_type_cmd =
+{
+ "metric-type",
+ ospf6_routemap_rule_set_metric_type,
+ ospf6_routemap_rule_set_metric_type_compile,
+ ospf6_routemap_rule_set_metric_type_free,
+};
+
+route_map_result_t
+ospf6_routemap_rule_set_metric (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ char *metric = rule;
+ struct ospf6_external_info *info = object;
+
+ if (type != RMAP_OSPF6)
+ return RMAP_OKAY;
+
+ info->metric = atoi (metric);
+ return RMAP_OKAY;
+}
+
+void *
+ospf6_routemap_rule_set_metric_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+ospf6_routemap_rule_set_metric_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd
+ospf6_routemap_rule_set_metric_cmd =
+{
+ "metric",
+ ospf6_routemap_rule_set_metric,
+ ospf6_routemap_rule_set_metric_compile,
+ ospf6_routemap_rule_set_metric_free,
+};
+
+route_map_result_t
+ospf6_routemap_rule_set_forwarding (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ char *forwarding = rule;
+ struct ospf6_external_info *info = object;
+
+ if (type != RMAP_OSPF6)
+ return RMAP_OKAY;
+
+ if (inet_pton (AF_INET6, forwarding, &info->forwarding) != 1)
+ {
+ memset (&info->forwarding, 0, sizeof (struct in6_addr));
+ return RMAP_ERROR;
+ }
+
+ return RMAP_OKAY;
+}
+
+void *
+ospf6_routemap_rule_set_forwarding_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+ospf6_routemap_rule_set_forwarding_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd
+ospf6_routemap_rule_set_forwarding_cmd =
+{
+ "forwarding-address",
+ ospf6_routemap_rule_set_forwarding,
+ ospf6_routemap_rule_set_forwarding_compile,
+ ospf6_routemap_rule_set_forwarding_free,
+};
+
+int
+route_map_command_status (struct vty *vty, int ret)
+{
+ if (! ret)
+ return CMD_SUCCESS;
+
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+ break;
+ default:
+ vty_out (vty, "route-map add set failed.%s", VTY_NEWLINE);
+ break;
+ }
+ return CMD_WARNING;
+}
+
+/* add "match address" */
+DEFUN (ospf6_routemap_match_address_prefixlist,
+ ospf6_routemap_match_address_prefixlist_cmd,
+ "match ipv6 address prefix-list WORD",
+ "Match values\n"
+ IPV6_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IPv6 prefix-list name\n")
+{
+ int ret = route_map_add_match ((struct route_map_index *) vty->index,
+ "ipv6 address prefix-list", argv[0]);
+ return route_map_command_status (vty, ret);
+}
+
+/* delete "match address" */
+DEFUN (ospf6_routemap_no_match_address_prefixlist,
+ ospf6_routemap_no_match_address_prefixlist_cmd,
+ "no match ipv6 address prefix-list WORD",
+ NO_STR
+ "Match values\n"
+ IPV6_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IPv6 prefix-list name\n")
+{
+ int ret = route_map_delete_match ((struct route_map_index *) vty->index,
+ "ipv6 address prefix-list", argv[0]);
+ return route_map_command_status (vty, ret);
+}
+
+/* add "set metric-type" */
+DEFUN (ospf6_routemap_set_metric_type,
+ ospf6_routemap_set_metric_type_cmd,
+ "set metric-type (type-1|type-2)",
+ "Set value\n"
+ "Type of metric\n"
+ "OSPF6 external type 1 metric\n"
+ "OSPF6 external type 2 metric\n")
+{
+ int ret = route_map_add_set ((struct route_map_index *) vty->index,
+ "metric-type", argv[0]);
+ return route_map_command_status (vty, ret);
+}
+
+/* delete "set metric-type" */
+DEFUN (ospf6_routemap_no_set_metric_type,
+ ospf6_routemap_no_set_metric_type_cmd,
+ "no set metric-type (type-1|type-2)",
+ NO_STR
+ "Set value\n"
+ "Type of metric\n"
+ "OSPF6 external type 1 metric\n"
+ "OSPF6 external type 2 metric\n")
+{
+ int ret = route_map_delete_set ((struct route_map_index *) vty->index,
+ "metric-type", argv[0]);
+ return route_map_command_status (vty, ret);
+}
+
+/* add "set metric" */
+DEFUN (set_metric,
+ set_metric_cmd,
+ "set metric <0-4294967295>",
+ "Set value\n"
+ "Metric value\n"
+ "Metric value\n")
+{
+ int ret = route_map_add_set ((struct route_map_index *) vty->index,
+ "metric", argv[0]);
+ return route_map_command_status (vty, ret);
+}
+
+/* delete "set metric" */
+DEFUN (no_set_metric,
+ no_set_metric_cmd,
+ "no set metric <0-4294967295>",
+ NO_STR
+ "Set value\n"
+ "Metric\n"
+ "METRIC value\n")
+{
+ int ret = route_map_delete_set ((struct route_map_index *) vty->index,
+ "metric", argv[0]);
+ return route_map_command_status (vty, ret);
+}
+
+/* add "set forwarding-address" */
+DEFUN (ospf6_routemap_set_forwarding,
+ ospf6_routemap_set_forwarding_cmd,
+ "set forwarding-address X:X::X:X",
+ "Set value\n"
+ "Forwarding Address\n"
+ "IPv6 Address\n")
+{
+ int ret = route_map_add_set ((struct route_map_index *) vty->index,
+ "forwarding-address", argv[0]);
+ return route_map_command_status (vty, ret);
+}
+
+/* delete "set forwarding-address" */
+DEFUN (ospf6_routemap_no_set_forwarding,
+ ospf6_routemap_no_set_forwarding_cmd,
+ "no set forwarding-address X:X::X:X",
+ NO_STR
+ "Set value\n"
+ "Forwarding Address\n"
+ "IPv6 Address\n")
+{
+ int ret = route_map_delete_set ((struct route_map_index *) vty->index,
+ "forwarding-address", argv[0]);
+ return route_map_command_status (vty, ret);
+}
+
+void
+ospf6_routemap_init ()
+{
+ route_map_init ();
+ route_map_init_vty ();
+ route_map_add_hook (ospf6_asbr_routemap_update);
+ route_map_delete_hook (ospf6_asbr_routemap_update);
+
+ route_map_install_match (&ospf6_routemap_rule_match_address_prefixlist_cmd);
+ route_map_install_set (&ospf6_routemap_rule_set_metric_type_cmd);
+ route_map_install_set (&ospf6_routemap_rule_set_metric_cmd);
+ route_map_install_set (&ospf6_routemap_rule_set_forwarding_cmd);
+
+ /* Match address prefix-list */
+ install_element (RMAP_NODE, &ospf6_routemap_match_address_prefixlist_cmd);
+ install_element (RMAP_NODE, &ospf6_routemap_no_match_address_prefixlist_cmd);
+
+ /* ASE Metric Type (e.g. Type-1/Type-2) */
+ install_element (RMAP_NODE, &ospf6_routemap_set_metric_type_cmd);
+ install_element (RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd);
+
+ /* ASE Metric */
+ install_element (RMAP_NODE, &set_metric_cmd);
+ install_element (RMAP_NODE, &no_set_metric_cmd);
+
+ /* ASE Metric */
+ install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd);
+ install_element (RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd);
+}
+
diff --git a/ospf6d/ospf6_routemap.h b/ospf6d/ospf6_routemap.h
new file mode 100644
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 <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "vty.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "table.h"
+#include "thread.h"
+#include "command.h"
+
+#include "ospf6_hook.h"
+#include "ospf6_proto.h"
+#include "ospf6_prefix.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+
+#include "ospf6_message.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_interface.h"
+#include "ospf6_area.h"
+#include "ospf6_top.h"
+
+#include "ospf6_route.h"
+#include "ospf6_zebra.h"
+
+#include "ospf6_nsm.h"
+#include "ospf6_asbr.h"
+#include "ospf6_abr.h"
+
+#define HEADER_DEPENDENCY
+#include "ospf6d.h"
+#undef HEADER_DEPENDENCY
+
+/* global ospf6d variable */
+struct ospf6 *ospf6;
+
+static void
+ospf6_top_foreach_area (struct ospf6 *o6, void *arg, int val,
+ void (*func) (void *, int, void *))
+{
+ listnode node;
+ struct ospf6_area *o6a;
+
+ for (node = listhead (o6->area_list); node; nextnode (node))
+ {
+ o6a = (struct ospf6_area *) getdata (node);
+ (*func) (arg, val, o6a);
+ }
+}
+
+static void
+ospf6_top_foreach_interface (struct ospf6 *o6, void *arg, int val,
+ void (*func) (void *, int, void *))
+{
+ listnode node;
+ struct ospf6_area *o6a;
+
+ for (node = listhead (o6->area_list); node; nextnode (node))
+ {
+ o6a = (struct ospf6_area *) getdata (node);
+ (*o6a->foreach_if) (o6a, arg, val, func);
+ }
+}
+
+static void
+ospf6_top_foreach_neighbor (struct ospf6 *o6, void *arg, int val,
+ void (*func) (void *, int, void *))
+{
+ listnode node;
+ struct ospf6_area *o6a;
+
+ for (node = listhead (o6->area_list); node; nextnode (node))
+ {
+ o6a = (struct ospf6_area *) getdata (node);
+ (*o6a->foreach_nei) (o6a, arg, val, func);
+ }
+}
+
+static int
+ospf6_top_maxage_remover (struct thread *t)
+{
+ int count;
+ struct ospf6 *o6 = (struct ospf6 *) THREAD_ARG (t);
+
+ o6->maxage_remover = (struct thread *) NULL;
+
+ count = 0;
+ o6->foreach_nei (o6, &count, NBS_EXCHANGE, ospf6_count_state);
+ o6->foreach_nei (o6, &count, NBS_LOADING, ospf6_count_state);
+ if (count != 0)
+ return 0;
+
+ ospf6_lsdb_remove_maxage (o6->lsdb);
+ return 0;
+}
+
+void
+ospf6_top_schedule_maxage_remover (void *arg, int val, struct ospf6 *o6)
+{
+ if (o6->maxage_remover != NULL)
+ return;
+
+ o6->maxage_remover =
+ thread_add_event (master, ospf6_top_maxage_remover, o6, 0);
+}
+
+void
+ospf6_show (struct vty *vty)
+{
+ listnode n;
+ struct ospf6_area *area;
+ char id_string[32];
+ unsigned long day, hour, min, sec;
+ struct timeval now, running;
+
+ /* process id, router id */
+ inet_ntop (AF_INET, &ospf6->router_id, id_string, sizeof (id_string));
+ vty_out (vty, " Routing Process (%lu) with ID %s%s",
+ ospf6->process_id, id_string, VTY_NEWLINE);
+
+ /* running time */
+ gettimeofday (&now, (struct timezone *)NULL);
+ ospf6_timeval_sub (&now, &ospf6->starttime, &running);
+ ospf6_timeval_decode (&running, &day, &hour, &min, &sec, NULL, NULL);
+ vty_out (vty, " Running %ld days %ld hours %ld minutes %ld seconds%s",
+ day, hour, min, sec, VTY_NEWLINE);
+
+ vty_out (vty, " Supports only single TOS(TOS0) routes%s", VTY_NEWLINE);
+
+ /* Redistribute config */
+ ospf6_redistribute_show_config (vty);
+
+ /* LSAs */
+ vty_out (vty, " Number of AS scoped LSAs is %u%s",
+ ospf6->lsdb->count, VTY_NEWLINE);
+ vty_out (vty, " Route calculation executed %d times%s",
+ ospf6->stat_route_calculation_execed, VTY_NEWLINE);
+
+ /* Route Statistics */
+#if 0
+ ospf6_route_statistics_show (vty, ospf6->route_table);
+#endif
+
+ /* Areas */
+ vty_out (vty, " Number of areas in this router is %u%s",
+ listcount (ospf6->area_list), VTY_NEWLINE);
+ for (n = listhead (ospf6->area_list); n; nextnode (n))
+ {
+ area = (struct ospf6_area *) getdata (n);
+ ospf6_area_show (vty, area);
+ }
+}
+
+void
+ospf6_statistics_show (struct vty *vty, struct ospf6 *o6)
+{
+ listnode node;
+ struct ospf6_area *o6a;
+ char running_time[128];
+ struct timeval now, running;
+
+ gettimeofday (&now, (struct timezone *) NULL);
+ ospf6_timeval_sub (&now, &o6->starttime, &running);
+ ospf6_timeval_string (&running, running_time, sizeof (running_time));
+
+ vty_out (vty, "Statistics of OSPF process %ld%s",
+ o6->process_id, VTY_NEWLINE);
+ vty_out (vty, " Running: %s%s", running_time, VTY_NEWLINE);
+
+#if 0
+ ospf6_route_statistics_show (vty, o6->route_table);
+#endif
+
+ for (node = listhead (o6->area_list); node; nextnode (node))
+ {
+ o6a = (struct ospf6_area *) getdata (node);
+ ospf6_area_statistics_show (vty, o6a);
+ }
+}
+
+static struct ospf6 *
+ospf6_new ()
+{
+ struct ospf6 *new;
+ new = XMALLOC (MTYPE_OSPF6_TOP, sizeof (struct ospf6));
+ if (new)
+ memset (new, 0, sizeof (struct ospf6));
+ return new;
+}
+
+void
+ospf6_free (struct ospf6 *ospf6)
+{
+ XFREE (MTYPE_OSPF6_TOP, ospf6);
+}
+
+void
+ospf6_top_topology_add (struct ospf6_route_req *request)
+{
+ assert (request->route.type == OSPF6_DEST_TYPE_ROUTER);
+ if (CHECK_FLAG (request->path.router_bits, OSPF6_ROUTER_LSA_BIT_E))
+ ospf6_asbr_asbr_entry_add (request);
+}
+
+void
+ospf6_top_topology_remove (struct ospf6_route_req *request)
+{
+ assert (request->route.type == OSPF6_DEST_TYPE_ROUTER);
+ if (CHECK_FLAG (request->path.router_bits, OSPF6_ROUTER_LSA_BIT_E))
+ ospf6_asbr_asbr_entry_remove (request);
+}
+
+struct ospf6 *
+ospf6_create (unsigned long process_id)
+{
+ struct ospf6 *o6;
+ char namebuf[64];
+
+ o6 = ospf6_new ();
+
+ /* initialize */
+ gettimeofday (&o6->starttime, (struct timezone *)NULL);
+ o6->process_id = process_id;
+ o6->version = OSPF6_VERSION;
+ o6->area_list = list_new ();
+
+ o6->lsdb = ospf6_lsdb_create ();
+
+ o6->foreach_area = ospf6_top_foreach_area;
+ o6->foreach_if = ospf6_top_foreach_interface;
+ o6->foreach_nei = ospf6_top_foreach_neighbor;
+
+ snprintf (namebuf, sizeof (namebuf), "InterTopology table");
+ o6->topology_table = ospf6_route_table_create (namebuf);
+ ospf6_route_hook_register (ospf6_top_topology_add,
+ ospf6_top_topology_add,
+ ospf6_top_topology_remove,
+ o6->topology_table);
+
+#if 0
+ snprintf (namebuf, sizeof (namebuf), "External table");
+ o6->external_table = ospf6_route_table_create (namebuf);
+ ospf6_route_hook_register (ospf6_asbr_external_route_add,
+ ospf6_asbr_external_route_add,
+ ospf6_asbr_external_route_remove,
+ o6->external_table);
+#endif /*0*/
+
+ snprintf (namebuf, sizeof (namebuf), "Top route table");
+ o6->route_table = ospf6_route_table_create (namebuf);
+ ospf6_route_hook_register (ospf6_zebra_route_update_add,
+ ospf6_zebra_route_update_add,
+ ospf6_zebra_route_update_remove,
+ o6->route_table);
+ ospf6_route_hook_register (ospf6_abr_route_add,
+ ospf6_abr_route_add,
+ ospf6_abr_route_remove,
+ o6->route_table);
+
+ return o6;
+}
+
+void
+ospf6_delete (struct ospf6 *ospf6)
+{
+ ospf6_route_remove_all (ospf6->route_table);
+ ospf6_free (ospf6);
+}
+
+struct ospf6 *
+ospf6_start ()
+{
+ if (ospf6)
+ return ospf6;
+
+ ospf6 = ospf6_create (0);
+ return ospf6;
+}
+
+void
+ospf6_stop ()
+{
+ if (!ospf6)
+ return;
+
+ ospf6_delete (ospf6);
+ ospf6 = NULL;
+}
+
+int
+ospf6_is_asbr (struct ospf6 *o6)
+{
+ int i = 0;
+ i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_SYSTEM);
+ i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_CONNECT);
+ i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_STATIC);
+ i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_KERNEL);
+ i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_RIPNG);
+ i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_BGP);
+ return (i);
+}
+
+DEFUN (show_ipv6_ospf6_route,
+ show_ipv6_ospf6_route_cmd,
+ "show ipv6 ospf6 route",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "Routing table\n"
+ )
+{
+ OSPF6_CMD_CHECK_RUNNING ();
+ return ospf6_route_table_show (vty, argc, argv, ospf6->route_table);
+}
+
+ALIAS (show_ipv6_ospf6_route,
+ show_ipv6_ospf6_route_prefix_cmd,
+ "show ipv6 ospf6 route (X::X|detail)",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "Routing table\n"
+ "match IPv6 prefix\n"
+ )
+
+DEFUN (show_ipv6_ospf6_topology,
+ show_ipv6_ospf6_topology_cmd,
+ "show ipv6 ospf6 topology",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "Inter Area topology information\n"
+ )
+{
+ OSPF6_CMD_CHECK_RUNNING ();
+ return ospf6_route_table_show (vty, argc, argv, ospf6->topology_table);
+}
+
+ALIAS (show_ipv6_ospf6_topology,
+ show_ipv6_ospf6_topology_router_cmd,
+ "show ipv6 ospf6 topology (A.B.C.D|<0-4294967295>|detail)",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "Inter Area topology information\n"
+ OSPF6_ROUTER_ID_STR
+ OSPF6_ROUTER_ID_STR
+ "Detailed information\n"
+ )
+
+ALIAS (show_ipv6_ospf6_topology,
+ show_ipv6_ospf6_topology_router_lsid_cmd,
+ "show ipv6 ospf6 topology (A.B.C.D|<0-4294967295>) (A.B.C.D|<0-4294967295>)",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "Inter Area topology information\n"
+ OSPF6_ROUTER_ID_STR
+ OSPF6_ROUTER_ID_STR
+ OSPF6_LS_ID_STR
+ OSPF6_LS_ID_STR
+ )
+
+void
+ospf6_top_init ()
+{
+ install_element (VIEW_NODE, &show_ipv6_ospf6_route_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_route_prefix_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_topology_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_topology_router_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_topology_router_lsid_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_route_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_route_prefix_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_router_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_router_lsid_cmd);
+}
+
diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h
new file mode 100644
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 <zebra.h>
+#include "linklist.h"
+
+#ifndef HEADER_DEPENDENCY
+/* Include other stuffs */
+#include "version.h"
+#include "log.h"
+#include "getopt.h"
+#include "thread.h"
+#include "command.h"
+#include "memory.h"
+#include "sockunion.h"
+#include "if.h"
+#include "prefix.h"
+#include "stream.h"
+#include "thread.h"
+#include "filter.h"
+#include "zclient.h"
+#include "table.h"
+#include "plist.h"
+
+/* OSPF stuffs */
+#include "ospf6_hook.h"
+#include "ospf6_types.h"
+#include "ospf6_prefix.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+
+#include "ospf6_message.h"
+#include "ospf6_proto.h"
+#include "ospf6_spf.h"
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_ism.h"
+#include "ospf6_nsm.h"
+#include "ospf6_route.h"
+#include "ospf6_dbex.h"
+#include "ospf6_network.h"
+#include "ospf6_zebra.h"
+#include "ospf6_dump.h"
+#include "ospf6_routemap.h"
+#include "ospf6_asbr.h"
+#include "ospf6_abr.h"
+#include "ospf6_intra.h"
+#endif /*HEADER_DEPENDENCY*/
+
+#define HASHVAL 64
+#define MAXIOVLIST 1024
+
+#define OSPF6_DAEMON_VERSION "0.9.6o"
+
+#define AF_LINKSTATE 0xff
+
+/* global variables */
+extern char *progname;
+extern int errno;
+extern int daemon_mode;
+extern struct thread_master *master;
+extern list iflist;
+extern list nexthoplist;
+extern struct sockaddr_in6 allspfrouters6;
+extern struct sockaddr_in6 alldrouters6;
+extern int ospf6_sock;
+extern char *recent_reason;
+
+/* Default configuration file name for ospfd. */
+#define OSPF6_DEFAULT_CONFIG "ospf6d.conf"
+
+/* Default port values. */
+#define OSPF6_VTY_PORT 2606
+#define OSPF6_VTYSH_PATH "/tmp/.ospf6d"
+
+#ifdef INRIA_IPV6
+#ifndef IPV6_PKTINFO
+#define IPV6_PKTINFO IPV6_RECVPKTINFO
+#endif /* IPV6_PKTINFO */
+#endif /* INRIA_IPV6 */
+
+/* Historycal for KAME. */
+#ifndef IPV6_JOIN_GROUP
+#ifdef IPV6_ADD_MEMBERSHIP
+#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
+#endif /* IPV6_ADD_MEMBERSHIP. */
+#ifdef IPV6_JOIN_MEMBERSHIP
+#define IPV6_JOIN_GROUP IPV6_JOIN_MEMBERSHIP
+#endif /* IPV6_JOIN_MEMBERSHIP. */
+#endif /* ! IPV6_JOIN_GROUP*/
+
+#ifndef IPV6_LEAVE_GROUP
+#ifdef IPV6_DROP_MEMBERSHIP
+#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
+#endif /* IPV6_DROP_MEMBERSHIP */
+#endif /* ! IPV6_LEAVE_GROUP */
+
+#define OSPF6_CMD_CHECK_RUNNING() \
+ if (ospf6 == NULL) \
+ { \
+ vty_out (vty, "OSPFv3 is not running%s", VTY_NEWLINE); \
+ return CMD_SUCCESS; \
+ }
+
+#define OSPF6_LEVEL_NONE 0
+#define OSPF6_LEVEL_NEIGHBOR 1
+#define OSPF6_LEVEL_INTERFACE 2
+#define OSPF6_LEVEL_AREA 3
+#define OSPF6_LEVEL_TOP 4
+#define OSPF6_LEVEL_MAX 5
+
+#define OSPF6_PASSIVE_STR \
+ "Suppress routing updates on an interface\n"
+#define OSPF6_PREFIX_LIST_STR \
+ "Advertise I/F Address only match entries of prefix-list\n"
+
+#define OSPF6_AREA_STR "Area information\n"
+#define OSPF6_AREA_ID_STR "Area ID (as an IPv4 notation)\n"
+#define OSPF6_SPF_STR "Shortest Path First tree information\n"
+#define OSPF6_ROUTER_ID_STR "Specify Router-ID\n"
+#define OSPF6_LS_ID_STR "Specify Link State ID\n"
+
+
+/* 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 <keller@tik.ee.ethz.ch>
+
+ * ospf_vty.c (show_ip_ospf_database): Fix CLI parse.
+
+2002-10-23 Juris Kalnins <juris@mt.lv>
+
+ * ospf_interface.c (ospf_if_stream_unset): When write queue
+ becomes empty stop write timer.
+
+2002-10-10 Greg Troxel <gdt@ir.bbn.com>
+
+ * ospf_packet.c (ospf_check_md5_digest): Change >= to > to make it
+ conform to RFC.
+
+2002-07-07 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.93 released.
+
+2002-06-19 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * ospf_spf.c (ospf_nexthop_calculation): Add NULL set to oi and
+ check of l2. Reported by: Daniel Drown <dan-zebra@drown.org>
+ (ospf_lsa_has_link): LSA Length calculation fix. Reported by:
+ Paul Jakma <paulj@alphyra.ie>.
+
+ * ospfd.c (ospf_if_update): Fix nextnode reference bug. Reported
+ by: juris@mt.lv.
+
+2002-01-21 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * ospfd.c: Merge [zebra 11445] Masahiko ENDO's Opaque-LSA support.
+
+2001-08-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_interface.c (ospf_add_to_if): Use /32 address to register
+ OSPF interface information.
+ (ospf_delete_from_if): Likewise.
+
+ * ospf_zebra.c (ospf_interface_address_delete): Likewise.
+
+2001-08-23 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * ospf_zebra.c (ospf_redistribute_unset): When redistribute type
+ is OSPF, do not unset redistribute flag.
+
+2001-08-19 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92a released.
+
+2001-08-15 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92 released.
+
+2001-08-12 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * ospfd.c (ospf_config_write): auto-cost reference-bandwidth
+ configuration display.
+
+2001-07-24 David Watson <dwatson@eecs.umich.edu>
+
+ * ospf_spf.c (ospf_spf_next): Modify ospf_vertex_add_parent to
+ check for an existing link before connecting the parent and child.
+ ospf_nexthop_calculation is also modified to check for duplicate
+ entries when copying from the parent. Finally, ospf_spf_next
+ removes duplicates when it merges two equal cost candidates.
+
+2001-07-23 itojun@iijlab.net
+
+ * ospfd.c (show_ip_ospf_neighbor): Check ospf_top before use it
+ [zebra 8549].
+
+2001-07-23 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * ospf_packet.c (ospf_write): Remove defined(__OpenBSD__) to make
+ it work on OpenBSD.
+
+2001-06-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_zebra.c (config_write_ospf_default_metric): Display
+ default-metric configuration.
+
+2001-06-18 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * ospf_ia.h (OSPF_EXAMINE_SUMMARIES_ALL): Remove old macros.
+
+2001-05-28 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * ospf_snmp.c (ospfIfEntry): Fix interface lookup bug to avoid
+ crush.
+ (ospfIfMetricEntry): Likewise.
+
+2001-03-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_packet.c (ospf_read): Fix typo. Reported by: "Jen B
+ Lin'Kova" <jen@stack.net>.
+
+2001-03-15 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_interface.c (ip_ospf_network): Set interface parameter.
+ (interface_config_write): Add check for OSPF_IFTYPE_LOOPBACK.
+
+ * ospf_zebra.c (ospf_interface_add): Set interface parameter.
+
+2001-02-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_packet.c (ospf_recv_packet): Solaris also need to add
+ (iph.ip_hl << 2) to iph.ip_len.
+
+2001-02-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospfd.h (OSPF_LS_REFRESH_TIME): Fix OSPF_LS_REFRESH_TIME value.
+ Suggested by: David Watson <dwatson@eecs.umich.edu>.
+
+ * ospf_zebra.c (zebra_init): Remove zebra node.
+
+ * ospfd.c (ospf_area_range_set): Function name is changed from
+ ospf_ara_range_cmd.
+ (ospf_area_range_unset): New function which separated from DEFUN.
+ New commands are added:
+ "no area A.B.C.D range A.B.C.D/M advertise"
+ "no area <0-4294967295> range A.B.C.D/M advertise"
+ "no area A.B.C.D range A.B.C.D/M not-advertise"
+ "no area <0-4294967295> range A.B.C.D/M not-advertise"
+
+ * ospf_lsa.c (ospf_lsa_more_recent): Fix previous change.
+
+2001-02-08 Matthew Grant <grantma@anathoth.gen.nz>
+
+ * ospf_network.c (ospf_if_add_allspfrouters): Use
+ setsockopt_multicast_ipv4.
+ (ospf_if_drop_allspfrouters): Likewise.
+
+ * ospf_lsa.c (ospf_router_lsa_install): Add rt_recalc flag.
+ (ospf_network_lsa_install): Likewise.
+ (ospf_summary_lsa_install): Likewise.
+ (ospf_summary_asbr_lsa_install): Likewise.
+ (ospf_external_lsa_install): Likewise.
+ (ospf_lsa_install): Call ospf_lsa_different to check this LSA is
+ new one or not.
+
+2001-02-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_zebra.c (ospf_interface_delete): Do not free interface
+ structure when ospfd receive interface delete message to support
+ pseudo interface.
+
+2001-02-01 Dick Glasspool <dick@ipinfusion.com>
+
+ * ospfd.c (area_range_notadvertise): Change area range "suppress"
+ command to "not-advertise".
+
+ * ospfd.h (OSPF_LS_REFRESH_TIME): Change OSPF_LS_REFRESH_TIME from
+ 1800 to 60.
+
+ * ospf_abr.c (ospf_abr_update_aggregate): When update_aggregate is
+ updating the area-range, the lowest cost is now saved.
+
+ * ospf_lsa.c (ospf_lsa_more_recent): Routing to compare sequence
+ numbers rather than creating overflow during calculation.
+
+2001-02-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.91 is released.
+
+2001-01-31 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_packet.c (ospf_db_desc_proc): Do not continue process when
+ NSM_SeqNumberMismatch is scheduled.
+ (ospf_ls_req): Free ls_upd when return from this function.
+ (ospf_ls_upd_timer): When update list is empty do not call
+ ospf_ls_upd_send(). Suggested by: endo@suri.co.jp (Masahiko
+ Endo).
+
+2001-01-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_lsa.c (ospf_maxage_flood): Flood LSA when it reaches
+ MaxAge. RFC2328 Section 14.
+ (ospf_maxage_lsa_remover): Call above function during removing
+ MaxAge LSA.
+
+2001-01-26 Dick Glasspool <dick@ipinfusion.com>
+
+ * ospf_flood.c (ospf_flood_through_as): Function is updated for
+ NSSA Translations now done at ospf_abr.c with no change in P-bit.
+
+ * ospf_lsa.c (ospf_get_nssa_ip): Get 1st IP connection for Forward
+ Addr.
+ (ospf_install_flood_nssa): Leave Type-7 LSA at Lock Count = 2.
+
+ * ospf_ase.c (ospf_ase_calculate_route): Add debug codes.
+
+ * ospf_abr.c (ospf_abr_translate_nssa): Recalculate LSA checksum.
+
+ * ospf_packet.h (OSPF_SEND_PACKET_LOOP): Added for test packet.
+
+ * ospf_dump.c (ospf_lsa_type_msg): Add OSPF_GROUP_MEMBER_LSA and
+ OSPF_AS_NSSA_LSA.
+
+ * ospfd.c (data_injection): Function to inject LSA. This is
+ debugging command.
+
+2001-01-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_route.c (ospf_route_match_same): Remove function.
+ (ospf_route_match_same_new): Renamed to ospf_route_match_same.
+
+ * ospf_zebra.c (ospf_interface_address_delete): Add check for
+ oi->address. Suggested by Matthew Grant
+ <grantma@anathoth.gen.nz>.
+ (ospf_zebra_add): Remove function.
+ (ospf_zebra_add_multipath): Rename to ospf_zebra_add.
+
+ * ospf_interface.c: Remove HAVE_IF_PSEUDO part.
+
+ * ospf_zebra.c: Likewise.
+
+2001-01-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_ase.c: Remove OLD_RIB part.
+
+ * ospf_route.c: Likewise.
+
+ * zebra-0.90 is released.
+
+ * ospf_packet.c (ospf_recv_packet): Use ip_len adjestment code to
+ NetBSD.
+
+2001-01-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_route.c (ospf_route_delete): Use
+ ospf_zebra_delete_multipath.
+
+2001-01-09 Matthew Grant <grantma@anathoth.gen.nz>
+
+ * ospf_interface.c (ospf_if_cleanup): Function name is renamed
+ from ospf_if_free(). Rewrite whole procudure to support primary
+ address deletion.
+
+ * ospf_zebra.c (ospf_interface_address_delete): Add primary
+ address deletion process.
+
+2001-01-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_packet.c (ospf_recv_packet): OpenBSD has same ip_len
+ treatment like FreeBSD.
+
+2001-01-09 endo@suri.co.jp (Masahiko Endo)
+
+ * ospf_packet.c (ospf_recv_packet): FreeBSD kernel network code
+ strips IP header size from receiving IP Packet. So we adjust
+ ip_len to whole IP packet size by adding IP header size.
+
+2001-01-08 endo@suri.co.jp (Masahiko Endo)
+
+ * ospf_network.c (ospf_serv_sock): When socket() is failed return
+ immediately.
+ (ospf_serv_sock): Close socket when it is not used.
+
+ * ospf_packet.c (ospf_write): Set sin_len when HAVE_SIN_LEN is
+ defined.
+ (ospf_write): When bind is fined, close sock.
+
+2001-01-07 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_zebra.c (ospf_interface_state_up): Fixes coredump that
+ appears when you try to configure bandwidth on the ppp interface
+ that is not yet configured in ospfd.
+
+2001-01-07 Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+ * ospf_route.c (show_ip_ospf_route_external): "show ip ospf route"
+ will print nexthops for AS-external routes.
+
+ * ospf_ase.c (ospf_ase_route_match_same): New function to compare
+ ASE route under multipath environment.
+ (ospf_ase_compare_tables): Likewise.
+
+2001-01-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospfd.h (OSPF_VTYSH_PATH): Change "/tmp/ospfd" to "/tmp/.ospfd".
+
+2000-12-28 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_route.c (ospf_route_install): Install multipath information
+ to zebra daemon.
+
+ * ospf_zebra.c (ospf_zebra_add_multipath): Function for passing
+ multipath information to zebra daemon.
+
+2000-12-25 Dick Glasspool <dick@ipinfusion.com>
+
+ * ospf_packet.c (ospf_write): Call ospf_packet_delete when sendto
+ fail.
+ (DISCARD_LSA): Add argument N for logging point of DISCARD_LSA is
+ called.
+
+ * ospf_lsa.c (ospf_external_lsa_refresh): NSSA install_flood will
+ leave Type-7 LSA at Lock Count = 2.
+
+ * ospf_flood.c (ospf_flood_through): Flood_though_as updated for
+ NSSA no P-bit off during Area flooding, but P-bit is turned off
+ for mulitple NSSA AS flooding.
+
+ * ospf_ase.c (ospf_ase_calculate_timer): Added calculations for
+ Type-7 LSDB.
+
+ * ospf_abr.c (ospf_abr_translate_nssa): Removed one unlock call.
+ (ospf_abr_announce_nssa_defaults): Corrected Debug from EVENT to
+ NSSA.
+
+2000-12-25 Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+ * ospf_zebra.c (ospf_zebra_read_ipv4): Checking the age of the
+ found LSA and if the LSA is MAXAGE we should call refresh instead
+ of originate.
+
+2000-12-18 Dick Glasspool <dick@ipinfusion.com>
+
+ * ospf_abr.c: Removed redundant "...flood" in
+ announce_network_to_area(). Repaired nssa Unlock by using
+ discard.
+
+ * ospf_packet.c: Removed old NSSA translate during mk_ls_update.
+
+ * ospfd.c: Free up all data bases including NSSA.
+
+ * ospf_lsa.c: Now allow removal of XLATE LSA's Check in
+ discard_callback. Added routine to get ip addr from within the
+ ifp.
+
+ * ospf_flood.c: Now set Forward Address for outgoing Type-7.
+
+ * ospf_lsa.h: Added prototype for the below. struct in_addr
+ ospf_get_ip_from_ifp (struct interface *ifp).
+
+2000-12-14 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_packet.c (ospf_recv_packet): New OSPF pakcet read method.
+ Now maximum packet length may be 65535 bytes (maximum IP packet
+ length).
+
+ * ospf_interface.c (ospf_if_stream_set): Don't make input buffer.
+
+ * ospfd.c (config_write_network_area): Remove unnecessary area
+ lookup code.
+
+2000-12-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_packet.c (ospf_read): Accept packet bigger than MTU value.
+
+2000-12-13 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospfd.c (config_write_network_area): Fix bug in
+ config_write_network_area function.
+
+2000-12-12 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_abr.c (ospf_abr_announce_network_to_area): Make Summary
+ LSA's origination and refreshment as same as other type of LSA.
+
+ * ospf_lsa.c (ospf_summary_lsa_refresh): Return struct ospf_lsa *.
+
+ * ospf_lsa.c (ospf_summary_asbr_lsa_refresh): Likewise.
+
+2000-12-08 Dick Glasspool <dick@ipinfusion.com>
+
+ The bulk of NSSA changes are contained herein; This version will
+ require manual setting of "always" for NSSA Translator, and will
+ not perform aggregation yet.
+
+ * ospf_dump.c: "debug ospf nssa" is added.
+
+ * ospf_dump.h: Likewise.
+
+ * ospf_packet.c (ospf_hello): Display router ID on Bad NSSA Hello.
+
+ * ospfd.c: Discard_LSA to stay away from LOCAL_XLT Process NSSA
+ 'never, candidate, always'. Change "suppress" to "not-advertise".
+
+ * ospfd.h: Add TranslatorRole to struct ospf_area. Add anyNSSA to
+ struct ospf.
+
+ * ospf_ase.c (ospf_ase_calculate_route): External to stay away
+ from LOCAL_XLT
+
+ * ospf_nsm.c (ospf_db_summary_add): External to stay away from
+ LOCAL_XLT
+
+ * ospf_abr.c: Major logic added for abr_nssa_task(). If ABR, and
+ NSSA translator, then do it. Approve the global list, and flush
+ any unapproved.
+
+ * ospf_lsa.h: New LSA flag OSPF_LSA_LOCAL_XLT to indicate that the
+ Type-5 resulted from a Local Type-7 translation; not used for
+ flooding, but used for flushing.
+
+ * ospf_flood.c: New NSSA flooding.
+
+2000-12-08 Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+ * ospfd.c (ospf_find_vl_data): New function for looking up virtual
+ link data.
+ (ospf_vl_set_security): Virtual link configuration with
+ authentication.
+ (ospf_vl_set_timers): Set timers for virtual link.
+
+ * New commands are added.
+ "area A.B.C.D virtual-link A.B.C.D"
+ "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535>"
+ "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535> authentication-key AUTH_KEY"
+ "area A.B.C.D virtual-link A.B.C.D authentication-key AUTH_KEY"
+ "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535> message-digest-key <1-255> md5 KEY"
+ "area A.B.C.D virtual-link A.B.C.D message-digest-key <1-255> md5 KEY"
+
+ * ospf_packet.c (ospf_check_md5_digest): Add neighbor's
+ cryptographic sequence number treatment.
+ (ospf_check_auth): OSPF input buffer is added to argument.
+ (ospf_read): Save neighbor's cryptographic sequence number.
+
+ * ospf_nsm.c (nsm_change_status): Clear cryptographic sequence
+ number when neighbor status is changed to NSM down.
+
+ * ospf_neighbor.c (ospf_nbr_new): Set zero to crypt_seqnum.
+
+ * ospf_neighbor.h (struct ospf_neighbor): Add cryptographic
+ sequence number to neighbor structure.
+
+2000-11-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_snmp.c (ospfIfLookup): OSPF MIB updates.
+ (ospfExtLsdbEntry): Add OspfExtLsdbTable treatment.
+
+2000-11-28 Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+ * ospfd.c (ospf_interface_down): Clear a ls_upd_queue queue of the
+ interface.
+ (ospf_ls_upd_queue_empty): New function to empty ls update queue
+ of the OSPF interface.
+ (no_router_ospf): 'no router ospf' unregister redistribution
+ requests from zebra.
+
+2000-11-28 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_ism.c (ism_change_status): Increment status change number.
+
+ * ospf_interface.h (struct ospf_interface): Add new member for
+ status change statistics.
+
+ * Makefile.am: Update dependencies.
+
+ * ospf_zebra.c (ospf_interface_add): OSPF SNMP interface update.
+ (ospf_interface_delete): OSPF SNMP interface delete.
+
+ * ospf_snmp.h: New file is added.
+
+2000-11-23 Dick Glasspool <dick@ipinfusion.com>
+
+ * ospfd.h: Add new ospf_area structure member for
+ NSSATranslatorRole and NSSATranslator state.
+
+ * ospfd.c: Provided for eventual commands to specify NSSA
+ elections for "translator- ALWAYS/NEVER/CANDIDATE". Provided for
+ decimal integer version of area-suppress.
+
+ * ospf_flood.c: Flood Type-7's only into NSSA (not AS).
+
+ * ospf_lsa.c: Undo some previous changes for NSSA. If NSSA
+ translator, advertise Nt bit.
+
+ * ospf_route.c: 1st version of "sh ip os border-routers".
+
+2000-11-23 Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+ * ospfd.c (area_vlink): Virtual link can not configured in stub
+ area.
+
+2000-11-23 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_packet.c (ospf_db_desc): In states Loading and Full the
+ slave must resend its last Database Description packet in response
+ to duplicate Database Description packets received from the
+ master. For this reason the slave must wait RouterDeadInterval
+ seconds before freeing the last Database Description packet.
+ Reception of a Database Description packet from the master after
+ this interval will generate a SeqNumberMismatch neighbor
+ event. RFC2328 Section 10.8
+ (ospf_make_db_desc): DD Master flag treatment.
+
+ * ospf_nsm.c (nsm_twoway_received): Move DD related procedure to
+ nsm_change_status().
+ (nsm_bad_ls_req): Likewise.
+ (nsm_adj_ok): Likewise.
+ (nsm_seq_number_mismatch): Likewise.
+ (nsm_oneway_received): Likewise.
+
+ * ospf_neighbor.h (struct ospf_neighbor): New structure member
+ last_send_ts for timestemp when last Database Description packet
+ was sent.
+
+ * ospf_nsm.c (ospf_db_desc_timer): Make it sure nbr->last_send is
+ there. Call ospf_db_desc_resend() in any case.
+
+2000-11-16 Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+ * ospf_lsa.c (lsa_link_broadcast_set): When there is no DR on
+ network (suppose you have only one router with interface priority
+ 0). It's router LSA does not contain the link information about
+ this network.
+
+ * ospf_nsm.c (nsm_timer_set): When you change a priority of
+ interface from/to 0 ISM_NeighborChange event should be scheduled
+ in order to elect new DR/BDR on the network.
+
+ * ospf_interface.c (ip_ospf_priority): Likewise.
+
+ * ospf_flood.c (ospf_ls_retransmit_add): When we add some LSA into
+ retransmit list we need to check whether the present old LSA in
+ retransmit list is not more recent than the new
+ one.
+
+2000-11-09 Dick Glasspool <dick@ipinfusion.com>
+
+ * ospf_packet.c: Allows for NSSA Type-7 LSA's throughout the NSSA
+ area. Any that exit the NSSA area are translated to type-5 LSA's.
+ The instantiated image is restored after translation.
+ (ospf_ls_upd_send_list): Renamed to ospf_ls_upd_queu_send().
+ (ospf_ls_upd_send): Old function which enclosed by #ifdef 0 is
+ removed.
+ (ospf_ls_ack_send): Likewise.
+
+ * ospf_flood.c: NSSA-LSA's without P-bit will be restricted to
+ local area. Otherwise they are allowed out the area to be
+ translated by ospf_packet.c.
+
+ * ospf_lsa.c: Undo some previous changes for NSSA.
+
+ * ospf_lsdb.h: New access for type 7.
+
+2000-11-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_route.c (ospf_path_exist): New function to check nexthop
+ and interface are in current OSPF path or not.
+ (ospf_route_copy_nexthops_from_vertex): Add nexthop to OSPF path
+ when it is not there. Reported by Michael Rozhavsky
+ <mrozhavsky@opticalaccess.com>
+
+2000-11-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_dump.c (config_write_debug): Add seventh string "detail" is
+ added for flag is OSPF_DEBUG_SEND | OSPF_DEBUG_RECV |
+ OSPF_DEBUG_DETAIL.
+
+2000-11-06 Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+ * ospf_lsa.c (router_lsa_flags): ASBR can't exit in stub area.
+
+2000-11-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_lsa.c (ospf_router_lsa_originate): Reduce unconditional
+ logging.
+
+2000-11-06 Dick Glasspool <dick@ipinfusion.com>
+
+ * ospfd.h: Add ait_ntoa function prototype.
+
+ * ospfd.c (ait_ntoa): New function for displaying area ID and
+ Stub/NSSA status.
+ (show_ip_ospf_interface_sub): Use ait_ntoa.
+ (show_ip_ospf_nbr_static_detail_sub): Likewise.
+ (show_ip_ospf_neighbor_detail_sub): Likewise.
+
+ * ospf_route.c (ospf_intra_route_add): Set external routing type
+ to ospf route.
+ (ospf_intra_add_router): Likewise.
+ (ospf_intra_add_transit): Likewise.
+ (ospf_intra_add_stub): Likewise.
+ (ospf_add_discard_route): Likewise.
+ (show_ip_ospf_route_network): Use ait_ntoa.
+ (show_ip_ospf_route_network): Likewise.
+ (show_ip_ospf_route_router): Likewise.
+
+ * ospf_lsa.c (show_lsa_detail): Use ait_ntoa.
+ (show_lsa_detail_adv_router): Likewise.
+ (show_ip_ospf_database_summary): Likewise.
+
+ * ospf_route.h (struct route_standard): Add new member
+ external_routing.
+
+ * ospf_ia.c (process_summary_lsa): Set external routing tyep to ospf
+ route.
+ (ospf_update_network_route): Likewise.
+ (ospf_update_router_route): Likewise.
+
+2000-11-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_flood.c (ospf_process_self_originated_lsa): Enclose
+ OSPF_AS_NSSA_LSA treatment with #ifdef HAVE_NSSA.
+
+2000-11-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Unconditional logging is enclosed with if (IS_DEBUG_OSPF_EVENT).
+ Please specify "debug ospf event" for enable logging.
+
+ * ospf_ism.c: Do not extern debug flag varible. It is done by
+ ospf_debug.h
+ * ospf_asbr.c: Likewise.
+ * ospf_lsa.c: Likewise.
+ * ospf_nsm.c: Likewise.
+ * ospf_zebra.c: Likewise.
+
+ * ospf_dump.c (debug_ospf_event): New command "debug ospf event"
+ is added.
+
+ * ospfd.c (router_ospf): Change logging from vty_out() to
+ zlog_info().
+ (ospf_area_stub_cmd): Likewise.
+
+ * ospf_dump.h: Extern term_debug flags.
+ (OSPF_DEBUG_EVENT): Add new flag.
+ (IS_DEBUG_OSPF_EVENT): Add new macro.
+
+2000-11-03 Dick Glasspool <dick@ipinfusion.com>
+
+ * ospf_flood.c (ospf_process_self_originated_lsa):
+ OSPF_AS_NSSA_LSA is treated as same as OSPF_AS_EXTERNAL_LSA.
+ (ospf_flood): Type-5's have no change. Type-7's can be received,
+ and will Flood the AS as Type-5's They will also flood the local
+ NSSA Area as Type-7's. The LSDB will be updated as Type-5's, and
+ during re-fresh will be converted back to Type-7's (if within an
+ NSSA).
+ (ospf_flood_through): Incoming Type-7's were allowed here if our
+ neighbor was an NSSA. So Flood our area with the Type-7 and also
+ if we are an ABR, flood thru AS as Type-5.
+
+ * ospf_lsa.c (ospf_external_lsa_refresh): Flood NSSA both NSSA
+ area and other area.
+
+ * ospf_packet.c (ospf_db_desc_proc): When AS External LSA is
+ exists in DD packet, make it sure that this area is not stub.
+ (ospf_ls_upd_list_lsa): When LSA type is NSSA then set lsa's area
+ to NULL.
+ (ospf_ls_upd): If the LSA is AS External LSA and the area is stub
+ then discard the lsa. If the LSA is NSSA LSA and the area is not
+ NSSA then discard the lsa.
+
+2000-11-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospfd.c (ospf_interface_run): Fix bug of Hello packet's option
+ is not properly set when interface comes up.
+
+2000-11-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospfd.h (OSPF_OPTION_O): Add new hello header option.
+
+2000-11-01 Dick Glasspool <dick@ipinfusion.com>
+
+ * ospf_lsa.h: Define OSPF_MAX_LSA to 8 when HAVE_NSSA is enabled.
+ (OSPF_GROUP_MEMBER_LSA): Define OSPF_GROUP_MEMBER_LSA.
+
+ * ospf_lsa.c (show_database_desc): Add "Group Membership LSA"
+ string.
+
+2000-10-31 Dick Glasspool <dick@ipinfusion.com>
+
+ * ospf_lsa.h (OSPF_AS_NSSA_LSA): Define OSPF_AS_NSSA_LSA.
+
+ * ospf_lsa.c (show_ip_ospf_database): NSSA database display
+ function is added. ALIASES which have "show ip ospf database
+ nssa-external" is added.
+ (show_ip_ospf_border_routers): New command "show ip ospf
+ border-routers" is added.
+
+2000-10-30 Dick Glasspool <dick@ipinfusion.com>
+
+ * ospfd.c (router_ospf): NSSA Enabled message is added for
+ testing.
+ (ospf_area_type_set): Are type set for NSSA area.
+ (ospf_area_stub_cmd): Special translation of no_summary into NSSA
+ and summary information. If NSSA is enabled pass the information
+ to ospf_area_type_set().
+ (area_nssa): New commands are added:
+ "area A.B.C.D nssa"
+ "area <0-4294967295> nssa"
+ "area A.B.C.D nssa no-summary"
+ "area <0-4294967295> nssa no-summary"
+ (ospf_no_area_stub_cmd): Special translation of no_summary into
+ NSSA and summary information. If external_routing is
+ OSPF_AREA_NSSA unset area with ospf_area_type_set (area,
+ OSPF_AREA_DEFAULT).
+ (show_ip_ospf_area): Display NSSA status.
+ (config_write_ospf_area): Show NSSA configuration.
+
+ * ospf_packet.c (ospf_hello): For NSSA support, ensure that NP is
+ on and E is off.
+
+2000-10-26 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_lsa.c (ospf_network_lsa_body_set): The network-LSA lists
+ those routers that are fully adjacent to the Designated Router;
+ each fully adjacent router is identified by its OSPF Router ID.
+ The Designated Router includes itself in this list. RFC2328,
+ Section 12.4.2.
+
+2000-10-23 Jochen Friedrich <jochen@scram.de>
+
+ * ospf_snmp.c: ospf_oid and ospfd_oid are used in smux_open after
+ it is registered. So those variables must be static.
+
+2000-10-18 K N Sridhar <sridhar@euler.ece.iisc.ernet.in>
+
+ * ospfd.c: Add area_default_cost_decimal_cmd and
+ no_area_default_cost_decimal_cmd alias.
+
+2000-10-05 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospfd.c (ospf_network_new): Fix setting area format.
+ (no_router_ospf): Check area existance when calling
+ ospf_interface_down().
+
+ * ospf_flood.c (ospf_external_info_check): Fix bug of refreshing
+ default route.
+
+2000-10-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.89 is released.
+
+2000-09-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_snmp.c (ospfHostEntry): OSPF Host MIB is implemented.
+
+ * ospfd.c (ospf_nbr_static_cmp): OSPF neighbor is sorted by it's
+ address.
+
+2000-09-28 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospf_interface.c (ospf_if_free): Fix deleting self neighbor twice.
+
+2000-09-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_packet.c (ospf_read): Solaris on x86 has ip_len with host
+ byte order.
+
+2000-09-25 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.c (ospf_compatible_rfc1583), (no_ospf_compatible_rfc1583):
+ Add CISCO compatible command.
+
+2000-09-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_abr.c (ospf_area_range_lookup): New function is added for
+ area range lookup in OSPF-MIB.
+ (ospf_area_range_lookup_next): Likewise.
+
+2000-09-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospfd.c (no_router_ospf): Delete virtual link before deleting
+ area structure.
+
+ * ospf_lsa.c (ospf_external_lsa_refresh_type): Check
+ EXTERNAL_INFO(type).
+
+ * ospfd.c (no_router_ospf): Call ospf_vl_delete() instead of
+ ospf_vl_data_free().
+
+ * ospf_interface.c (ospf_vl_shutdown): Execute ISM_InterfaceDown
+ when ospf_vl_shutdown is called.
+ (ospf_vl_delete): Call ospf_vl_shutdown() to delete virtual link
+ interface's thread.
+
+2000-09-21 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_lsa.c: New implementation of OSPF refresh.
+
+2000-09-20 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_snmp.c (ospfLsdbLookup): Add LSDB MIB implementation.
+
+2000-09-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_snmp.c (ospfStubAreaEntry): Add OSPF stub area MIB.
+
+2000-09-18 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_route.h (route_standard): Change member from `struct area'
+ to area_id.
+
+ * ospf_abr.c (ospf_abr_announce_network), (ospf_abr_should_announce),
+ (ospf_abr_process_network_rt), (ospf_abr_announce_rtr),
+ (ospf_abr_process_router_rt):
+ * ospf_ase.c (ospf_find_asbr_route),
+ (ospf_find_asbr_router_through_area),
+ * ospf_ia.c (ospf_find_abr_route), (ospf_ia_router_route),
+ (process_summary_lsa), (ospf_update_network_route),
+ (ospf_update_router_route):
+ * ospf_route.c (ospf_intra_route_add), (ospf_intra_add_router),
+ (ospf_intra_add_transit), (ospf_intra_add_stub),
+ (ospf_route_table_dump), (show_ip_ospf_route_network),
+ (show_ip_ospf_route_router), (ospf_asbr_route_cmp),
+ (ospf_prune_unreachable_routers):
+ * ospf_spf.c (ospf_rtrs_print):
+ * ospfd.c (ospf_rtrs_free): Fix the struct change above.
+
+2000-09-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_network.c (ospf_serv_sock_init): Enclose SO_BINDTODEVICE
+ with ifdef.
+
+2000-09-13 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_ism.c (ospf_elect_dr), (ospf_elect_bdr): Fix DR election.
+
+ * ospf_network.c (ospf_serv_sock_init): Add socket option
+ SO_BINDTODEVICE on read socket.
+
+ * ospf_packet.c (ospf_hello): Ignore Hello packet if E-bit does
+ not match.
+
+ * ospfd.c (ospf_area_check_free), (ospf_area_get),
+ (ospf_area_add_if): New function added.
+
+2000-09-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_route.c (ospf_intra_add_router): Update ABR and ASBR router
+ count.
+
+ * ospf_spf.c (ospf_spf_init): Rest ABR and ASBR router count
+ starting SPF calculation.
+
+ * ospfd.h (struct ospf_area): Add ABR and ASBR router count.
+
+2000-09-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospfd.c (ospf_area_id_cmp): New area structure is sorted by area
+ ID.
+
+ * ospf_lsa.c (ospf_router_lsa_originate): For OSPF MIB update
+ lsa_originate_count.
+ (ospf_network_lsa_originate): Likewise.
+ (ospf_summary_lsa_originate): Likewise.
+ (ospf_summary_asbr_lsa_originate): Likewise.
+ (ospf_external_lsa_originate): Likewise.
+
+2000-09-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_snmp.c (ospf_variables): ospfRouterID's type RouterID
+ syntax is IpAddress.
+ (ospf_admin_stat): New function for OSPF administrative status
+ check.
+
+2000-09-10 Jochen Friedrich <jochen@scram.de>
+
+ * ospf_snmp.c: Implement OSPF MIB skeleton.
+
+2000-09-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_snmp.c: New file is added.
+
+2000-09-07 David Lipovkov <davidl@nbase.co.il>
+
+ * ospf_zebra.c (ospf_interface_delete): Add pseudo interface
+ treatment.
+
+ * ospf_interface.c (interface_config_write): Likewise.
+
+2000-08-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.88 is released.
+
+2000-08-17 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospfd.c (ospf_area_free): Remove virtual link configuration only
+ when Area is removed.
+
+2000-08-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospfd.c (network_area): Revert check for EXTERNAL_INFO
+ (ZEBRA_ROUTE_CONNECT).
+ (no_network_area): Likewise.
+
+2000-08-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospfd.h (struct ospf): Add distance_table and
+ distance_{all,intra,inter,external}.
+
+ * ospf_zebra.c: Add OSPF distance related functions.
+
+2000-08-15 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_asbr.c (ospf_external_info_find_lsa): New function added.
+
+ * ospf_lsa.c (ospf_default_external_info),
+ (ospf_default_originate_timer), (ospf_external_lsa_refresh_default):
+ New function added.
+
+ * ospf_zebra.c
+ (ospf_default_information_originate_metric_type_routemap),
+ (ospf_default_information_originate_always_metric_type_routemap):
+ Change name and add route-map function.
+ (ospf_default_information_originate_metric_routemap),
+ (ospf_default_information_originate_routemap),
+ (ospf_default_information_originate_type_metric_routemap):
+ New DEFUN added.
+
+2000-08-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_zebra.c (zebra_interface_if_set_value): Change ifindex
+ restore size from two octet to four.
+
+2000-08-14 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospf_ase.c (ospf_ase_incremental_update): Implement incremental
+ AS-external-LSA in 16.6 of RFC2328.
+
+2000-08-14 Matthew Grant <grantma@anathoth.gen.nz>
+
+ * ospf_interface.c (ospf_if_get_output_cost): Change cost
+ calculation algorithm.
+
+ * ospf_packet (ospf_ls_upd): Fix problem of LSA retransmitting.
+
+2000-08-11 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospf_lsa.c (ospf_maxage_lsa_remover): Fix maxage remover for
+ AS-external-LSAs.
+
+2000-08-10 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.c (auto_cost_reference_bandwidth): New DEFUN added.
+ `auto-cost reference-bandwidth' OSPF router command added.
+
+2000-08-08 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_routemap.c (ospf_route_map_update): New function added.
+ Add route-map event hook.
+
+2000-08-08 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_zebra.c (ospf_distribute_check_connected): If redistribute
+ prefix is connected route on OSPF enabled interface, suppress to
+ announce it.
+
+2000-08-08 Matthew Grant <grantma@anathoth.gen.nz>
+
+ * ospf_interface.c (ospf_if_get_output_cost):
+ New function added. Handle bandwidth parameter for cost
+ calculation.
+
+2000-08-08 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospf_interface.c (interface_config_write): Show interface
+ configuration regardless interface is down.
+
+ * ospf_ase.c (ospf_ase_caocluate_route): Whole rewritten external
+ route calculate function.
+
+2000-08-08 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_routemap.c: New file added.
+
+ * ospf_asbr.c (ospf_reset_route_map_set_values),
+ (ospf_route_map_set_compare): New function added.
+
+ * ospf_lsa.c (ospf_external_lsa_body_set): Set routemap metric
+ with AS-external-LSA.
+
+2000-08-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_ase.c (ospf_ase_calculate_route_add): Pass new->cost to
+ ospf_zebra_add as metric.
+ (ospf_ase_calculate_route_add): Likewise.
+
+ * ospf_route.c (ospf_route_install): Pass or->cost to
+ ospf_zebra_add as metric.
+
+ * ospf_zebra.c (ospf_zebra_add): Add metric arguemnt.
+ (ospf_zebra_delete): Likewise.
+
+2000-08-03 Matthew Grant <grantma@anathoth.gen.nz>
+
+ * ospf_flood.c (ospf_flood_delayed_lsa_ack): New function added.
+ Dispatch delayed-ACK with flooding AS-external-LSA across virtual
+ link.
+
+2000-07-31 Matthew Grant <grantma@anathoth.gen.nz>
+
+ * ospfd.c (show_ip_ospf_area): Fix lack of VTY_NEWLINE when
+ `show ip ospf'.
+
+ * ospf_interface.c (ospf_if_free): Fix bug of crash with
+ Point-to-Point interface.
+
+2000-07-27 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospf_flood.c (ospf_process_self_originated_lsa):
+ Make sure to clear LSA->param (redistributed external information)
+ before refreshment.
+
+2000-07-27 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospfd.c (refresh_group_limit), (refresh_per_slice),
+ (refresh_age_diff): New defun added. Refresher related parameter
+ can be configurable.
+
+2000-07-27 Akihiro Mizutani <mizutani@dml.com>
+
+ * ospf_interface.c (interface_config_write): Print `description'
+ config directive to work.
+
+2000-07-24 Akihiro Mizutani <mizutani@dml.com>
+
+ * ospf_interface.c (ospf_if_init): Use install_default for
+ INTERFACE_NODE.
+
+2000-07-24 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_packet.c (ospf_ls_upd_send_list), (ospf_ls_upd_send_event),
+ (ospf_ls_ack_send_list), (ospf_ls_ack_send_event): New function added.
+ This make sending always as many LS update/Ack combined in one ospf
+ packet.
+
+2000-07-24 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_packet.c (ospf_ls_upd_list_lsa): Set NULL to lsa->area if
+ LSA is AS-external-LSA.
+
+ * ospf_nsm.c (nsm_reset_nbr): Do not cancel Inactivity timer.
+
+2000-07-21 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_zebra.c (ospf_default_originate_timer): Set timer for
+ `default-information originate'. Fix some default originate
+ related functions.
+
+2000-07-12 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (stream_put_ospf_metric): New function added.
+
+2000-07-12 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (show_ip_ospf_database_router),
+ (show_ip_ospf_database_network), (show_ip_ospf_database_summary),
+ (show_ip_ospf_database_summary_asbr), (show_ip_ospf_database_externel),
+ (show_router_lsa), (show_any_lsa), (show_router_lsa_self),
+ (show_any_lsa_self): Functions removed.
+
+ (show_lsa_prefix_set), (show_lsa_detail_proc), (show_lsa_detail),
+ (show_lsa_detail_adv_router_proc), (show_lsa_detail_adv_router):
+ New functions added. Replace above functions.
+
+ (show_ip_ospf_database_all), (show_ip_ospf_database_self_originated):
+ Functions removed.
+ (show_ip_ospf_database_summary): New functions added. Replace
+ above functions.
+
+ (show_ip_ospf_database_cmd): DEFUN rearranged.
+ (show_ip_ospf_database_type_id_cmd),
+ (show_ip_ospf_database_type_id_adv_router_cmd),
+ (show_ip_ospf_database_type_is_self_cmd): New ALIASes added.
+ (show_ip_ospf_database_type_adv_rotuer_cmd): New DEFUN added.
+ (show_ip_ospf_database_type_self_cmd): New ALIAS added.
+
+2000-07-11 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_asbr.c (ospf_external_info_new),
+ (ospf_external_info_free): New functions added.
+
+ * ospf_lsa.h (ospf_lsa): Add new member `void *param' to set
+ origination parameter for external-LSA.
+ Remove member `redistribute'.
+
+ * ospf_zebra.c (ospf_redistirbute_set): When `redistribute'
+ command executed, metric and metric-type values are overridden.
+ If one of those is changed refresh AS-external-LSAs for appropriate
+ type.
+
+2000-07-11 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospf_lsa.c (ospf_summary_lsa_refresh),
+ (ospf_summary_asbr_lsa_refresh): Make sure to refresh summary-LSAs.
+
+ * ospf_abr.c (set_metric): New function added.
+
+2000-07-07 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_zebra.c (ospf_default_information_originate_metric_type),
+ (ospf_default_information_originate_type_metric): New defun added.
+ Metic and Metric type can be set to default route.
+ (ospf_default_information_originate_always_metric_type):
+ (ospf_default_information_originate_always_type_metric):
+ New defun added. Metric and Metric type can be set to default
+ always route.
+
+ * ospf_zebra.c (ospf_default_metric), (no_ospf_default_metric):
+ New defun added.
+
+2000-07-06 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_flood.c (ospf_flood_through_area): Fix bug of considering
+ on the same interface the LSA was received from.
+
+2000-07-06 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospfd.c (ospf_config_write): Fix bug of printing `area stub'
+ command with `write mem'.
+
+ * ospfd.c (no_router_ospf): Remove installed routes from zebra.
+
+ * ospf_zebra.c (ospf_interface_delete): Fix function to handle
+ zebra interface delete event.
+
+2000-07-06 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_zebra.c (ospf_default_information_originate),
+ (ospf_default_information_originate_always): New DEFUN added.
+
+2000-07-05 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospf_route.c (ospf_terminate): Make sure to remove external route
+ when SIGINT received.
+
+2000-07-03 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_flood.c, ospf_ism.c, ospf_lsa,c, ospfd.c: Make sure to free
+ many structure with `no router ospf'.
+
+2000-06-30 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_neighbor.c (ospf_nbr_new),
+ ospf_nsm.c (nsm_timer_set): Start LS update timer only
+ when neighbor enters Exchange state.
+
+2000-06-29 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_nsm.c (nsm_timer_set), (nsm_exchange_done),
+ ospf_packet.c (ospf_db_desc_proc):
+ Do not cancel DD retransmit timer when Master.
+
+2000-06-29 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_abr.c (ospf_abr_announce_network_to_area),
+ (ospf_abr_announce_rtr_to_area)
+ ospf_ase.c (ospf_ase_rtrs_register_lsa),
+ ospf_flood.c (ospf_process_self_originated_lsa),
+ (ospf_flood_through_area), (ospf_ls_request_delete),
+ ospf_interface.c (ospf_if_free),
+ ospf_ism.c (ism_change_status),
+ ospf_lsa.c (ospf_router_lsa_update_timer),
+ (ospf_router_lsa_install), (ospf_network_lsa_install),
+ (ospf_lsa_maxage_delete), (ospf_lsa_action),
+ (ospf_schedule_lsa_flood_area),
+ ospf_nsm.c (nsm_change_status),
+ ospf_packet.c (ospf_make_ls_req_func), (ospf_make_ls_ack):
+ Use ospf_lsa_{lock,unlock} for all looking-up of LSA.
+
+ * ospf_flood.c (ospf_ls_request_free): Function deleted.
+
+ * ospf_lsa.c (ospf_discard_from_db): New function added.
+
+2000-06-26 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.h (ospf): struct member `external_lsa' name changed to
+ `lsdb'.
+
+2000-06-26 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (ospf_lsa_install), (ospf_router_lsa_install),
+ (ospf_network_lsa_install), (ospf_summary_lsa_install),
+ (ospf_summary_asbr_lsa_install), (ospf_external_lsa_install):
+ Functions re-arranged.
+
+ * ospf_lsa.c (IS_LSA_MAXAGE), (IS_LSA_SELF): Macro added.
+
+2000-06-20 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospf_packet.c (ospf_ls_req), (ospf_ls_upd), (ospf_ls_ack): Add
+ verification of LS type.
+
+2000-06-20 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_ase.c (ospf_ase_calculate_timer): Add more sanity check
+ whether rn->info is NULL.
+
+2000-06-20 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.c (show_ip_ospf_interface_sub): Show Router-ID of both
+ DR and Backup correctly with `show ip ospf interface' command.
+
+2000-06-20 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (ospf_lsa_lock), (ospf_lsa_unlock),
+ (ospf_lsa_discard): These functions are used for avoiding
+ unexpected reference to freed LSAs.
+
+2000-06-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_packet.c (ospf_ls_upd): Initialize lsa by NULL to avoid
+ warning.
+
+2000-06-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_ase.h (ospf_ase_rtrs_register_lsa): Add prototype.
+
+2000-06-12 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (ospf_external_lsa_install): Make sure to register
+ LSA to rtrs_external when replacing AS-external-LSAs in LSDB.
+ Fix core dump.
+
+2000-06-10 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsdb.c (id_to_prefix), (ospf_lsdb_hash_key),
+ (ospf_lsdb_hash_cmp), (ospf_lsdb_new), (ospf_lsdb_iterator),
+ (lsdb_free), (ospf_lsdb_free), (ospf_lsdb_add), (ospf_lsdb_delete),
+ (find_lsa), (ospf_lsdb_lookup), (find_by_id),
+ (ospf_lsdb_lookup_by_id), (ospf_lsdb_lookup_by_header): Functinos
+ removed for migration to new_lsdb.
+
+ * ospf_lsa.c (ospf_summary_lsa_install),
+ (ospf_summary_asbr_lsa_install), (ospf_maxage_lsa_remover),
+ (ospf_lsa_maxage_walker), (ospf_lsa_lookup),
+ (ospf_lsa_lookup_by_id): Use new_lsdb instead of ospf_lsdb.
+ (count_lsa), (ospf_lsa_count_table), (ospf_lsa_count),
+ (ospf_get_free_id_for_prefix): Funcitions removed.
+
+2000-06-09 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_ism.c (ism_interface_down): Prevent some unneeded DR changes.
+
+ * ospf_packet.c (ospf_db_desc_proc): Fix memory leak.
+ (ospf_hello): Always copy router-ID when hello is received.
+
+2000-06-08 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_lsa.h (struct ospf_lsa): Add member of pointer to struct
+ ospf_area.
+
+2000-06-08 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospf_ase.c (ospf_asbr_route_same): New function added.
+ This function makes sure external route calculation more
+ precisely.
+
+2000-06-07 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospf_ism.c (ism_change_status): Use ospf_lsa_flush_area for
+ network-LSA deletion instead of using ospf_lsdb_delete.
+ Also cancel network-LSA origination timer.
+
+2000-06-07 Levi Harper <lharper@kennedytech.com>
+
+ * ospf_interface.c (ospf_if_down): Close read fd when an interface
+ goes down.
+
+2000-06-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_asbr.c (ospf_external_info_lookup): Add explicit brace for
+ avoid ambiguous else.
+
+ * ospf_flood.c (ospf_external_info_check): Likewise.
+
+2000-06-05 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_nsm.c (nsm_adj_ok): Fix bug of DR election.
+
+2000-06-04 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_zebra.c (ospf_default_information_originate),
+ (no_ospf_default_information_originate): New DEFUN added.
+
+2000-06-03 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.h, ospf_asbr.h (external_info): Struct moved from
+ ospf_lsa.h to ospf_asbr.h.
+
+ * ospf_lsa.c, ospf_asbr.c (ospf_external_info_add),
+ (ospf_external_info_delete): Function moved from ospf_lsa.c
+ to ospf_asbr.c.
+
+2000-06-03 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_flood.c (ospf_external_info_check): New function added.
+ (ospf_process_self_orignated_lsa): Make sure to flush
+ self-originated AS-external-LSA, when router reboot and no longer
+ originate those AS-external-LSA.
+
+2000-06-02 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_network.c (ospf_serv_sock): Remove SO_DONTROUTE
+ socket option.
+
+ * ospf_packet.c (ospf_write): Set MSG_DONTROUTE flag for
+ unicast destination packets.
+
+2000-06-02 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsdb.c (new_lsdb_delete): Delete entry from LSDB only when
+ specified LSA matches.
+
+2000-06-02 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_network.c (ospf_serv_sock): Set SO_DONTROUTE
+ socket option.
+
+2000-06-01 Akihiro Mizutani <mizutani@dml.com>
+
+ * ospf_dump.c: Replace string `Debugging functions\n' with DEBUG_STR.
+ Replace string `OSPF information\n' with OSPF_STR.
+
+2000-06-01 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsdb.[ch]: Use new_lsdb struct for network-LSA instead of
+ ospf_lsdb.
+
+2000-06-01 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_dump.c (config_debug_ospf_packet), (config_debug_ospf_event),
+ (config_debug_ospf_ism), (config_debug_ospf_nsm),
+ (config_debug_ospf_lsa), (config_debug_ospf_zebra),
+ (term_debug_ospf_packet), (term_debug_ospf_event),
+ (term_debug_ospf_ism), (term_debug_ospf_nsm),
+ (term_debug_ospf_lsa), (term_debug_ospf_zebra): Repalce debug_ospf_*
+ variable to use for debug option flags.
+
+ (debug_ospf_packet), (debug_ospf_ism), (debug_ospf_nsm),
+ (debug_ospf_lsa), (debug_ospf_zebra): Set {config,term}_debug_*
+ flags when vty->node is CONFIG_NODE, otherwise set only term_debug_*
+ flags.
+
+ * ospf_dump.h (CONF_DEBUG_PACKET_ON), (CONF_DEBUG_PACKET_OFF),
+ (TERM_DEBUG_PACKET_ON), (TERM_DEBUG_PACKET_OFF),
+ (CONF_DEBUG_ON), (CONF_DEBUG_OFF), (IS_CONF_DEBUG_OSPF_PACKET),
+ (IS_CONF_DEBUG_OSPF): New Macro added.
+
+2000-05-31 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.c (clear_ip_ospf_neighbor): New DEFUN added.
+ Currently this command is used for only debugging.
+
+ * ospf_nsm.c (nsm_change_status): Make sure thread cancellation
+ for network-LSA when DR has no full neighbors.
+
+ * ospf_nsm.c (ospf_db_summary_clear): New function added.
+
+2000-05-30 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsdb.c (new_lsdb_insert): LSAs are always freed by
+ maxage_lsa_remover when LSA is replaced.
+
+2000-05-25 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_flood.c (ospf_ls_retransmit_delete_nbr_all): Add argument
+ `struct ospf_area' to remove LSA from Link State retransmission list
+ of neighbor from only one Area.
+
+2000-05-24 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospf_lsdb.c (ospf_lsdb_add): Preserve flags field when
+ overriting old LSA with new LSA.
+
+2000-05-24 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_lsa.c (ospf_router_lsa_body_set): Fix bug of router-LSA
+ size calculation.
+
+2000-05-22 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospf_route.c (ospf_intra_add_stub):
+ * ospf_spf.h (struct vertex): Use u_int32_t for distance (cost)
+ value instead of u_int16_t.
+
+2000-05-22 Axel Gerlach <agerlach@datus.datus.com>
+
+ * ospf_ia.c (ospf_ia_network_route): Fix bug of Inter-area route
+ equal cost path calculation.
+
+2000-05-21 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_ase.c (ospf_ase_calculate_route_delete): New function added.
+ Make sure, when rotuer route is deleted, related external routes
+ are also deleted.
+
+2000-05-20 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.c (ospf_interface_down): Make sure interface flag is disable
+ and set fd to -1.
+
+2000-05-16 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_asbr.c (ospf_asbr_should_announce), (ospf_asbr_route_remove):
+ Functions removed.
+
+ * ospfd.h (EXTERNAL_INFO): Macro added.
+ Substitute `ospf_top->external_info[type]' with it.
+
+2000-05-16 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (ospf_rtrs_external_remove): New function added.
+
+2000-05-14 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_flood.c (ospf_ls_retransmit_delete_nbr_all)
+ * ospf_lsdb.c (new_lsdb_insert)
+ * ospf_packet.c (ospf_ls_ack): Fix database synchonization problem.
+
+2000-05-14 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_lsa.h (tv_adjust), (tv_ceil), (tv_floor), (int2tv),
+ (tv_add), (tv_sub), (tv_cmp): Prototype definition added.
+
+ * ospf_nsm.h (ospf_db_summary_delete_all): Prototype definition added.
+
+2000-05-13 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.[ch] (ospf_lsa): struct timestamp type is changed from
+ time_t to struct timeval.
+ (tv_adjust), (tv_ceil), (tv_floor), (int2tv), (tv_add),
+ (tv_sub), (tv_cmp): timeval utillity functions added.
+
+2000-05-12 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.[ch] (ospf_schedule_update_router_lsas): Delete function.
+ Change to use macro OSPF_LSA_UPDATE_TIMER instead of using
+ this function.
+ router-LSA refresh timer related stuff is re-organized.
+
+2000-05-10 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_interface.c (ospf_vl_set_params):
+ * ospf_packet.c (ospf_check_network_mask):
+ * ospf_spf.[ch] (ospf_spf_next):
+ Remove field address from `struct vertex', and search for peer
+ address of virtual link in function `ospf_vl_set_params' instead.
+
+2000-05-10 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_packet.c (ospf_ls_upd): Fix some memory leak related LSA.
+
+2000-05-08 Thomas Molkenbur <tmo@datus.com>
+
+ * ospf_packet.c (ospf_packet_dup): Replace ospf_steram_copy()
+ with ospf_stream_dup() to fix memory leak.
+
+2000-05-08 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospf_flood.c (ospf_flood_through_area): Fix the problem of
+ LSA update without DROther.
+
+2000-05-04 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_spf.c (ospf_vertex_free): Fix memory leak of SPF calculation.
+
+2000-05-03 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_neighbor.c (ospf_db_summary_add): Use new_lsdb struct
+ instead linked-list.
+ (ospf_db_summary_count), (ospf_db_summary_isempty):
+ New function added.
+
+ * ospf_lsa.c (ospf_rotuer_lsa): Re-arrange and divide functions.
+
+2000-05-02 Gleb Natapov <gleb@nbase.co.il>
+
+ * ospf_lsdb.c (new_lsdb_cleanup): Fix memory leak. When LSDB are
+ not needed any more, then free them.
+
+2000-05-02 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.c (timers_spf), (no_timers_spf): New defun added.
+ SPF calculation timers related stuff is rearranged.
+
+ * ospf_spf.c (ospf_spf_calculate_timer_add): Function removed.
+ SPF timer is scheduled by SPF calculation delay and holdtime
+ configuration variable.
+
+ * ospf_lsa.c (ospf_external_lsa_nexthop_get): Set AS-external-LSA's
+ forwarding address when nexthop learned by other protocols is
+ in the OSPF domain.
+
+ * ospf_zebra.c (ospf_redistribute_source_metric_type),
+ (ospf_redistribute_source_type_metric): Re-arrange DEFUNs and
+ ALIASes.
+
+2000-05-01 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_flood.c (ospf_ls_retransmit_count),
+ (ospf_ls_retransmit_isempty): New function added.
+
+ (ospf_ls_retransmit_add), (ospf_ls_retransmit_delete),
+ (ospf_ls_retransmit_clear), (ospf_ls_retransmit_lookup),
+ (ospf_ls_retransmit_delete_all), (ospf_ls_retransmit_delete_nbr_all),
+ (ospf_ls_retransmit_add_nbr_all): Replace these functions to use
+ new_lsdb.
+
+2000-04-29 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.c (no_network_area): Add check Area-ID whether specified
+ Area-ID with prefix matches config.
+
+2000-04-27 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (ospf_maxage_lsa_remover): Fix problem of
+ remaining withdrawn routes on zebra.
+
+2000-04-25 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospf_nsm.c (nsm_kill_nbr), (nsm_ll_down), (nsm_change_status),
+ (ospf_nsm_event): Fix network-LSA re-origination problem.
+
+2000-04-24 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_nsm.c (ospf_db_desc_timer): Fix bug of segmentation fault
+ with DD retransmission.
+
+ * ospf_nsm.c (nsm_kill_nbr): Fix bug of re-origination when
+ a neighbor disappears.
+
+2000-04-23 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospf_abr.c (ospf_abr_announce_network_to_area): Fix bug of
+ summary-LSAs reorigination. Correctly copy OSPF_LSA_APPROVED
+ flag to new LSA. when summary-LSA is reoriginatd.
+
+ * ospf_flood.c (ospf_flood_through_area): Fix bug of flooding
+ procedure. Change the condition of interface selection.
+
+2000-04-21 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (ospf_refresher_register_lsa): Fix bug of refresh never
+ occurs.
+
+ * ospfd.c (show_ip_ospf_neighbor_id): New defun added.
+ `show ip ospf neighbor' related commands are re-arranged.
+
+2000-04-20 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_dump.c (debug_ospf_zebra): New defun added.
+ Suppress zebra related debug information.
+
+2000-04-19 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_zebra.c (ospf_distribute_list_update_timer),
+ (ospf_distribute_list_update), (ospf_filter_update):
+ New function added. Re-organize `distribute-list' router ospf
+ command.
+
+2000-04-13 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospf_packet.c (ospf_make_ls_upd): Add check for MAX_AGE.
+
+2000-04-14 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospf_packet.c (ospf_make_ls_upd): Increment LS age by configured
+ interface transmit_delay.
+
+2000-04-14 Sira Panduranga Rao <pandu@euler.ece.iisc.ernet.in>
+
+ * ospf_interface.c (ip_ospf_cost), (no_ip_ospf_cost):
+ Add to schedule router_lsa origination when the interface cost changes.
+
+2000-04-12 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (ospf_refresher_register_lsa),
+ (ospf_refresher_unregister_lsa): Fix bug of core dumped.
+
+ * ospfd.c (no_router_ospf): Fix bug of core dumped.
+
+2000-03-29 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_nsm.c (nsm_oneway_received): Fix bug of MS flag unset.
+
+2000-03-29 Michael Rozhavsky <mike@nbase.co.il>
+
+ * ospf_lsa.c (ospf_network_lsa):
+ * ospf_nsm.c (ospf_nsm_event): Fix bug of Network-LSA originated
+ in stub network.
+
+2000-03-28 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_nsm.c (nsm_bad_ls_req), (nsm_seq_number_mismatch),
+ (nsm_oneway_received): Fix bug of NSM state flapping between
+ ExStart and Exchange.
+
+2000-03-28 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_packet.h (strcut ospf_header): Fix the size of ospf_header,
+ change u_int8_t to u_char.
+
+2000-03-27 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (ospf_lsa_checksum): Take care of BIGENDIAN architecture.
+
+2000-03-27 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.c (ospf_interface_run): Make sure Address family matches.
+
+2000-03-26 Love <lha@s3.kth.se>
+
+ * ospf_packet.c (ospf_write): Chack result of sendto().
+
+2000-03-26 Sira Panduranga Rao <pandu@euler.ece.iisc.ernet.in>
+
+ * ospf_nsm.c (nsm_oneway_received): Fix bug of 1-WayReceived in NSM.
+
+2000-03-23 Libor Pechacek <farco@clnet.cz>
+
+ * ospf_lsa.c (ospf_network_lsa)
+ * ospf_lsdb.c (new_lsdb_insert): Fix bug of accessing to
+ unallocated memory.
+
+2000-03-23 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.c (ospf_config_write): Fix bug of duplicate line for
+ `area A.B.C.D authentication'.
+
+2000-03-22 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_debug.c (debug_ospf_lsa), (no_debug_ospf_lsa): Defun added.
+ Suppress all zlog related to LSAs with this config option.
+
+2000-03-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_nsm.c (ospf_nsm_event): Add check for NSM_InactivityTimer.
+
+2000-03-21 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_packet.c (ospf_ls_upd_timer), (ospf_ls_req):
+ Fix bug of memory leak about linklist.
+
+ * ospf_flood.c (ospf_flood_through_area): Likewise.
+
+2000-03-18 Sira Panduranga Rao <pandu@euler.ece.iisc.ernet.in>
+
+ * ospf_flood.c (ospf_ls_retransmit_lookup): Add checksum comparison
+ to identify LSA uniquely. This fix routes lost.
+
+2000-03-18 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_ase.c (ospf_find_asbr_route): Add sanity check with router
+ routing table.
+
+2000-03-17 Alex Zinin <zinin@amt.ru>
+
+ * ospf_spf.[ch]: Bug fix.
+ The 2nd stage of Dijkstra could consider one vertex
+ more than once if there is more than one link
+ between the routers, thus adding extra CPU overhead
+ and extra next-hops.
+ Fixed.
+
+2000-03-15 Sira Panduranga Rao <pandu@euler.ece.iisc.ernet.in>
+
+ * ospf_nsm.c (nsm_inactivity_timer): Changed to call nsm_kill_nbr().
+
+2000-03-14 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_route.c (ospf_route_copy_nexthops): Fix bug of memory leak of
+ ospf_path. Actually ignore merging ospf_route with completely same
+ paths.
+
+2000-03-12 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (show_as_external_lsa_detail): fix bug of
+ external route tag byte order.
+
+2000-03-11 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsdb.c (ospf_lsdb_insert): New function added.
+
+2000-03-09 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (ospf_external_lsa_install),
+ (ospf_lsa_lookup), (show_ip_ospf_database_all),
+ (show_ip_ospf_database_self_originate): Use struct new_lsdb for
+ LSDB of AS-external-LSAs instead of ospf_lsdb.
+
+ * ospf_lsa.c (ospf_lsa_unique_id): New function added.
+ Use for assigning Unique Link State ID instead of
+ ospf_get_free_id_for_prefix().
+
+2000-03-09 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_ase.c (ospf_ase_calculate_timer): Fix bug of segmentation
+ fault reported by George Bonser <george@siteROCK.com>.
+
+2000-03-07 Libor Pechacek <farco@clnet.cz>
+
+ * ospfd.c (ospf_interface_down): Fix bug of segmentation fault.
+
+2000-03-06 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_route.c (ospf_route_cmp): Change meaning of return values.
+
+2000-03-02 Alex Zinin <zinin@amt.ru>
+ * ospfd.h, ospf_ia.h
+ New Shortcut ABR code. Now area's flag can be configured
+ with Default, Enable, and Disable values.
+ More info will be in the new ver of I-D soon (see IETF web).
+
+2000-02-25 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (ospf_lsa_header_set), (ospf_external_lsa_body_set),
+ (osfp_external_lsa_originate), (ospf_external_lsa_queue),
+ (ospf_external_lsa_originate_from_queue): New function added.
+ (ospf_external_lsa): Function removed.
+
+ * ospf_zebra.c (ospf_zebra_read_ipv4): Originate AS-external-LSA
+ when listen a route from Zebra, instead creating external route.
+
+ * ospf_asbr.c (ospf_asbr_route_add_flood_lsa),
+ (ospf_asbr_route_add_queue_lsa),
+ (ospf_asbr_route_install_lsa), (ospf_asbr_route_add):
+ Functions removed.
+
+ * ospf_ase.c (process_ase_lsa): Function will not be used.
+ (ospf_ase_calculate), (ospf_ase_calculate_route_add),
+ (ospf_ase_calculate_new_route), (ospf_ase_caluculate_asbr_route):
+ process_ase_lsa () is separated to these functions.
+
+ OSPF AS-external-LSA origination is whole re-organized.
+
+2000-02-18 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_packet.c (ospf_ls_upd): Fix bug of OSPF LSA memory leak.
+
+ * ospf_asbr.c (ospf_asbr_route_add_flood_lsa),
+ (ospf_asbr_route_add_queue_lsa): Fix bug of OSPF external route
+ memory leak.
+
+2000-02-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_asbr.c (ospf_asbr_route_install_lsa): Re-calculate LSA
+ checksum after change Advertised Router field.
+
+2000-02-09 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_asbr.c (ospf_external_route_lookup): Add new function.
+
+2000-02-08 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.c (ospf_router_id_get), (ospf_router_id_update),
+ (ospf_router_id_update_timer): Router ID decision algorithm is changed.
+ Router ID is chosen from all of eligible interface addresses even if
+ it is not enable to OSPF.
+
+2000-02-08 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_asbr.c (ospf_asbr_route_add): Function divided to
+ ospf_asbr_route_add_flood_lsa, ospf_asbr_route_add_queue_lsa and
+ ospf_asbr_route_install_lsa. If Router-ID is not set, then LSA is
+ waited to install to LSDB.
+ `0.0.0.0 adv_router' AS-external-LSA origination bug was fixed.
+
+2000-02-01 Sira Panduranga Rao <pandu@euler.ece.iisc.ernet.in>
+
+ * ospf_flood.c (ospf_ls_retransmit_lookup): Compare LS seqnum
+ in the ACK before deleting.
+
+ * ospf_packet.c (ospf_hello): Reset the flags after a shutdown
+ and no shutdown of the interface.
+
+2000-01-31 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_packet.c (ospf_ls_req): Send multiple Link State Update
+ packets respond to a Link State Request packet.
+
+ * ospfd.c (show_ip_ospf_neighbor_detail_sub): Show thread state.
+
+ * ospf_interface.c (ospf_vl_new): Crash when backbone area
+ is not configured and set virtual-link to no-backbone area,
+ bug fixed.
+
+2000-01-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_neighbor.h (struct ospf_neighbor): Add pointer to last send
+ LS Request LSA.
+
+ * ospf_packet.c (ospf_ls_upd): Comment out LS request list
+ treatment. That should be done in OSPF flooding procedure.
+
+ * ospf_flood.c (ospf_flood_through_area): Enclose
+ ospf_check_nbr_loding inside if-else close.
+
+2000-01-31 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_packet.c (ospf_make_ls_upd): Fix bug of #LSAs counting.
+
+2000-01-29 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_packet.c (ospf_make_md5_digest): Fix bug of md5 authentication.
+
+2000-01-28 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.c (show_ip_ospf): Show Number of ASE-LSAs.
+
+2000-01-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_packet.c (ospf_make_db_desc): Don't use rm_list for
+ removing LSA from nbr->db_summary.
+
+2000-01-27 Sira Panduranga Rao <pandu@euler.ece.iisc.ernet.in>
+
+ * ospf_packet.c (ospf_ls_upd_send): Set AllSPFRouters to
+ destination when the link is point-to-point.
+ (ospf_ls_ack_send_delayed): Likewise.
+
+2000-01-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_flood.c (ospf_ls_request_delete_all): Fix bug of next
+ pointer lookup after the node is freed.
+
+2000-01-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_asbr.c (ospf_asbr_route_add): Instead of scanning all AS
+ external route, use ospf_top->external_self.
+
+2000-01-27 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (ospf_forward_address_get): New function added.
+
+ * ospf_asbr.c (ospf_asbr_check_lsas): Originate AS-external-LSA
+ only when it should be replaced.
+
+2000-01-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_flood.c (ospf_ls_retransmit_clear): Delete list node.
+
+ * ospf_lsa.c (ospf_lsa_free): Reduce logging message using
+ ospf_zlog value.
+
+ * ospf_ism.c (ism_change_status): Fix bug of DR -> non DR status
+ change. Self originated LSA is freed but not deleted from lsdb.
+
+2000-01-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_ism.c (ism_interface_down): Don't use router_id for
+ detecting self neighbor structure. Instead of that compare
+ pointer itself.
+
+ * ospf_neighbor.c (ospf_nbr_free): Cancel all timer when neighbor
+ is deleted.
+ (ospf_nbr_free): Free last send packet.
+
+ * ospf_neighbor.h (struct ospf_neighbor): Remove host strucutre.
+ Instead of that src is introduced.
+
+ * ospf_nsm.h: Enclose macro defenition with do {} while (0).
+
+2000-01-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospfd.c: Change part of passive interface implementation. For
+ passive interface just disabling sending/receiving Hello on the
+ interface.
+
+2000-01-16 Kai Bankett <kai.bankett@vew-telnet.net>
+
+ * ospf_interface.h (OSPF_IF_PASSIVE): Add passive flag.
+ * ospf_interface.c (ospf_if_lookup_by_name): Add new function.
+ * ospf_lsa.c (ospf_router_lsa): Skip passive interface.
+ * ospfd.c (passive_interface): New command passive-interface is
+ added.
+ (ospf_config_write): Print passive interface.
+
+2000-01-15 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_interface.h (crypt_key): New struct added to store
+ multiple cryptographic autheitication keys.
+ (ospf_interface): struct changed.
+
+ * ospf_interface.c: ospf_crypt_key_new, ospf_crypt_key_add,
+ ospf_crypt_key_lookup, ospf_crypt_key_delete: new functions added.
+
+ * ospf_packet.c (ip_ospf_message_digest_key): Changed to store
+ multiple cryptographic authentication keys.
+
+2000-01-14 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_interface.c: DEFUN (if_ospf_*) commands changed name to
+ ip_ospf_* ().
+ Old notation `ospf *' still remains backward compatibility.
+
+1999-12-29 Alex Zinin <zinin@amt.ru>
+ * ospf_lsa.c: ospf_lsa_more_recent() bug fix
+ * ospf_nsm.c, ospf_packet.c: remove nbr data struct when
+ int goes down, also check DD flags correctly (bug fix)
+
+1999-12-28 Alex Zinin <zinin@amt.ru>
+ * "redistribute <source> metric-type (1|2) metric <XXX>" added
+
+1999-12-23 Alex Zinin <zinin@amt.ru>
+ * added RFC1583Compatibility flag
+ * added dynamic interface up/down functionality
+
+1999-11-19 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_neighbor.h (struct ospf_neighbor): Add member state_change
+ for NSM state change statistics.
+
+1999-11-19 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.c (show_ip_ospf_neighbor_detail),
+ (show_ip_ospf_neighbor_int_detail): DEFUN Added.
+
+1999-11-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_asbr.c (ospf_asbr_check_lsas): Add check of
+ lsa->refresh_list.
+
+1999-11-11 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_ia.[ch] (OSPF_EXAMINE_SUMMARIES_ALL): Macro added.
+ This macro is expanded to ospf_examine_summaries ()
+ for SUMMARY_LSA and SUMMARY_LSA_ASBR.
+ (OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL): Macro added.
+ This macro is expanded to ospf_examine_transit_summaries ()
+ for SUMMARY_LSA and SUMMARY_LSA_ASBR.
+
+1999-11-11 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.[ch] (ospf_find_self_summary_lsa_by_prefix): Changed to
+ macro OSPF_SUMMARY_LSA_SELF_FIND_BY_PREFIX.
+ (ospf_find_self_summary_asbr_lsa_by_prefix): Changed to
+ macro OSPF_SUMMARY_ASBR_LSA_SELF_FIND_BY_PREFIX.
+ (ospf_find_self_external_lsa_by_prefix): Changed to
+ macro OSPF_EXTERNAL_LSA_SELF_FIND_BY_PREFIX.
+
+1999-11-11 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.c (ospf_abr_type): ospf_abr_type_cisco, ospf_abr_type_ibm,
+ ospf_abr_type_shortcut and ospf_abr_type_standard DEFUNs are
+ combined.
+ * ospfd.c (no_ospf_abr_type): no_ospf_abr_type_cisco,
+ no_ospf_abr_type_ibm and no_ospf_abr_type_shortcut DEFUNS are
+ combined.
+
+1999-11-10 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_route.c (ospf_lookup_int_by_prefix): Move function to
+ ospf_interface.c and change name to ospf_if_lookup_by_prefix ().
+
+1999-11-01 Alex Zinin <zinin@amt.ru>
+ * ospf_packet.c
+ some correction to LSU processing
+
+ * ospf_lsa.c ospfd.h
+ randomize initial LSA refreshment interval
+ and limit the size of LSA-group to 10
+ to let randomization work more effectively.
+
+1999-10-31 Alex Zinin <zinin@amt.ru>
+ * ospf_interface.c
+ cancel t_network_lsa_self
+ when freeing int structure
+
+ * ospf_abr.c ospf_asbr.c ospf_flood.c ospf_lsa.c
+ ospf_lsa.h ospf_lsdb.h ospfd.c ospfd.h
+
+ Summary and ASE LSA refreshment functions
+ added---LSA refreshment is paced to 70 LSAs
+ per sec to avoid link overflow. Refreshment events
+ are further randomized within a 10 sec interval
+ to avoid syncing.
+
+ Also the sigfault of memcmp() in ospf_lsa_is_different()
+ is fixed.
+
+1999-10-30 Alex Zinin <zinin@amt.ru>
+ * ospf_nsm.c
+ Fix the bug where MAX_AGE LSAs
+ are included into the DB summary.
+
+ * ospf_interface.c
+ allocate 2*MTU input buffer instead of just MTU
+ for the cases when the other router mistakenly
+ sends larger packets thus causing fragmentation, etc.
+
+ * ospf_nsm.c
+ in nsm_reset_nbr() lists should be freed
+ not when they are empty.
+
+1999-10-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_zebra.c (ospf_acl_hook): Move OSPF_IS_ASBR and OSPF_IS_ABR
+ check inside of if (ospf_top).
+
+1999-10-29 Alex Zinin <zinin@amt.ru>
+ * ospf_lsa.c ospf_lsdb.c :
+ add assertion in lsa and lsa->data alloc functions,
+ as well as in lsdb_add for new->data
+
+ * ospf_lsdb.c: free hash table correctly
+
+1999-10-28 John Capo <jc@irbs.com>
+
+ * ospf_packet.h (OSPF_PACKET_MAX): Correct MAX packet length
+ calculation
+
+1999-10-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * OSPF-TRAP-MIB.txt: New file added. Edited version of RFC1850.
+
+ * OSPF-MIB.txt: New file added. Edited version of RFC1850.
+
+1999-10-27 Alex Zinin <zinin@amt.ru>
+ * ospfd, ospf_zebra, ospf_abr
+ "area import-list" command is added.
+ This command allows to filter the inter-area routes
+ injected into an area. Access list hook function
+ extended to invalidate area exp/imp lists.
+
+1999-10-25 Yoshinobu Inoue <shin@nd.net.fujitsu.co.jp>
+
+ * ospfd.c (ospf_interface_run): Enable to detect P2P network
+ on an OSPF interface.
+
+1999-10-19 Jordan Mendelson <jordy@wserv.com>
+
+ * ospf_lsdb.c (ospf_lsdb_add): Fix bug of crash
+ in ospf_ls_retransmit_lookup ().
+
+1999-10-19 Vladimir B. Grebenschikov <vova@express.ru>
+
+ * ospf_route.c: Workaround about installation of OSPF routes into
+ the zebra daemon. Add checking of existance routes. Free
+ ospf_top->old_table if it exists.
+
+1999-10-15 Jordan Mendelson <jordy@wserv.com>
+
+ * Add support for MD5 authentication.
+
+1999-10-12 Alex Zinin <zinin@amt.ru>
+ * ospfd.c, ospfd.h, ospf_abr.c:
+ a new command "area export-list" was added, it allows
+ the admin. to control which intra-area routes are
+ announced to other areas by the ABR
+
+1999-10-12 Alex Zinin <zinin@amt.ru>
+ * ospf_asbr.c (ospf_asbr_check_lsas): Fix bug of coredump
+ when "no redistribute" is used after a distribute list
+ denying some networks was used
+
+1999-10-05 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_route.c (ospf_path_dup): New function added.
+
+1999-10-05 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_interface.[ch]: Some of VL related funciton name changed.
+
+1999-09-27 Alex Zinin <zinin@amt.ru>
+
+ * ospf_zebra.c: Distribute-list functionality added
+
+1999-09-27 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.c (show_ip_ospf): Fix bug of segmentation fault when no ospf
+ instance exists.
+
+1999-09-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospfd.c (ospf_interface_down): Fix bug of misusing nextnode()
+ instead of node->next. Reported by Hiroki Ishibashi
+ <ishibasi@dcd.abk.nec.co.jp>.
+
+ * ospf_route.c (show_ip_ospf_route): Add check for ospf is enabled
+ or not.
+
+1999-09-23 Alex Zinin <zinin@amt.ru>
+
+ * stub area support added
+
+1999-09-23 Alex Zinin <zinin@amt.ru>
+
+ * fwd_addr in ASE-LSAs is now set correctly
+ * ASE routing changed to check the fwd_addr
+ and skip the route if the addr points to one
+ of our interfaces to avoid loops.
+
+1999-09-22 Alex Zinin <zinin@amt.ru>
+
+ * ospf_interface:
+ ospf_vls_in_area() added, it returns
+ the number of VLs configured through the area
+
+ * ospf_interface.c ospf_lsa.c ospf_lsdb.c ospfd.c
+ honor correct mem alloc
+
+1999-09-22 Alex Zinin <zinin@amt.ru>
+
+ * memory.[ch]:
+ Some OSPF mem types added,
+ plus more info in "show mem"
+
+1999-09-21 Alex Zinin <zinin@amt.ru>
+
+ * ospfd.c:
+ "area range substitute" added.
+ It can be used on NAT-enabled (IP-masquarade)
+ routers to announce private networks
+ from an area as public ones into the outside
+ world (not in the RFC, btw :)
+
+1999-09-21 Alex Zinin <zinin@amt.ru>
+
+ * ospfd.c:
+ "area range suppress" added.
+ This command allows to instruct the router
+ to be silent about specific ranges, i.e.,
+ it is a method of route filtering on area
+ borders
+
+1999-09-21 Alex Zinin <zinin@amt.ru>
+
+ * ospfd.c VLs removed when "no network area" executed
+
+1999-09-20 Alex Zinin <zinin@amt.ru>
+
+ * ospf_ase.c bug fix for not-zero fwd_addr
+ and directly connected routes.
+
+1999-09-20 Yon Uriarte <yon@plannet.de>
+
+ * ospf_packet.c (ospf_make_ls_req): Introduce delta value for
+ checking the length of OSPF packet exceeds MTU or not.
+
+ * ospf_lsa.c (ospf_lsa_different): Apply ntohs for checking
+ l1->data->length.
+
+1999-09-18 Alex Zinin <zinin@amt.ru>
+
+ * ospf_lsa.c bug fix for ospf_network_lsa() to
+ include itself into the RID list
+
+1999-09-10 Alex Zinin <zinin@amt.ru>
+
+ * Alternative ABR behaviors IBM/Cisco/Shortcut
+ implemented
+
+1999-09-10 Alex Zinin <zinin@amt.ru>
+
+ * router and network-LSA origination
+ changed to honor MinLSInterval
+
+1999-09-08 Alex Zinin <zinin@amt.ru>
+
+ * modified ABR behavior to honor VLs and transit
+ areas
+
+1999-09-07 Alex Zinin <zinin@amt.ru>
+
+ * completed VL functionality
+
+1999-09-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_asbr.c: New file.
+ ospf_asbr.h: New file.
+
+ * ospf_zebra.c (ospf_redistribute_connected): Add redistribute
+ related stuff.
+
+1999-09-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospfd.h (OSPF_FLAG_VIRTUAL_LINK): Change OSPF_FLAG_VEND to
+ OSPF_FLAG_VIRTUAL_LINK for comprehensiveness.
+
+1999-09-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_spf.c (ospf_spf_register): Change name from
+ ospf_spf_route_add() to ospf_spf_register().
+ Include "ospfd/ospf_abr.h" for ospf_abr_task() prototype.
+
+1999-09-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_lsa.c (ospf_external_lsa_install): Change to update
+ lsa->data rather than install new one, when same id lsa is already
+ installed.
+
+1999-09-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_lsa.c (ospf_router_lsa_install): Return lsa value.
+ (ospf_network_lsa_install): Likewise.
+ (ospf_summary_lsa_install): Likewise.
+ (ospf_summary_asbr_lsa_install): Likewise.
+ (ospf_external_lsa_install): Likewise.
+
+ * ospf_spf.c (ospf_spf_calculate): Comment out debug function
+ ospf_rtrs_print().
+
+1999-08-31 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_spf.c (ospf_rtrs_free): Add ospf_spf_calculate() for
+ freeing rtrs.
+
+1999-08-31 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (show_ip_ospf_database_summary),
+ (show_ip_ospf_database_summary_asbr),
+ (show_ip_ospf_database_external): New function added.
+ `show ip ospf database summary',
+ `show ip ospf database asbr-summary'
+ `show ip ospf database external' command can be used.
+
+ * ospf_lsa.c (ospf_lsa_count_table): New function added.
+ (show_ip_ospf_database_all): show nothing if a type of LSA
+ does not exist.
+
+1999-08-31 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_lsa.c (ospf_maxage_lsa_remover): Preserve next pointer when
+ the node is deleted.
+
+1999-08-31 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_flood.c (ospf_ls_retransmit_lookup): change to return
+ struct ospf_lsa *.
+ (ospf_ls_request_new), (ospf_ls_request_free),
+ (ospf_ls_request_add), (ospf_ls_request_delete),
+ (ospf_ls_request_delete_all), (ospf_ls_request_lookup):
+ New function added.
+
+ * ospf_packet.c (ospf_ls_upd_send_lsa): New function added.
+
+ * ospf_lsa.h (LS_AGE): Slightly change macro definition.
+
+ * ospf_lsa.c (ospf_lsa_more_recent), (ospf_lsa_diffrent):
+ Use LS_AGE macro.
+
+1999-08-30 Alex Zinin <zinin@amt.ru>
+
+ * ospfd.c
+ fix a bug with area range config write
+ added "show ip ospf" command, it will be enhanced later on
+
+1999-08-30 Alex Zinin <zinin@amt.ru>
+
+ * ospf_lsa.c
+ updated ospf_router_lsa() to honor flags (B-bit)
+
+1999-08-30 Alex Zinin <zinin@amt.ru>
+
+ * ospf_abr.c
+ wrote major functions implementing ABR activity
+
+1999-08-30 Alex Zinin <zinin@amt.ru>
+
+ * ospf_ia.c ospf_route.c ospf_route.h
+ fixed the bug with ospf_route.origin field.
+ Now it holds pointer to lsa_header
+
+1999-08-30 Alex Zinin <zinin@amt.ru>
+
+ * ospf_flood.c ospf_flood.h:
+ transformed ospf_flood_if_select into ospf_flood_through_area()
+ added new ospf_flood_if_select() and ospf_flood_through_as()
+
+1999-08-30 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_flood.[ch]: New file added.
+
+ * ospf_packet.c (ospf_lsa_flooding),
+ (ospf_lsa_flooding_select_if): functions move to ospf_flood.c
+
+ * ospf_neighbor.c (ospf_put_lsa_on_retransm_list),
+ (ospf_remove_lsa_from_retransm_list),
+ (ospf_nbr_remove_all_lsas_from_retransm_list),
+ (ospf_lsa_remove_from_ls_retransmit):
+ (ospf_lsa_retransmit): functions move to
+ ospf_flood.c, and change function's name:
+
+ ospf_put_lsa_on_retransm_list ()
+ -> ospf_ls_retransmit_add ()
+ ospf_remove_lsa_from_retransm_list ()
+ -> ospf_ls_retransmit_delete ()
+ ospf_nbr_remove_all_lsas_from_retransm_list ()
+ -> ospf_ls_retransmit_clear ()
+ ospf_lsa_remove_from_ls_retransmit ()
+ -> ospf_ls_retransmit_delete_nbr_all ()
+ ospf_lsa_retransmit ()
+ -> ospf_ls_retransmit_add_nbr_all ()
+
+ * ospf_lsa.c (ospf_lsa_lookup_from_list): function move to
+ ospf_flood.c, and change name to ospf_ls_retransmit_lookup ().
+
+1999-08-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_neighbor.c (ospf_nbr_lookup_by_addr): Use
+ route_node_lookup() instead of route_node_get().
+
+ * ospf_packet.c (ospf_ls_upd): Temporary comment out (6) check.
+
+1999-08-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_route.c (ospf_lookup_int_by_prefix): Add check of
+ oi->address.
+
+1999-08-29 Alex Zinin <zinin@amt.ru>
+ * ospf_lsa.c
+ MaxAge LSA deletion functions added.
+
+1999-08-29 Alex Zinin <zinin@amt.ru>
+ * ospf_neighbor.c
+ ospf_nbr_lookup_by_addr(): added route_unlock_node()
+ when function returns NULL if (rn->info == NULL)
+
+1999-08-29 Alex Zinin <zinin@amt.ru>
+ * ospfd.c
+ added a hack for area range deletion
+
+1999-08-29 Alex Zinin <zinin@amt.ru>
+ * ospf_lsa.h
+ included lsdb field into struct ospf_lsa, to find
+ LSDB easier when removing MaxAge LSAs.
+
+1999-08-29 Alex Zinin <zinin@amt.ru>
+ * ospf_lsa.c ospf_neighbor.c ospf_nsm.c
+ ospf_packet.c changed to honor new retransmit list
+ management functions
+
+1999-08-29 Alex Zinin <zinin@amt.ru>
+ * ospf_neighbor.c , .h added new retransmit list functions.
+
+1999-08-29 Alex Zinin <zinin@amt.ru>
+ * Makefile.in
+ added ospf_ase, ospf_abr, ospf_ia
+
+1999-08-29 Alex Zinin <zinin@amt.ru>
+ * ospf_spf.c:
+ - changed ospf_next_hop_calculation() to include interface
+ and nexthop addr for directly connected routers---more informative
+ and solves problem with route installation into the kernel
+ - changed ospf_nexthop_out_if_addr() to support routers, not only
+ transit networks
+ - added ospf_process_stubs();
+
+1999-08-29 Alex Zinin <zinin@amt.ru>
+ * ospf_lsa.c:
+ - changed ospf_router_lsa() to provide correct links
+ for p-t-p interfaces;
+ - changed ospf_summary_lsa_install() to support table
+ of self-originated summary-LSAs;
+ - added ospf_summary_asbr_lsa_install() and ospf_external_lsa_install()
+ - changed ospf_lsa_install() accordingly
+ - changed show_ip_ospf_database_router_links() to support p-t-p
+
+1999-08-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_packet.c (ospf_make_db_desc): Only master can clear more
+ flag.
+
+1999-08-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_packet.c (ospf_read): Add check of IP src address.
+
+1999-08-28 Alex Zinin <zinin@amt.ru>
+ * ospf_neighbor.h
+ added ospf_nbr_lookup_by_routerid()
+
+1999-08-28 Alex Zinin <zinin@amt.ru>
+ * ospfd.h
+ added ABR/ASBR flag definitions and fields;
+ added iflist field to area structure;
+ summary_lsa_self and summary_lsa_asbr_self are changed
+ to be route tables;
+ added ranges field---configured area ranges;
+ A separate Routers RT added;
+ area range config commands and config write added
+
+
+1999-08-28 Alex Zinin <zinin@amt.ru>
+ * ospf_route.c :
+ ospf_route_free()--added code to free the list of paths;
+ The following functions added:
+ ospf_intra_add_router();
+ ospf_intra_add_transit();
+ ospf_intra_add_stub();
+ the last function uses new ospf_int_lookup_by_prefix();
+ show_ip_ospf_route_cmd()--changed to support new RT structure;
+ added ospf_cmp_routes()--general route comparision function;
+ added ospf_route_copy_nexthops() and ospf_route_copy_nexthops_from_vertex()
+ they are used in ASE and IA routing;
+ added ospf_subst_route() and ospf_add_route();
+
+1999-08-28 Alex Zinin <zinin@amt.ru>
+ * ospf_route.h :
+ changed struct ospf_path to include output interface,
+ changed struct ospf_route to support IA and ASE routing.
+ added prototypes of the function used in IA and ASE modules.
+
+1999-08-28 Alex Zinin <zinin@amt.ru>
+ * ospf_lsa.h ospf_lsa.c :
+ added ospf_my_lsa(), an interface independent version of
+ ospf_lsa_is_self_originated(), it will be used in ASE and IA-routing.
+
+1999-08-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_interface.c (interface_config_write): Add check for
+ oi->nbr_self.
+
+1999-08-25 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (ospf_lsa_dup): New function added.
+
+ * ospf_packet.c (ospf_write), (ospf_read): Print send/recv
+ interface in debug message.
+
+1999-08-25 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_packet.c (ospf_ls_ack_send): The name is changed from
+ `ospf_ls_ack_send'.
+ (ospf_ls_ack_send_delayed) (ospf_ls_ack_timer): New function added.
+ Delayed Link State Acknowledgment is scheduled by timer.
+
+1999-08-25 Alex Zinin <zinin@amt.ru>
+
+ * ospf_lsa.c (ospf_router_lsa): Incorrectly included link to
+ a stub network instead of link to a transit network into
+ originated router-LSA, bug fixed.
+
+1999-08-24 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.c (ospf_update_router_id): New function added.
+
+ * ospf_network.c (ospf_write): Create new socket per transmission.
+ And select outgoing interface whether dst is unicast or multicast.
+
+ * ospf_packet.c: LSA flooding will work.
+
+1999-08-24 VOP <vop@unity.net>
+
+ * ospf_route.c: Include "sockunion.h"
+
+1999-08-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_network.c (ospf_serv_sock_init): Enclose
+ IPTOS_PREC_INTERNETCONTROL setting with #ifdef for OS which does
+ not have the definition.
+
+1999-08-23 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_packet.c: Fix bug of DD processing.
+
+1999-08-18 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (show_ip_ospf_database): Show actual `LS age'.
+
+1999-08-17 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.h (OSPF_MAX_LSA): The value of OSPF_MAX_LSA is
+ corrected. The bug of `mes_lookup' is fixed.
+ This had been reported by Poul-Henning Kamp <phk@freebsd.org>.
+
+ * ospf_lsa.c (ospf_router_lsa_install): The name is changed from
+ `ospf_add_router_lsa'.
+ (ospf_network_lsa_install): The name is changed from
+ `ospf_add_network_lsa'.
+
+ * ospf_interface.h (ospf_interface): Add member `nbr_self'.
+
+ * ospf_interface.c (ospf_if_is_enable): New function added.
+
+1999-08-16 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.h (struct lsa_header): The name is changed from
+ `struct ospf_lsa'.
+ (struct ospf_lsa): New struct added to control each LSA's aging
+ and timers.
+
+ * ospf_lsa.c (ospf_lsa_data_free): The name is change from
+ `ospf_lsa_free'.
+ (ospf_lsa_data_new), (ospf_lsa_new), (ospf_lsa_free),
+ (ospf_lsa_different), (ospf_lsa_install): New function added.
+
+ * ospf_packet.c (ospf_ls_upd_list_lsa): New function added.
+
+1999-08-12 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_nsm.c (nsm_reset_nbr): New function added.
+ KillNbr and LLDown neighbor event call this function.
+
+1999-08-10 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_packet.c (ospf_ls_retransmit)
+ (ospf_ls_upd_timer): New function added.
+ Set retransmission timer for Link State Update.
+
+1999-07-29 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_ism.c (ospf_dr_election): Fix bug of DR election.
+
+1999-07-28 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_network.c (ospf_serv_sock_init): Set IP precedence field
+ with IPTOS_PREC_INTERNET_CONTROL.
+
+ * ospf_nsm.c (nsm_change_status): Schedule NeighborChange event
+ if NSM status change.
+
+ * ospf_packet.c (ospf_make_hello): Never include a neighbor in
+ Hello packet, when the neighbor goes down.
+
+1999-07-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am (noinst_HEADERS): Add ospf_route.h.
+
+ * ospf_route.c (show_ip_ospf_route): Add `show ip ospf route'
+ command.
+
+1999-07-25 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (ospf_router_lsa): Fix bug of LS sequence number
+ assignement.
+
+1999-07-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_route.c (ospf_route_table_free): New function added.
+
+ * ospf_spf.c (ospf_spf_next): Free vertex w when cw's and w's
+ distance is same.
+
+ * ospfd.h (struct ospf): Add old_table.
+
+ * ospf_main.c (sighup): Call of log_rotate () removed.
+
+ * ospf_lsa.c (ospf_lsa_is_self_originated): Fix bug of checking
+ area->lsa as self LSA. This should be area->lsa_self.
+
+1999-07-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_zebra.c (ospf_zebra_add): ospf_zebra_add
+ (),ospf_zebra_delete () added.
+
+ * ospf_spf.c (ospf_spf_calculate): Call ospf_intra_route_add ().
+
+1999-07-24 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c: Change LS sequence number treatment.
+ (ospf_lsa_is_self_originated): New function added.
+ (show_ip_ospf_database_self_originated): New DEFUN added.
+
+1999-07-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_interface.c (ospf_if_lookup_by_addr): Add loopback check.
+
+1999-07-22 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_spf.c (ospf_nexthop_new), (ospf_nexthop_free),
+ (ospf_nexthop_dup): function added.
+ (ospf_nexthop_calculation): function changed.
+
+ * ospf_interface.c (ospf_if_lookup_by_addr): function added.
+
+1999-07-21 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_spf.c (ospf_spf_closest_vertex): function removed.
+
+1999-07-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_spf.c (ospf_spf_next): Apply ntohs for fetching metric.
+
+1999-07-21 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_neighbor.c (ospf_nbr_lookup_by_router_id): fundtion removed.
+
+ * ospf_lsa.c (show_ip_ospf_database_router): describe each
+ connected link.
+
+1999-07-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_spf.c (ospf_spf_next): V is router LSA or network LSA so
+ change behavior according to LSA type.
+ (ospf_lsa_has_link): Link check function is added.
+
+1999-07-20 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_spf.c (ospf_spf_calculate_schedule): Add new function for
+ SPF calcultion schedule addtition.
+ (ospf_spf_calculate_timer_add): Rough 30 sec interval SPF calc
+ timer is added.
+ (ospf_spf_next_router): Delete ospf_spf_next_network ().
+
+ * ospf_lsa.c (show_ip_ospf_database_all): Network-LSA display
+ header typo correction. Display of router LSA's #link added.
+
+1999-07-19 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_packet.c (ospf_check_network_mask): Added new function for
+ receiving Raw IP packet on an appropriate interface.
+
+1999-07-16 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.c (ospf_router_id): new DEFUN added.
+
+1999-07-15 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_spf.c (ospf_spf_init), (ospf_spf_free),
+ (ospf_spf_has_vertex), (ospf_vertex_lookup),
+ (ospf_spf_next_router), (ospf_spf_next_network),
+ (ospf_spf_closest_vertex), (ospf_spf_calculate):
+ function added.
+
+1999-07-13 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_ism.c: fix bug of DR Election.
+
+ * ospf_nsm.c: fix bug of adjacency forming.
+
+1999-07-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospfd.c (ospf_init): Change to use install_default.
+
+1999-07-01 Rick Payne <rickp@rossfell.co.uk>
+
+ * ospf_zebra.c (zebra_init): Install standard commands to
+ ZEBRA_NODE.
+
+1999-06-30 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_dump.c: Whole debug command is improved.
+ (ISM|NSM) (events|status|timers) debug option added.
+ (show_debugging_ospf): new DEFUN added.
+
+1999-06-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_lsa.c (ospf_lsa_lookup_from_list): Change !IPV4_ADDR_CMP to
+ IPV4_ADDR_SAME.
+
+1999-06-29 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_dump.c (ospf_summary_lsa_dump): Add summary-LSA dump routine.
+ (ospf_as_external_lsa_dump): Add AS-external-LSA dump routine.
+
+ * ospf_nsm.c (nsm_twoway_received): fix condtion of adjacnet.
+
+ * ospf_ism.c (ospf_dr_election): fix DR Election.
+
+ * ospf_dump.c (ospf_nbr_state_message): fix `show ip ospf neighbor'
+ command's state.
+
+1999-06-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_dump.c (ospf_router_lsa_dump): Add router-LSA dump routine.
+
+1999-06-28 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (show_ip_ospf_database_network): fix bug of
+ `show ip ospf database network' command output.
+
+ * ospf_nsm.c (nsm_inactivity_timer): Clear list of Link State
+ Retransmission, Database Summary and Link State Request.
+
+ * ospf_packet.c (ospf_ls_req_timer): New function added.
+ Set Link State Request retransmission timer.
+
+1999-06-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_main.c (main): Change default output from ZLOG_SYSLOG to
+ ZLOG_STDOUT.
+
+ * ospfd.c (ospf_init): Register show_ip_ospf_interface_cmd and
+ show_ip_ospf_neighbor_cmd to VIEW_NODE.
+
+ * ospf_lsa.c (ospf_lsa_init): Register show_ip_ospf_database_cmd
+ and show_ip_ospf_database_type_cmd to VIEW_NODE.
+
+1999-06-25 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_packet.c: fix bug of DD making.
+ fix bug of LS-Update reading.
+
+1999-06-23 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_packet.c: All type of packets are changed to use
+ fifo queue structure.
+ (ospf_fill_header) function added.
+
+1999-06-22 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_packet.c (ospf_packet_new): New function added to handle
+ sending ospf packet by fifo queue structure.
+ (ospf_packet_free), (ospf_fifo_new), (ospf_fifo_push),
+ (ospf_fifo_pop), (ospf_fifo_head), (ospf_fifo_flush),
+ (ospf_fifo_free): Likewise.
+
+1999-06-21 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_nsm.c (ospf_db_desc_timer): function added.
+ (nsm_timer_set) function added.
+ * ospf_dump.c (ospf_option_dump): function added.
+ * ospf_packet.c (ospf_ls_req) (ospf_make_ls_req): function added.
+
+1999-06-20 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c (ospf_lsa_more_recent): function added.
+ * ospf_neighbor.h (struct ospf_neighbor): Change member ms_flag
+ to dd_flags.
+
+1999-06-19 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c: DEFUN (show_ip_ospf_database) Added.
+ * ospf_interface.c (if_ospf_cost), (if_ospf_dead_interval),
+ (if_ospf_hello_interval), (if_ospf_priority),
+ (if_ospf_retransmit_interval), (if_ospf_transmit_delay)
+ argument changed from NUMBER to <range>.
+ DEFUN (if_ospf_network_broadcast),
+ DEFUN (if_ospf_network_non_broadcast),
+ DEFUN (if_ospf_network_point_to_multipoint),
+ DEFUN (if_ospf_network_point_to_point) functions are combined to
+ DEFUN (if_ospf_network).
+
+1999-06-18 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c: ospf_add_router_lsa (), ospf_add_network_lsa (),
+ ospf_lsa_lookup (), ospf_lsa_count () Added.
+
+1999-06-15 Toshiaki Takada <takada@zebra.org>
+
+ * DEFUN (ospf_debug_ism), DEFUN (ospf_debug_nsm),
+ DEFUN (no_ospf_debug_ism), DEFUN (no_ospf_debug_nsm) Added.
+ `debug ospf ism' command shows debug message.
+ `debuf ospf nsm' command shows debug message.
+
+1999-06-14 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c: ospf_network_lsa () Added.
+ ospf_lsa_checksum () Added.
+ * DEFUN (ospf_debug_packet), DEFUN (no_ospf_debug_packet) Added.
+ `debug ospf packet' command shows debug message.
+
+1999-06-13 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_packet.h: Remove struct ospf_ls_req {}, ospf_ls_upd {},
+ ospf_ls_ack {}.
+
+1999-06-11 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_dump.c: fix IP packet length treatment.
+
+1999-06-10 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_ism.h: Add OSPF_ISM_EVENT_EXECUTE() Macro Added.
+ * ospf_nsm.h: Add OSPF_NSM_EVENT_EXECUTE() Macro Added.
+
+ * ospf_packet.c: ospf_db_desc (), ospf_db_desc_send () Added.
+ ospf_make_hello (), ospf_make_db_desc () Added.
+ ospf_db_desc_proc () Added.n
+
+ * Database Description packet can be processed.
+
+1999-06-08 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.c: New file.
+
+1999-06-07 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_neighbor.c: ospf_fully_adjacent_count () Added.
+
+1999-06-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_spf.[ch]: New file.
+
+1999-05-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_zebra.c: Changed to use lib/zclient.c routines.
+
+ * ospf_zebra.h (zebra_start): Remove struct zebra.
+
+1999-05-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospfd.c (ospf_config_write): Add cast (unsigned long int) to
+ ntohl for sprintf warning.
+
+1999-05-19 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_ism.c (ospf_dr_election): Join AllDRouters Multicast group
+ if interface state changes to DR or BDR.
+
+1999-05-14 Stephen R. van den Berg <srb@cuci.nl>
+
+ * ospf_main.c (signal_init): SIGTERM call sigint.
+ (sigint): Logging more better message.
+
+1999-05-12 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.c: Fix bug of `no router ospf' statement, it will work.
+
+1999-05-11 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_neighbor.c: ospf_nbr_free () Added.
+
+1999-05-10 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.h: struct ospf_area { }, struct ospf_network { } Changed.
+ * Fix bug of `no network' statement, it will work.
+
+1999-05-07 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_interface.c, ospf_zebra.c: Fix bug of last interface is not
+ updated by ospf_if_update ().
+
+1999-04-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am (noinst_HEADERS): Add ospf_lsa.h for distribution.
+
+1999-04-25 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_interface.c: DEFUN (no_if_ospf_cost),
+ DEFUN (no_if_ospf_dead_interval),
+ DEFUN (no_if_ospf_hello_interval),
+ DEFUN (no_if_ospf_priority),
+ DEFUN (no_if_ospf_retransmit_interval),
+ DEFUN (no_if_ospf_transmit_delay) Added.
+
+ interface_config_write () suppress showing interface
+ default values.
+
+1999-04-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_dump.c (ospf_timer_dump): If thread is NULL return "inactive".
+
+ * ospfd.c (ospf_if_update): Fix bug of using ospf_area { } instead
+ of ospf_network { }. So `router ospf' statement in ospfd.conf
+ works again.
+ (ospf_if_update): Call ospf_get_router_id for updating router ID.
+
+1999-04-25 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_interface.c: DEFUN (if_ospf_network) deleted.
+ DEFUN (if_ospf_network_broadcast),
+ DEFUN (if_ospf_network_non_broadcast),
+ DEFUN (if_ospf_network_point_to_multipoint),
+ DEFUN (if_ospf_network_point_to_point),
+ DEFUN (no_if_ospf_network) Added.
+
+1999-04-23 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.h: struct area { } changed to struct ospf_network { }.
+ Add struct ospf_area { }.
+ * ospfd.c: Add ospf_area_lookup_by_area_id (), ospf_network_new (),
+ and ospf_network_free ().
+ DEFUN (area_authentication), DEFUN (no_area_authentication) Added.
+
+1999-04-22 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_lsa.h: New file.
+ * ospf_packet.h: LSA related struct definition are moved to
+ ospf_lsa.h.
+ * ospf_packet.c: ospf_verify_header () Added.
+
+1999-04-21 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_ism.c: ospf_elect_dr () and related function is changed.
+ DR Election bug fixed.
+ * ospf_dump.c: ospf_nbr_state_message (), ospf_timer_dump () Added.
+ * ospfd.c: DEFUN (show_ip_ospf_neighbor) Added.
+
+1999-04-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_main.c (main): access_list_init () is added for vty
+ connection filtering.
+
+1999-04-16 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.c: DEFUN (show_ip_ospf_interface) Added.
+ * ospf_neighbor.c: ospf_nbr_count () Added.
+
+1999-04-15 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.h: struct ospf { } Changed.
+ * ospfd.c: ospf_lookup_by_process_id () Deleted.
+ * ospf_ism.c: ospf_wait_timer () Added. WaitTimer will work.
+
+1999-04-14 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_ism.c: ospf_elect_dr () Added.
+ * ospf_network.c: ospf_if_ipmulticast () Added.
+
+1999-04-11 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_interface.c: interface_config_write (),
+ DEFUN (if_ip_ospf_cost),
+ DEFUN (if_ip_ospf_dead_interval),
+ DEFUN (if_ip_ospf_hello_interval),
+ DEFUN (if_ip_ospf_priority),
+ DEFUN (if_ip_ospf_retransmit_interval) and
+ DEFUN (if_ip_ospf_transmit_delay) Added.
+
+1999-04-08 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_dump.c: ospf_packet_db_desc_dump () Added.
+ * ospf_neighbor.c: ospf_nbr_bidirectional () Added.
+ * ospf_nsm.c: nsm_twoway_received () Added.
+
+1999-04-02 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_neighbor.c: New file.
+ * ospf_neighbor.h: New file.
+ * ospf_nsm.c: New file.
+ * ospf_nsm.h: New file.
+ * ospf_packet.c: Add ospf_make_header (), ospf_hello () and
+ ospf_hello_send (). Now OSPFd can receive Hello and send Hello.
+
+1999-03-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_packet.c: Add ospf_recv_packet (). Now OSPF Hello can receive.
+
+1999-03-19 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_packet.c: New file.
+ * ospf_packet.h: New file.
+ * ospf_network.c: New file.
+ * ospf_network.h: New file.
+ * ospfd.h: move OSPF message structure has moved to ospf_packet.h.
+
+1999-03-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf_zebra.c (ospf_zebra_get_interface): Fix for IPv6 interface
+ address.
+
+ * Makefile.am (install-sysconfDATA): Overwrite install-sysconfDATA
+ for install ospfd.conf.sample as owner read only file.
+
+ * ospf_main.c (usage): Change to use ZEBRA_BUG_ADDRESS.
+
+1999-03-15 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_ism.c: New file.
+ * ospf_ism.h: New file.
+ * ospf_dump.c: New file.
+ * ospf_dump.h: New file.
+
+ * ospfd.h: Add (struct ospf), (struct config_network),
+ (struct message) structure.
+
+ * ospf_interface.c: Add ospf_if_match_network ().
+ * ospf_interface.h (struct ospf_interface): Change struct members.
+
+ * ospfd.c: ospf_lookup_by_process_id (), ospf_network_new (),
+ DEFUN (network_area): Added.
+
+ * ospfd.conf.sample: Change sample configuration.
+
+1999-03-05 Toshiaki Takada <takada@zebra.org>
+
+ * ospf_interface.c: New file.
+ * ospf_interface.h: New file.
+ * ospf_zebra.h: New file.
+ * ospf_zebra.c: Add interface function for zebra daemon.
+ * ospfd.c: New file.
+
+1999-02-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Move IPv6 codes and files to ospf6d directory.
+
+1999-02-18 Peter Galbavy <Peter.Galbavy@knowledge.com>
+
+ * syslog support added
+
+1998-12-22 Toshiaki Takada <takada@zebra.org>
+
+ * ospfd.h: New file.
+ * ospf_lsa.h: New file.
+
+1998-12-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am: New file.
+ * ospf_main.c: New file.
+
diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am
new file mode 100644
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 <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "vty.h"
+#include "filter.h"
+#include "plist.h"
+#include "log.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ia.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_dump.h"
+
+
+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 <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "vty.h"
+#include "filter.h"
+#include "log.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_dump.h"
+
+/* 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 <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "hash.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "vty.h"
+#include "log.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_dump.h"
+
+#define DEBUG
+
+struct ospf_route *
+ospf_find_asbr_route (struct route_table *rtrs, struct prefix_ipv4 *asbr)
+{
+ struct route_node *rn;
+ struct ospf_route *or, *best = NULL;
+ listnode node;
+ list chosen;
+
+ /* Sanity check. */
+ if (rtrs == NULL)
+ return NULL;
+
+ rn = route_node_lookup (rtrs, (struct prefix *) asbr);
+ if (! rn)
+ return NULL;
+
+ route_unlock_node (rn);
+
+ chosen = list_new ();
+
+ /* First try to find intra-area non-bb paths. */
+ if (!CHECK_FLAG (ospf_top->config, OSPF_RFC1583_COMPATIBLE))
+ for (node = listhead ((list) rn->info); node; nextnode (node))
+ if ((or = getdata (node)) != NULL)
+ if (or->cost < OSPF_LS_INFINITY)
+ if (!OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id) &&
+ or->path_type == OSPF_PATH_INTRA_AREA)
+ listnode_add (chosen, or);
+
+ /* If none is found -- look through all. */
+ if (listcount (chosen) == 0)
+ {
+ list_free (chosen);
+ chosen = rn->info;
+ }
+
+ /* Now find the route with least cost. */
+ for (node = listhead (chosen); node; nextnode (node))
+ if ((or = getdata (node)) != NULL)
+ if (or->cost < OSPF_LS_INFINITY)
+ {
+ if (best == NULL)
+ best = or;
+ else if (best->cost > or->cost)
+ best = or;
+ else if (best->cost == or->cost &&
+ IPV4_ADDR_CMP (&best->u.std.area_id,
+ &or->u.std.area_id) < 0)
+ best = or;
+ }
+
+ if (chosen != rn->info)
+ list_delete (chosen);
+
+ return best;
+}
+
+struct ospf_route *
+ospf_find_asbr_route_through_area (struct route_table *rtrs,
+ struct prefix_ipv4 *asbr,
+ struct ospf_area *area)
+{
+ struct route_node *rn;
+
+ /* Sanity check. */
+ if (rtrs == NULL)
+ return NULL;
+
+ rn = route_node_lookup (rtrs, (struct prefix *) asbr);
+
+ if (rn)
+ {
+ listnode node;
+ struct ospf_route *or;
+
+ route_unlock_node (rn);
+
+ for (node = listhead ((list) rn->info); node; nextnode (node))
+ if ((or = getdata (node)) != NULL)
+ if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id))
+ return or;
+ }
+
+ return NULL;
+}
+
+void
+ospf_ase_complete_direct_routes (struct ospf_route *ro, struct in_addr nexthop)
+{
+ listnode node;
+ struct ospf_path *op;
+
+ for (node = listhead (ro->path); node; nextnode (node))
+ if ((op = getdata (node)) != NULL)
+ if (op->nexthop.s_addr == 0)
+ op->nexthop.s_addr = nexthop.s_addr;
+}
+
+int
+ospf_ase_forward_address_check (struct in_addr fwd_addr)
+{
+ listnode ifn;
+ struct ospf_interface *oi;
+
+ for (ifn = listhead (ospf_top->oiflist); ifn; nextnode (ifn))
+ if ((oi = getdata (ifn)) != NULL)
+ if (if_is_up (oi->ifp))
+ if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
+ if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &fwd_addr))
+ return 0;
+
+ return 1;
+}
+
+/* Calculate ASBR route. */
+struct ospf_route *
+ospf_ase_calculate_asbr_route (struct route_table *rt_network,
+ struct route_table *rt_router,
+ struct as_external_lsa *al)
+{
+ struct prefix_ipv4 asbr;
+ struct ospf_route *asbr_route;
+ struct route_node *rn;
+
+ /* Find ASBR route from Router routing table. */
+ asbr.family = AF_INET;
+ asbr.prefix = al->header.adv_router;
+ asbr.prefixlen = IPV4_MAX_BITLEN;
+ apply_mask_ipv4 (&asbr);
+
+ asbr_route = ospf_find_asbr_route (rt_router, &asbr);
+
+ if (asbr_route == NULL)
+ {
+ zlog_info ("ospf_ase_calculate(): Route to ASBR %s not found",
+ inet_ntoa (asbr.prefix));
+ return NULL;
+ }
+
+ if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL))
+ {
+ zlog_info ("ospf_ase_calculate(): Originating router is not an ASBR");
+ return NULL;
+ }
+
+ if (al->e[0].fwd_addr.s_addr != 0)
+ {
+ zlog_info ("ospf_ase_calculate(): "
+ "Forwarding address is not 0.0.0.0.");
+
+ if (! ospf_ase_forward_address_check (al->e[0].fwd_addr))
+ {
+ zlog_info ("ospf_ase_calculate(): "
+ "Forwarding address is one of our addresses, Ignore.");
+ return NULL;
+ }
+
+ zlog_info ("ospf_ase_calculate(): "
+ "Looking up in the Network Routing Table.");
+
+ /* Looking up the path to the fwd_addr from Network route. */
+ asbr.family = AF_INET;
+ asbr.prefix = al->e[0].fwd_addr;
+ asbr.prefixlen = IPV4_MAX_BITLEN;
+
+ rn = route_node_match (rt_network, (struct prefix *) &asbr);
+
+ if (rn == NULL)
+ {
+ zlog_info ("ospf_ase_calculate(): "
+ "Couldn't find a route to the forwarding address.");
+ return NULL;
+ }
+
+ route_unlock_node (rn);
+
+ if ((asbr_route = rn->info) == NULL)
+ {
+ zlog_info ("ospf_ase_calculate(): "
+ "Somehow OSPF route to ASBR is lost");
+ return NULL;
+ }
+ }
+
+ return asbr_route;
+}
+
+struct ospf_route *
+ospf_ase_calculate_new_route (struct ospf_lsa *lsa,
+ struct ospf_route *asbr_route, u_int32_t metric)
+{
+ struct as_external_lsa *al;
+ struct ospf_route *new;
+
+ al = (struct as_external_lsa *) lsa->data;
+
+ new = ospf_route_new ();
+
+ /* Set redistributed type -- does make sense? */
+ /* new->type = type; */
+ new->id = al->header.id;
+ new->mask = al->mask;
+
+ if (!IS_EXTERNAL_METRIC (al->e[0].tos))
+ {
+ zlog_info ("Route[External]: type-1 created.");
+ new->path_type = OSPF_PATH_TYPE1_EXTERNAL;
+ new->cost = asbr_route->cost + metric; /* X + Y */
+ }
+ else
+ {
+ zlog_info ("Route[External]: type-2 created.");
+ new->path_type = OSPF_PATH_TYPE2_EXTERNAL;
+ new->cost = asbr_route->cost; /* X */
+ new->u.ext.type2_cost = metric; /* Y */
+ }
+
+ new->type = OSPF_DESTINATION_NETWORK;
+ new->path = list_new ();
+ new->u.ext.origin = lsa;
+ new->u.ext.tag = ntohl (al->e[0].route_tag);
+ new->u.ext.asbr = asbr_route;
+
+ assert (new != asbr_route);
+
+ return new;
+}
+
+#define OSPF_ASE_CALC_INTERVAL 1
+
+int
+ospf_ase_calculate_route (struct ospf_lsa * lsa, void * p_arg, int n_arg)
+{
+ u_int32_t metric;
+ struct as_external_lsa *al;
+ struct ospf_route *asbr_route;
+ struct prefix_ipv4 asbr, p;
+ struct route_node *rn;
+ struct ospf_route *new, *or;
+ int ret;
+
+ assert (lsa);
+ al = (struct as_external_lsa *) lsa->data;
+
+#ifdef HAVE_NSSA
+ if (lsa->data->type == OSPF_AS_NSSA_LSA)
+ if (IS_DEBUG_OSPF_NSSA)
+ zlog_info ("ospf_ase_calc(): Processing Type-7");
+
+ /* Stay away from any Local Translated Type-7 LSAs */
+ if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
+ {
+ if (IS_DEBUG_OSPF_NSSA)
+ zlog_info ("ospf_ase_calc(): Rejecting Local Xlt'd");
+ return 0;
+ }
+#endif /* HAVE_NSSA */
+
+ zlog_info ("Route[External]: Calculate AS-external-LSA to %s/%d",
+ inet_ntoa (al->header.id), ip_masklen (al->mask));
+ /* (1) If the cost specified by the LSA is LSInfinity, or if the
+ LSA's LS age is equal to MaxAge, then examine the next LSA. */
+ if ((metric = GET_METRIC (al->e[0].metric)) >= OSPF_LS_INFINITY)
+ {
+ zlog_info ("Route[External]: Metric is OSPF_LS_INFINITY");
+ return 0;
+ }
+ if (IS_LSA_MAXAGE (lsa))
+ {
+ zlog_info ("Route[External]: AS-external-LSA is MAXAGE");
+ return 0;
+ }
+
+ /* (2) If the LSA was originated by the calculating router itself,
+ examine the next LSA. */
+ if (IS_LSA_SELF (lsa))
+ {
+ zlog_info ("Route[External]: AS-external-LSA is self originated");
+ return 0;
+ }
+
+ /* (3) Call the destination described by the LSA N. N's address is
+ obtained by masking the LSA's Link State ID with the
+ network/subnet mask contained in the body of the LSA. Look
+ up the routing table entries (potentially one per attached
+ area) for the AS boundary router (ASBR) that originated the
+ LSA. If no entries exist for router ASBR (i.e., ASBR is
+ unreachable), do nothing with this LSA and consider the next
+ in the list. */
+
+ asbr.family = AF_INET;
+ asbr.prefix = al->header.adv_router;
+ asbr.prefixlen = IPV4_MAX_BITLEN;
+ apply_mask_ipv4 (&asbr);
+
+ asbr_route = ospf_find_asbr_route (ospf_top->new_rtrs, &asbr);
+ if (asbr_route == NULL)
+ {
+ zlog_info ("Route[External]: Can't find originating ASBR route");
+ return 0;
+ }
+ if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL))
+ {
+ zlog_info ("Route[External]: Originating router is not an ASBR");
+ return 0;
+ }
+
+ /* Else, this LSA describes an AS external path to destination
+ N. Examine the forwarding address specified in the AS-
+ external-LSA. This indicates the IP address to which
+ packets for the destination should be forwarded. */
+
+ if (al->e[0].fwd_addr.s_addr == 0)
+ {
+ /* If the forwarding address is set to 0.0.0.0, packets should
+ be sent to the ASBR itself. Among the multiple routing table
+ entries for the ASBR, select the preferred entry as follows.
+ If RFC1583Compatibility is set to "disabled", prune the set
+ of routing table entries for the ASBR as described in
+ Section 16.4.1. In any case, among the remaining routing
+ table entries, select the routing table entry with the least
+ cost; when there are multiple least cost routing table
+ entries the entry whose associated area has the largest OSPF
+ Area ID (when considered as an unsigned 32-bit integer) is
+ chosen. */
+
+ /* asbr_route already contains the requested route */
+ }
+ else
+ {
+ /* If the forwarding address is non-zero, look up the
+ forwarding address in the routing table.[24] The matching
+ routing table entry must specify an intra-area or inter-area
+ path; if no such path exists, do nothing with the LSA and
+ consider the next in the list. */
+ if (! ospf_ase_forward_address_check (al->e[0].fwd_addr))
+ {
+ zlog_info ("Route[External]: Forwarding address is our router address");
+ return 0;
+ }
+
+ asbr.family = AF_INET;
+ asbr.prefix = al->e[0].fwd_addr;
+ asbr.prefixlen = IPV4_MAX_BITLEN;
+
+ rn = route_node_match (ospf_top->new_table, (struct prefix *) &asbr);
+
+ if (rn == NULL || (asbr_route = rn->info) == NULL)
+ {
+ zlog_info ("Route[External]: Can't find route to forwarding address");
+ if (rn)
+ route_unlock_node (rn);
+ return 0;
+ }
+
+ route_unlock_node (rn);
+ }
+
+ /* (4) Let X be the cost specified by the preferred routing table
+ entry for the ASBR/forwarding address, and Y the cost
+ specified in the LSA. X is in terms of the link state
+ metric, and Y is a type 1 or 2 external metric. */
+
+
+ /* (5) Look up the routing table entry for the destination N. If
+ no entry exists for N, install the AS external path to N,
+ with next hop equal to the list of next hops to the
+ forwarding address, and advertising router equal to ASBR.
+ If the external metric type is 1, then the path-type is set
+ to type 1 external and the cost is equal to X+Y. If the
+ external metric type is 2, the path-type is set to type 2
+ external, the link state component of the route's cost is X,
+ and the type 2 cost is Y. */
+ new = ospf_ase_calculate_new_route (lsa, asbr_route, metric);
+
+ /* (6) Compare the AS external path described by the LSA with the
+ existing paths in N's routing table entry, as follows. If
+ the new path is preferred, it replaces the present paths in
+ N's routing table entry. If the new path is of equal
+ preference, it is added to N's routing table entry's list of
+ paths. */
+
+ /* Set prefix. */
+ p.family = AF_INET;
+ p.prefix = al->header.id;
+ p.prefixlen = ip_masklen (al->mask);
+
+ /* if there is a Intra/Inter area route to the N
+ do not install external route */
+ if ((rn = route_node_lookup (ospf_top->new_table,
+ (struct prefix *) &p)) != NULL
+ && (rn->info != NULL))
+ {
+ if (new)
+ ospf_route_free (new);
+ return 0;
+ }
+
+ /* Find a route to the same dest */
+ /* If there is no route, create new one. */
+ if ((rn = route_node_lookup (ospf_top->new_external_route,
+ (struct prefix *) &p)) == NULL
+ || (or = rn->info) == NULL)
+ {
+ zlog_info ("Route[External]: Adding a new route %s/%d",
+ inet_ntoa (p.prefix), p.prefixlen);
+
+ ospf_route_add (ospf_top->new_external_route, &p, new, asbr_route);
+
+ if (al->e[0].fwd_addr.s_addr)
+ ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
+ return 0;
+ }
+ else
+ {
+ /* (a) Intra-area and inter-area paths are always preferred
+ over AS external paths.
+
+ (b) Type 1 external paths are always preferred over type 2
+ external paths. When all paths are type 2 external
+ paths, the paths with the smallest advertised type 2
+ metric are always preferred. */
+ ret = ospf_route_cmp (new, or);
+
+ /* (c) If the new AS external path is still indistinguishable
+ from the current paths in the N's routing table entry,
+ and RFC1583Compatibility is set to "disabled", select
+ the preferred paths based on the intra-AS paths to the
+ ASBR/forwarding addresses, as specified in Section
+ 16.4.1.
+
+ (d) If the new AS external path is still indistinguishable
+ from the current paths in the N's routing table entry,
+ select the preferred path based on a least cost
+ comparison. Type 1 external paths are compared by
+ looking at the sum of the distance to the forwarding
+ address and the advertised type 1 metric (X+Y). Type 2
+ external paths advertising equal type 2 metrics are
+ compared by looking at the distance to the forwarding
+ addresses.
+ */
+ /* New route is better */
+ if (ret < 0)
+ {
+ zlog_info ("Route[External]: New route is better");
+ ospf_route_subst (rn, new, asbr_route);
+ if (al->e[0].fwd_addr.s_addr)
+ ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
+ or = new;
+ new = NULL;
+ }
+ /* Old route is better */
+ else if (ret > 0)
+ {
+ zlog_info ("Route[External]: Old route is better");
+ /* do nothing */
+ }
+ /* Routes are equal */
+ else
+ {
+ zlog_info ("Route[External]: Routes are equal");
+ ospf_route_copy_nexthops (or, asbr_route->path);
+ if (al->e[0].fwd_addr.s_addr)
+ ospf_ase_complete_direct_routes (or, al->e[0].fwd_addr);
+ }
+ }
+ /* Make sure setting newly calculated ASBR route.*/
+ or->u.ext.asbr = asbr_route;
+ if (new)
+ ospf_route_free (new);
+
+ lsa->route = or;
+ return 0;
+}
+
+int
+ospf_ase_route_match_same (struct route_table *rt, struct prefix *prefix,
+ struct ospf_route *newor)
+{
+ struct route_node *rn;
+ struct ospf_route *or;
+ struct ospf_path *op;
+ struct ospf_path *newop;
+ listnode n1;
+ listnode n2;
+
+ if (! rt || ! prefix)
+ return 0;
+
+ rn = route_node_lookup (rt, prefix);
+ if (! rn)
+ return 0;
+
+ route_unlock_node (rn);
+
+ or = rn->info;
+ if (or->path_type != newor->path_type)
+ return 0;
+
+ switch (or->path_type)
+ {
+ case OSPF_PATH_TYPE1_EXTERNAL:
+ if (or->cost != newor->cost)
+ return 0;
+ break;
+ case OSPF_PATH_TYPE2_EXTERNAL:
+ if ((or->cost != newor->cost) ||
+ (or->u.ext.type2_cost != newor->u.ext.type2_cost))
+ return 0;
+ break;
+ default:
+ assert (0);
+ return 0;
+ }
+
+ if (or->path->count != newor->path->count)
+ return 0;
+
+ /* Check each path. */
+ for (n1 = listhead (or->path), n2 = listhead (newor->path);
+ n1 && n2; nextnode (n1), nextnode (n2))
+ {
+ op = getdata (n1);
+ newop = getdata (n2);
+
+ if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop))
+ return 0;
+ }
+ return 1;
+}
+
+int
+ospf_ase_compare_tables (struct route_table *new_external_route,
+ struct route_table *old_external_route)
+{
+ struct route_node *rn, *new_rn;
+ struct ospf_route *or;
+
+ /* Remove deleted routes */
+ for (rn = route_top (old_external_route); rn; rn = route_next (rn))
+ if ((or = rn->info))
+ {
+ if (! (new_rn = route_node_lookup (new_external_route, &rn->p)))
+ ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
+ else
+ route_unlock_node (new_rn);
+ }
+
+
+ /* Install new routes */
+ for (rn = route_top (new_external_route); rn; rn = route_next (rn))
+ if ((or = rn->info) != NULL)
+ if (! ospf_ase_route_match_same (old_external_route, &rn->p, or))
+ ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or);
+
+ return 0;
+}
+
+int
+ospf_ase_calculate_timer (struct thread *t)
+{
+ struct ospf *ospf;
+
+#ifdef HAVE_NSSA
+ listnode node;
+ struct ospf_area *area;
+#endif /* HAVE_NSSA */
+
+ ospf = THREAD_ARG (t);
+ ospf->t_ase_calc = NULL;
+
+ if (ospf->ase_calc)
+ {
+ ospf->ase_calc = 0;
+
+ /* Calculate external route for each AS-external-LSA */
+ foreach_lsa (EXTERNAL_LSDB (ospf_top), NULL, 0,
+ ospf_ase_calculate_route);
+
+#ifdef HAVE_NSSA
+ /* This version simple adds to the table all NSSA areas */
+ if (ospf_top->anyNSSA)
+ for (node = listhead (ospf_top->areas); node; nextnode (node))
+ {
+ area = getdata (node);
+ if (IS_DEBUG_OSPF_NSSA)
+ zlog_info ("ospf_ase_calculate_timer(): looking at area %s",
+ inet_ntoa (area->area_id));
+
+ if (area->external_routing == OSPF_AREA_NSSA)
+
+ foreach_lsa (NSSA_LSDB (area), NULL, 0,
+ ospf_ase_calculate_route);
+ }
+#endif /* HAVE_NSSA */
+
+ /* Compare old and new external routing table and install the
+ difference info zebra/kernel */
+ ospf_ase_compare_tables (ospf_top->new_external_route,
+ ospf_top->old_external_route);
+
+ /* Delete old external routing table */
+ ospf_route_table_free (ospf_top->old_external_route);
+ ospf_top->old_external_route = ospf_top->new_external_route;
+ ospf_top->new_external_route = route_table_init ();
+ }
+ return 0;
+}
+
+void
+ospf_ase_calculate_schedule ()
+{
+ if (! ospf_top)
+ return;
+
+ ospf_top->ase_calc = 1;
+}
+
+void
+ospf_ase_calculate_timer_add ()
+{
+ if (! ospf_top)
+ return;
+
+ if (! ospf_top->t_ase_calc)
+ ospf_top->t_ase_calc = thread_add_timer (master, ospf_ase_calculate_timer,
+ ospf_top, OSPF_ASE_CALC_INTERVAL);
+}
+
+void
+ospf_ase_register_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
+{
+ struct route_node *rn;
+ struct prefix_ipv4 p;
+ list lst;
+ struct as_external_lsa *al;
+
+ al = (struct as_external_lsa *) lsa->data;
+ p.family = AF_INET;
+ p.prefix = lsa->data->id;
+ p.prefixlen = ip_masklen (al->mask);
+ apply_mask_ipv4 (&p);
+
+ rn = route_node_get (top->external_lsas, (struct prefix *) &p);
+ if ((lst = rn->info) == NULL)
+ rn->info = lst = list_new();
+
+ /* We assume that if LSA is deleted from DB
+ is is also deleted from this RT */
+
+ listnode_add (lst, ospf_lsa_lock (lsa));
+}
+
+void
+ospf_ase_unregister_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
+{
+ struct route_node *rn;
+ struct prefix_ipv4 p;
+ list lst;
+ struct as_external_lsa *al;
+
+ al = (struct as_external_lsa *) lsa->data;
+ p.family = AF_INET;
+ p.prefix = lsa->data->id;
+ p.prefixlen = ip_masklen (al->mask);
+ apply_mask_ipv4 (&p);
+
+ rn = route_node_get (top->external_lsas, (struct prefix *) &p);
+ lst = rn->info;
+#ifdef ORIGINAL_CODING
+ assert (lst);
+
+ listnode_delete (lst, lsa);
+ ospf_lsa_unlock (lsa);
+#else /* ORIGINAL_CODING */
+ /* XXX lst can be NULL */
+ if (lst) {
+ listnode_delete (lst, lsa);
+ ospf_lsa_unlock (lsa);
+ }
+#endif /* ORIGINAL_CODING */
+}
+
+void
+ospf_ase_external_lsas_finish (struct route_table *rt)
+{
+ struct route_node *rn;
+ struct ospf_lsa *lsa;
+ list lst;
+ listnode node;
+
+ for (rn = route_top (rt); rn; rn = route_next (rn))
+ if ((lst = rn->info) != NULL)
+ {
+ for (node = listhead (lst); node; node = nextnode (node))
+ if ((lsa = getdata (node)) != NULL)
+ ospf_lsa_unlock (lsa);
+ list_delete (lst);
+ }
+
+ route_table_finish (rt);
+}
+
+void
+ospf_ase_incremental_update (struct ospf_lsa *lsa, struct ospf *top)
+{
+ list lsas;
+ listnode node;
+ struct route_node *rn, *rn2;
+ struct prefix_ipv4 p;
+ struct route_table *tmp_old;
+ struct as_external_lsa *al;
+
+ al = (struct as_external_lsa *) lsa->data;
+ p.family = AF_INET;
+ p.prefix = lsa->data->id;
+ p.prefixlen = ip_masklen (al->mask);
+ apply_mask_ipv4 (&p);
+
+ /* if new_table is NULL, there was no spf calculation, thus
+ incremental update is unneeded */
+ if (!top->new_table)
+ return;
+
+ /* If there is already an intra-area or inter-area route
+ to the destination, no recalculation is necessary
+ (internal routes take precedence). */
+
+ rn = route_node_lookup (top->new_table, (struct prefix *) &p);
+ if (rn && rn->info)
+ {
+ route_unlock_node (rn);
+ return;
+ }
+
+ rn = route_node_lookup (top->external_lsas, (struct prefix *) &p);
+ assert (rn && rn->info);
+ lsas = rn->info;
+
+ for (node = listhead (lsas); node; nextnode (node))
+ if ((lsa = getdata (node)) != NULL)
+ ospf_ase_calculate_route (lsa, NULL, 0);
+
+ /* prepare temporary old routing table for compare */
+ tmp_old = route_table_init ();
+ rn = route_node_lookup (top->old_external_route, (struct prefix *) &p);
+ if (rn && rn->info)
+ {
+ rn2 = route_node_get (tmp_old, (struct prefix *) &p);
+ rn2->info = rn->info;
+ }
+
+ /* install changes to zebra */
+ ospf_ase_compare_tables (top->new_external_route, tmp_old);
+
+ /* update top->old_external_route table */
+ if (rn && rn->info)
+ ospf_route_free ((struct ospf_route *) rn->info);
+
+ rn2 = route_node_lookup (top->new_external_route, (struct prefix *) &p);
+ /* if new route exists, install it to top->old_external_route */
+ if (rn2 && rn2->info)
+ {
+ if (!rn)
+ rn = route_node_get (top->old_external_route, (struct prefix *) &p);
+ rn->info = rn2->info;
+ }
+ else
+ {
+ /* remove route node from top->old_external_route */
+ if (rn)
+ {
+ rn->info = NULL;
+ route_unlock_node (rn);
+ route_unlock_node (rn);
+ }
+ }
+
+ if (rn2)
+ {
+ /* rn2->info is stored in route node of top->old_external_route */
+ rn2->info = NULL;
+ route_unlock_node (rn2);
+ route_unlock_node (rn2);
+ }
+
+ route_table_finish (tmp_old);
+}
diff --git a/ospfd/ospf_ase.h b/ospfd/ospf_ase.h
new file mode 100644
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 <zebra.h>
+
+#include "linklist.h"
+#include "thread.h"
+#include "prefix.h"
+#include "command.h"
+#include "stream.h"
+#include "log.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_network.h"
+
+struct message ospf_ism_state_msg[] =
+{
+ { ISM_DependUpon, "DependUpon" },
+ { ISM_Down, "Down" },
+ { ISM_Loopback, "Loopback" },
+ { ISM_Waiting, "Waiting" },
+ { ISM_PointToPoint, "Point-To-Point" },
+ { ISM_DROther, "DROther" },
+ { ISM_Backup, "Backup" },
+ { ISM_DR, "DR" },
+};
+int ospf_ism_state_msg_max = OSPF_ISM_STATE_MAX;
+
+struct message ospf_nsm_state_msg[] =
+{
+ { NSM_DependUpon, "DependUpon" },
+ { NSM_Down, "Down" },
+ { NSM_Attempt, "Attempt" },
+ { NSM_Init, "Init" },
+ { NSM_TwoWay, "2-Way" },
+ { NSM_ExStart, "ExStart" },
+ { NSM_Exchange, "Exchange" },
+ { NSM_Loading, "Loading" },
+ { NSM_Full, "Full" },
+};
+int ospf_nsm_state_msg_max = OSPF_NSM_STATE_MAX;
+
+struct message ospf_lsa_type_msg[] =
+{
+ { OSPF_UNKNOWN_LSA, "unknown" },
+ { OSPF_ROUTER_LSA, "router-LSA" },
+ { OSPF_NETWORK_LSA, "network-LSA" },
+ { OSPF_SUMMARY_LSA, "summary-LSA" },
+ { OSPF_ASBR_SUMMARY_LSA, "summary-LSA" },
+ { OSPF_AS_EXTERNAL_LSA, "AS-external-LSA" },
+ { OSPF_GROUP_MEMBER_LSA, "GROUP MEMBER LSA" },
+ { OSPF_AS_NSSA_LSA, "NSSA-LSA" },
+ { 8, "Type-8 LSA" },
+ { OSPF_OPAQUE_LINK_LSA, "Link-Local Opaque-LSA" },
+ { OSPF_OPAQUE_AREA_LSA, "Area-Local Opaque-LSA" },
+ { OSPF_OPAQUE_AS_LSA, "AS-external Opaque-LSA" },
+};
+int ospf_lsa_type_msg_max = OSPF_MAX_LSA;
+
+struct message ospf_link_state_id_type_msg[] =
+{
+ { OSPF_UNKNOWN_LSA, "(unknown)" },
+ { OSPF_ROUTER_LSA, "" },
+ { OSPF_NETWORK_LSA, "(address of Designated Router)" },
+ { OSPF_SUMMARY_LSA, "(summary Network Number)" },
+ { OSPF_ASBR_SUMMARY_LSA, "(AS Boundary Router address)" },
+ { OSPF_AS_EXTERNAL_LSA, "(External Network Number)" },
+ { OSPF_GROUP_MEMBER_LSA, "(Group membership information)" },
+ { OSPF_AS_NSSA_LSA, "(External Network Number for NSSA)" },
+ { 8, "(Type-8 LSID)" },
+ { OSPF_OPAQUE_LINK_LSA, "(Link-Local Opaque-Type/ID)" },
+ { OSPF_OPAQUE_AREA_LSA, "(Area-Local Opaque-Type/ID)" },
+ { OSPF_OPAQUE_AS_LSA, "(AS-external Opaque-Type/ID)" },
+};
+int ospf_link_state_id_type_msg_max = OSPF_MAX_LSA;
+
+struct message ospf_redistributed_proto[] =
+{
+ { ZEBRA_ROUTE_SYSTEM, "System" },
+ { ZEBRA_ROUTE_KERNEL, "Kernel" },
+ { ZEBRA_ROUTE_CONNECT, "Connected" },
+ { ZEBRA_ROUTE_STATIC, "Static" },
+ { ZEBRA_ROUTE_RIP, "RIP" },
+ { ZEBRA_ROUTE_RIPNG, "RIPng" },
+ { ZEBRA_ROUTE_OSPF, "OSPF" },
+ { ZEBRA_ROUTE_OSPF6, "OSPFv3" },
+ { ZEBRA_ROUTE_BGP, "BGP" },
+ { ZEBRA_ROUTE_MAX, "Default" },
+};
+int ospf_redistributed_proto_max = ZEBRA_ROUTE_MAX + 1;
+
+struct message ospf_network_type_msg[] =
+{
+ { OSPF_IFTYPE_NONE, "NONE" },
+ { OSPF_IFTYPE_POINTOPOINT, "Point-to-Point" },
+ { OSPF_IFTYPE_BROADCAST, "Broadcast" },
+ { OSPF_IFTYPE_NBMA, "NBMA" },
+ { OSPF_IFTYPE_POINTOMULTIPOINT, "Point-to-MultiPoint" },
+ { OSPF_IFTYPE_VIRTUALLINK, "Virtual-Link" },
+};
+int ospf_network_type_msg_max = OSPF_IFTYPE_MAX;
+
+/* Configuration debug option variables. */
+unsigned long conf_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
+unsigned long conf_debug_ospf_event = 0;
+unsigned long conf_debug_ospf_ism = 0;
+unsigned long conf_debug_ospf_nsm = 0;
+unsigned long conf_debug_ospf_lsa = 0;
+unsigned long conf_debug_ospf_zebra = 0;
+unsigned long conf_debug_ospf_nssa = 0;
+
+/* Enable debug option variables -- valid only session. */
+unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
+unsigned long term_debug_ospf_event = 0;
+unsigned long term_debug_ospf_ism = 0;
+unsigned long term_debug_ospf_nsm = 0;
+unsigned long term_debug_ospf_lsa = 0;
+unsigned long term_debug_ospf_zebra = 0;
+unsigned long term_debug_ospf_nssa = 0;
+
+
+#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 <zebra.h>
+
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "command.h"
+#include "table.h"
+#include "thread.h"
+#include "memory.h"
+#include "log.h"
+#include "zclient.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_dump.h"
+
+extern struct zclient *zclient;
+
+/* 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 <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "hash.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "table.h"
+#include "log.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospf_ia.h"
+#include "ospfd/ospf_dump.h"
+
+#define DEBUG
+
+struct ospf_route *
+ospf_find_abr_route (struct route_table *rtrs,
+ struct prefix_ipv4 *abr,
+ struct ospf_area *area)
+{
+ struct route_node *rn;
+ struct ospf_route *or;
+ listnode node;
+
+ if ((rn = route_node_lookup (rtrs, (struct prefix *) abr)) == NULL)
+ return NULL;
+
+ route_unlock_node (rn);
+
+ for (node = listhead ((list) rn->info); node; nextnode (node))
+ if ((or = getdata (node)) != NULL)
+ if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id) && (or->u.std.flags & ROUTER_LSA_BORDER))
+ return or;
+
+ return NULL;
+}
+
+void
+ospf_ia_network_route (struct route_table *rt, struct prefix_ipv4 *p,
+ struct ospf_route *new_or, struct ospf_route *abr_or)
+{
+ struct route_node *rn1;
+ struct ospf_route *or;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_ia_network_route(): processing summary route to %s/%d",
+ inet_ntoa (p->prefix), p->prefixlen);
+
+ /* Find a route to the same dest */
+ if ((rn1 = route_node_lookup (rt, (struct prefix *) p)))
+ {
+ int res;
+
+ route_unlock_node (rn1);
+
+ if ((or = rn1->info))
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_ia_network_route(): "
+ "Found a route to the same network");
+ /* Check the existing route. */
+ if ((res = ospf_route_cmp (new_or, or)) < 0)
+ {
+ /* New route is better, so replace old one. */
+ ospf_route_subst (rn1, new_or, abr_or);
+ }
+ else if (res == 0)
+ {
+ /* New and old route are equal, so next hops can be added. */
+ route_lock_node (rn1);
+ ospf_route_copy_nexthops (or, abr_or->path);
+ route_unlock_node (rn1);
+
+ /* new route can be deleted, because existing route has been updated. */
+ ospf_route_free (new_or);
+ }
+ else
+ {
+ /* New route is worse, so free it. */
+ ospf_route_free (new_or);
+ return;
+ }
+ } /* if (or)*/
+ } /*if (rn1)*/
+ else
+ { /* no route */
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_ia_network_route(): add new route to %s/%d",
+ inet_ntoa (p->prefix), p->prefixlen);
+ ospf_route_add (rt, p, new_or, abr_or);
+ }
+}
+
+void
+ospf_ia_router_route (struct route_table *rt, struct prefix_ipv4 *p,
+ struct ospf_route *new_or, struct ospf_route *abr_or)
+{
+ struct route_node *rn;
+ struct ospf_route *or = NULL;
+ int ret;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_ia_router_route(): considering %s/%d",
+ inet_ntoa (p->prefix), p->prefixlen);
+ /* Find a route to the same dest */
+ rn = route_node_get (rt,(struct prefix *) p);
+
+ if (rn->info == NULL)
+ /* This is a new route */
+ rn->info = list_new ();
+ else
+ {
+ struct ospf_area *or_area;
+ or_area = ospf_area_lookup_by_area_id (new_or->u.std.area_id);
+ assert (or_area);
+ /* This is an additional route */
+ route_unlock_node (rn);
+ or = ospf_find_asbr_route_through_area (rt, p, or_area);
+ }
+
+ if (or)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_ia_router_route(): "
+ "a route to the same ABR through the same area exists");
+ /* New route is better */
+ if ((ret = ospf_route_cmp (new_or, or)) < 0)
+ {
+ listnode_delete (rn->info, or);
+ ospf_route_free (or);
+ /* proceed down */
+ }
+ /* Routes are the same */
+ else if (ret == 0)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_ia_router_route(): merging the new route");
+
+ ospf_route_copy_nexthops (or, abr_or->path);
+ ospf_route_free (new_or);
+ return;
+ }
+ /* New route is worse */
+ else
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_ia_router_route(): skipping the new route");
+ ospf_route_free (new_or);
+ return;
+ }
+ }
+
+ ospf_route_copy_nexthops (new_or, abr_or->path);
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_ia_router_route(): adding the new route");
+
+ listnode_add (rn->info, new_or);
+}
+
+
+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 <zebra.h>
+
+#include "thread.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "memory.h"
+#include "command.h"
+#include "stream.h"
+#include "log.h"
+
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_network.h"
+#include "ospfd/ospf_dump.h"
+#ifdef HAVE_SNMP
+#include "ospfd/ospf_snmp.h"
+#endif /* HAVE_SNMP */
+
+
+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 <zebra.h>
+
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "memory.h"
+#include "stream.h"
+#include "log.h"
+#include "thread.h"
+#include "hash.h"
+#include "sockunion.h" /* for inet_aton() */
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_zebra.h"
+
+
+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 <zebra.h>
+
+#include "prefix.h"
+#include "table.h"
+#include "memory.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+
+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 <zebra.h>
+
+#include "version.h"
+#include "getopt.h"
+#include "thread.h"
+#include "prefix.h"
+#include "linklist.h"
+#include "if.h"
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+#include "filter.h"
+#include "plist.h"
+#include "stream.h"
+#include "log.h"
+#include "memory.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_vty.h"
+
+/* Configuration filename and directory. */
+char config_current[] = OSPF_DEFAULT_CONFIG;
+char config_default[] = SYSCONFDIR OSPF_DEFAULT_CONFIG;
+
+/* OSPFd options. */
+struct option longopts[] =
+{
+ { "daemon", no_argument, NULL, 'd'},
+ { "config_file", required_argument, NULL, 'f'},
+ { "pid_file", required_argument, NULL, 'i'},
+ { "log_mode", no_argument, NULL, 'l'},
+ { "help", no_argument, NULL, 'h'},
+ { "vty_addr", required_argument, NULL, 'A'},
+ { "vty_port", required_argument, NULL, 'P'},
+ { "version", no_argument, NULL, 'v'},
+ { 0 }
+};
+
+/* OSPFd program name */
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* Process ID saved for use by init system */
+char *pid_file = PATH_OSPFD_PID;
+
+/* Help information display. */
+static void
+usage (char *progname, int status)
+{
+ if (status != 0)
+ fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+ else
+ {
+ printf ("Usage : %s [OPTION...]\n\
+Daemon which manages OSPF.\n\n\
+-d, --daemon Runs in daemon mode\n\
+-f, --config_file Set configuration file name\n\
+-i, --pid_file Set process identifier file name\n\
+-A, --vty_addr Set vty's bind address\n\
+-P, --vty_port Set vty's port number\n\
+-v, --version Print program version\n\
+-h, --help Display this help and exit\n\
+\n\
+Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
+ }
+ exit (status);
+}
+
+/* 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 <zebra.h>
+
+#include "thread.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "sockunion.h"
+#include "log.h"
+#include "sockopt.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_network.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_packet.h"
+
+/* Join to the OSPF ALL SPF ROUTERS multicast group. */
+int
+ospf_if_add_allspfrouters (struct ospf *top, struct prefix *p,
+ unsigned int ifindex)
+{
+ int ret;
+
+ ret = setsockopt_multicast_ipv4 (top->fd, IP_ADD_MEMBERSHIP,
+ p->u.prefix4, htonl (OSPF_ALLSPFROUTERS),
+ ifindex);
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (AllSPFRouters): %s",
+ strerror (errno));
+ else
+ zlog_info ("interface %s join AllSPFRouters Multicast group.",
+ inet_ntoa (p->u.prefix4));
+
+ return ret;
+}
+
+int
+ospf_if_drop_allspfrouters (struct ospf *top, struct prefix *p,
+ unsigned int ifindex)
+{
+ int ret;
+
+ ret = setsockopt_multicast_ipv4 (top->fd, IP_DROP_MEMBERSHIP,
+ p->u.prefix4, htonl (OSPF_ALLSPFROUTERS),
+ ifindex);
+ if (ret < 0)
+ zlog_warn("can't setsockopt IP_DROP_MEMBERSHIP (AllSPFRouters): %s",
+ strerror (errno));
+ else
+ zlog_info ("interface %s leave AllSPFRouters Multicast group.",
+ inet_ntoa (p->u.prefix4));
+
+ return ret;
+}
+
+/* Join to the OSPF ALL Designated ROUTERS multicast group. */
+int
+ospf_if_add_alldrouters (struct ospf *top, struct prefix *p, unsigned int
+ ifindex)
+{
+ int ret;
+
+ ret = setsockopt_multicast_ipv4 (top->fd, IP_ADD_MEMBERSHIP,
+ p->u.prefix4, htonl (OSPF_ALLDROUTERS),
+ ifindex);
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (AllDRouters): %s",
+ strerror (errno));
+ else
+ zlog_info ("interface %s join AllDRouters Multicast group.",
+ inet_ntoa (p->u.prefix4));
+
+ return ret;
+}
+
+int
+ospf_if_drop_alldrouters (struct ospf *top, struct prefix *p, unsigned int
+ ifindex)
+{
+ int ret;
+
+ ret = setsockopt_multicast_ipv4 (top->fd, IP_DROP_MEMBERSHIP,
+ p->u.prefix4, htonl (OSPF_ALLDROUTERS),
+ ifindex);
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IP_DROP_MEMBERSHIP (AllDRouters): %s",
+ strerror (errno));
+ else
+ zlog_info ("interface %s leave AllDRouters Multicast group.",
+ inet_ntoa (p->u.prefix4));
+
+ return ret;
+}
+
+int
+ospf_if_ipmulticast (struct ospf *top, struct prefix *p, unsigned int ifindex)
+{
+ u_char val;
+ int ret, len;
+
+ val = 0;
+ len = sizeof (val);
+
+ /* Prevent receiving self-origined multicast packets. */
+ ret = setsockopt (top->fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&val, len);
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IP_MULTICAST_LOOP(0): %s", strerror (errno));
+
+ /* Explicitly set multicast ttl to 1 -- endo. */
+ val = 1;
+ ret = setsockopt (top->fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&val, len);
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IP_MULTICAST_TTL(1): %s", strerror (errno));
+
+ ret = setsockopt_multicast_ipv4 (top->fd, IP_MULTICAST_IF,
+ p->u.prefix4, 0, ifindex);
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IP_MULTICAST_IF: %s", strerror (errno));
+
+ return ret;
+}
+
+int
+ospf_sock_init (void)
+{
+ int ospf_sock;
+ int ret, tos, hincl = 1;
+
+ ospf_sock = socket (AF_INET, SOCK_RAW, IPPROTO_OSPFIGP);
+ if (ospf_sock < 0)
+ {
+ zlog_warn ("ospf_read_sock_init: socket: %s", strerror (errno));
+ return -1;
+ }
+
+ /* Set precedence field. */
+#ifdef IPTOS_PREC_INTERNETCONTROL
+ tos = IPTOS_PREC_INTERNETCONTROL;
+ ret = setsockopt (ospf_sock, IPPROTO_IP, IP_TOS,
+ (char *) &tos, sizeof (int));
+ if (ret < 0)
+ {
+ zlog_warn ("can't set sockopt IP_TOS %d to socket %d", tos, ospf_sock);
+ close (ospf_sock); /* Prevent sd leak. */
+ return ret;
+ }
+#endif /* IPTOS_PREC_INTERNETCONTROL */
+
+ /* we will include IP header with packet */
+ ret = setsockopt (ospf_sock, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof (hincl));
+ if (ret < 0)
+ zlog_warn ("Can't set IP_HDRINCL option");
+
+#if defined (IP_PKTINFO)
+ ret = setsockopt (ospf_sock, IPPROTO_IP, IP_PKTINFO, &hincl, sizeof (hincl));
+ if (ret < 0)
+ zlog_warn ("Can't set IP_PKTINFO option");
+#elif defined (IP_RECVIF)
+ ret = setsockopt (ospf_sock, IPPROTO_IP, IP_RECVIF, &hincl, sizeof (hincl));
+ if (ret < 0)
+ zlog_warn ("Can't set IP_RECVIF option");
+#else
+#warning "cannot be able to receive link information on this OS"
+#endif
+
+ return ospf_sock;
+}
diff --git a/ospfd/ospf_network.h b/ospfd/ospf_network.h
new file mode 100644
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 <zebra.h>
+#ifdef HAVE_OPAQUE_LSA
+
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "memory.h"
+#include "command.h"
+#include "vty.h"
+#include "stream.h"
+#include "log.h"
+#include "thread.h"
+#include "hash.h"
+#include "sockunion.h" /* for inet_aton() */
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_zebra.h"
+
+/*------------------------------------------------------------------------*
+ * Followings are initialize/terminate functions for Opaque-LSAs handling.
+ *------------------------------------------------------------------------*/
+
+#ifdef HAVE_OSPF_TE
+#include "ospfd/ospf_te.h"
+#endif /* HAVE_OSPF_TE */
+
+static void ospf_opaque_register_vty (void);
+static void ospf_opaque_funclist_init (void);
+static void ospf_opaque_funclist_term (void);
+static void free_opaque_info_per_type (void *val);
+static void free_opaque_info_per_id (void *val);
+static int ospf_opaque_lsa_install_hook (struct ospf_lsa *lsa);
+static int ospf_opaque_lsa_delete_hook (struct ospf_lsa *lsa);
+
+void
+ospf_opaque_init (void)
+{
+ ospf_opaque_register_vty ();
+ ospf_opaque_funclist_init ();
+
+#ifdef HAVE_OSPF_TE
+ if (ospf_mpls_te_init () != 0)
+ exit (1);
+#endif /* HAVE_OSPF_TE */
+
+ return;
+}
+
+void
+ospf_opaque_term (void)
+{
+#ifdef HAVE_OSPF_TE
+ ospf_mpls_te_term ();
+#endif /* HAVE_OSPF_TE */
+
+ ospf_opaque_funclist_term ();
+ return;
+}
+
+int
+ospf_opaque_type9_lsa_init (struct ospf_interface *oi)
+{
+ if (oi->opaque_lsa_self != NULL)
+ list_delete (oi->opaque_lsa_self);
+
+ oi->opaque_lsa_self = list_new ();
+ oi->opaque_lsa_self->del = free_opaque_info_per_type;
+ oi->t_opaque_lsa_self = NULL;
+ return 0;
+}
+
+void
+ospf_opaque_type9_lsa_term (struct ospf_interface *oi)
+{
+ OSPF_TIMER_OFF (oi->t_opaque_lsa_self);
+ if (oi->opaque_lsa_self != NULL)
+ list_delete (oi->opaque_lsa_self);
+ oi->opaque_lsa_self = NULL;
+ return;
+}
+
+int
+ospf_opaque_type10_lsa_init (struct ospf_area *area)
+{
+ if (area->opaque_lsa_self != NULL)
+ list_delete (area->opaque_lsa_self);
+
+ area->opaque_lsa_self = list_new ();
+ area->opaque_lsa_self->del = free_opaque_info_per_type;
+ area->t_opaque_lsa_self = NULL;
+
+#ifdef MONITOR_LSDB_CHANGE
+ area->lsdb->new_lsa_hook = ospf_opaque_lsa_install_hook;
+ area->lsdb->del_lsa_hook = ospf_opaque_lsa_delete_hook;
+#endif /* MONITOR_LSDB_CHANGE */
+ return 0;
+}
+
+void
+ospf_opaque_type10_lsa_term (struct ospf_area *area)
+{
+#ifdef MONITOR_LSDB_CHANGE
+ area->lsdb->new_lsa_hook =
+ area->lsdb->del_lsa_hook = NULL;
+#endif /* MONITOR_LSDB_CHANGE */
+
+ OSPF_TIMER_OFF (area->t_opaque_lsa_self);
+ if (area->opaque_lsa_self != NULL)
+ list_delete (area->opaque_lsa_self);
+ area->opaque_lsa_self = NULL;
+ return;
+}
+
+int
+ospf_opaque_type11_lsa_init (struct ospf *top)
+{
+ if (top->opaque_lsa_self != NULL)
+ list_delete (top->opaque_lsa_self);
+
+ top->opaque_lsa_self = list_new ();
+ top->opaque_lsa_self->del = free_opaque_info_per_type;
+ top->t_opaque_lsa_self = NULL;
+
+#ifdef MONITOR_LSDB_CHANGE
+ top->lsdb->new_lsa_hook = ospf_opaque_lsa_install_hook;
+ top->lsdb->del_lsa_hook = ospf_opaque_lsa_delete_hook;
+#endif /* MONITOR_LSDB_CHANGE */
+ return 0;
+}
+
+void
+ospf_opaque_type11_lsa_term (struct ospf *top)
+{
+#ifdef MONITOR_LSDB_CHANGE
+ top->lsdb->new_lsa_hook =
+ top->lsdb->del_lsa_hook = NULL;
+#endif /* MONITOR_LSDB_CHANGE */
+
+ OSPF_TIMER_OFF (top->t_opaque_lsa_self);
+ if (top->opaque_lsa_self != NULL)
+ list_delete (top->opaque_lsa_self);
+ top->opaque_lsa_self = NULL;
+ return;
+}
+
+static const char *
+ospf_opaque_type_name (u_char opaque_type)
+{
+ const char *name = "Unknown";
+
+ switch (opaque_type)
+ {
+ case OPAQUE_TYPE_WILDCARD: /* This is a special assignment! */
+ name = "Wildcard";
+ break;
+ case OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA:
+ name = "Traffic Engineering LSA";
+ break;
+ case OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC:
+ name = "Sycamore optical topology description";
+ break;
+ case OPAQUE_TYPE_GRACE_LSA:
+ name = "Grace-LSA";
+ break;
+ default:
+ if (OPAQUE_TYPE_RANGE_UNASSIGNED (opaque_type))
+ name = "Unassigned";
+ else if (OPAQUE_TYPE_RANGE_RESERVED (opaque_type))
+ name = "Private/Experimental";
+ break;
+ }
+ return name;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are management functions to store user specified callbacks.
+ *------------------------------------------------------------------------*/
+
+struct opaque_info_per_type; /* Forward declaration. */
+
+struct ospf_opaque_functab
+{
+ u_char opaque_type;
+ struct opaque_info_per_type *oipt;
+
+ int (* new_if_hook)(struct interface *ifp);
+ int (* del_if_hook)(struct interface *ifp);
+ void (* ism_change_hook)(struct ospf_interface *oi, int old_status);
+ void (* nsm_change_hook)(struct ospf_neighbor *nbr, int old_status);
+ void (* config_write_router)(struct vty *vty);
+ void (* config_write_if )(struct vty *vty, struct interface *ifp);
+ void (* config_write_debug )(struct vty *vty);
+ void (* show_opaque_info )(struct vty *vty, struct ospf_lsa *lsa);
+ int (* lsa_originator)(void *arg);
+ void (* lsa_refresher )(struct ospf_lsa *lsa);
+ int (* new_lsa_hook)(struct ospf_lsa *lsa);
+ int (* del_lsa_hook)(struct ospf_lsa *lsa);
+};
+
+static list ospf_opaque_type9_funclist;
+static list ospf_opaque_type10_funclist;
+static list ospf_opaque_type11_funclist;
+
+static void
+ospf_opaque_del_functab (void *val)
+{
+ XFREE (MTYPE_OSPF_OPAQUE_FUNCTAB, val);
+ return;
+}
+
+static void
+ospf_opaque_funclist_init (void)
+{
+ list funclist;
+
+ funclist = ospf_opaque_type9_funclist = list_new ();
+ funclist->del = ospf_opaque_del_functab;
+
+ funclist = ospf_opaque_type10_funclist = list_new ();
+ funclist->del = ospf_opaque_del_functab;
+
+ funclist = ospf_opaque_type11_funclist = list_new ();
+ funclist->del = ospf_opaque_del_functab;
+ return;
+}
+
+static void
+ospf_opaque_funclist_term (void)
+{
+ list funclist;
+
+ funclist = ospf_opaque_type9_funclist;
+ list_delete (funclist);
+
+ funclist = ospf_opaque_type10_funclist;
+ list_delete (funclist);
+
+ funclist = ospf_opaque_type11_funclist;
+ list_delete (funclist);
+ return;
+}
+
+static list
+ospf_get_opaque_funclist (u_char lsa_type)
+{
+ list funclist = NULL;
+
+ switch (lsa_type)
+ {
+ case OSPF_OPAQUE_LINK_LSA:
+ funclist = ospf_opaque_type9_funclist;
+ break;
+ case OSPF_OPAQUE_AREA_LSA:
+ funclist = ospf_opaque_type10_funclist;
+ break;
+ case OSPF_OPAQUE_AS_LSA:
+ funclist = ospf_opaque_type11_funclist;
+ break;
+ default:
+ zlog_warn ("ospf_get_opaque_funclist: Unexpected LSA-type(%u)", lsa_type);
+ break;
+ }
+ return funclist;
+}
+
+int
+ospf_register_opaque_functab (
+ u_char lsa_type,
+ u_char opaque_type,
+ int (* new_if_hook)(struct interface *ifp),
+ int (* del_if_hook)(struct interface *ifp),
+ void (* ism_change_hook)(struct ospf_interface *oi, int old_status),
+ void (* nsm_change_hook)(struct ospf_neighbor *nbr, int old_status),
+ void (* config_write_router)(struct vty *vty),
+ void (* config_write_if )(struct vty *vty, struct interface *ifp),
+ void (* config_write_debug )(struct vty *vty),
+ void (* show_opaque_info )(struct vty *vty, struct ospf_lsa *lsa),
+ int (* lsa_originator)(void *arg),
+ void (* lsa_refresher )(struct ospf_lsa *lsa),
+ int (* new_lsa_hook)(struct ospf_lsa *lsa),
+ int (* del_lsa_hook)(struct ospf_lsa *lsa))
+{
+ list funclist;
+ struct ospf_opaque_functab *new;
+ int rc = -1;
+
+ if ((funclist = ospf_get_opaque_funclist (lsa_type)) == NULL)
+ {
+ zlog_warn ("ospf_register_opaque_functab: Cannot get funclist for Type-%u LSAs?", lsa_type);
+ goto out;
+ }
+ else
+ {
+ listnode node;
+ struct ospf_opaque_functab *functab;
+
+ for (node = listhead (funclist); node; nextnode (node))
+ if ((functab = getdata (node)) != NULL)
+ if (functab->opaque_type == opaque_type)
+ {
+ zlog_warn ("ospf_register_opaque_functab: Duplicated entry?: lsa_type(%u), opaque_type(%u)", lsa_type, opaque_type);
+ goto out;
+ }
+ }
+
+ if ((new = XCALLOC (MTYPE_OSPF_OPAQUE_FUNCTAB,
+ sizeof (struct ospf_opaque_functab))) == NULL)
+ {
+ zlog_warn ("ospf_register_opaque_functab: XMALLOC: %s", strerror (errno));
+ goto out;
+ }
+
+ new->opaque_type = opaque_type;
+ new->oipt = NULL;
+ new->new_if_hook = new_if_hook;
+ new->del_if_hook = del_if_hook;
+ new->ism_change_hook = ism_change_hook;
+ new->nsm_change_hook = nsm_change_hook;
+ new->config_write_router = config_write_router;
+ new->config_write_if = config_write_if;
+ new->config_write_debug = config_write_debug;
+ new->show_opaque_info = show_opaque_info;
+ new->lsa_originator = lsa_originator;
+ new->lsa_refresher = lsa_refresher;
+ new->new_lsa_hook = new_lsa_hook;
+ new->del_lsa_hook = del_lsa_hook;
+
+ listnode_add (funclist, new);
+ rc = 0;
+
+out:
+ return rc;
+}
+
+void
+ospf_delete_opaque_functab (u_char lsa_type, u_char opaque_type)
+{
+ list funclist;
+ listnode node;
+ struct ospf_opaque_functab *functab;
+
+ if ((funclist = ospf_get_opaque_funclist (lsa_type)) != NULL)
+ for (node = listhead (funclist); node; nextnode (node))
+ {
+ if ((functab = getdata (node)) != NULL
+ && functab->opaque_type == opaque_type)
+ {
+ /* Cleanup internal control information, if it still remains. */
+ if (functab->oipt != NULL)
+ free_opaque_info_per_type (functab->oipt);
+
+ /* Dequeue listnode entry from the list. */
+ listnode_delete (funclist, functab);
+
+ /* Avoid misjudgement in the next lookup. */
+ if (listcount (funclist) == 0)
+ funclist->head = funclist->tail = NULL;
+
+ XFREE (MTYPE_OSPF_OPAQUE_FUNCTAB, functab);
+ goto out;
+ }
+ }
+out:
+ return;
+}
+
+static struct ospf_opaque_functab *
+ospf_opaque_functab_lookup (struct ospf_lsa *lsa)
+{
+ list funclist;
+ listnode node;
+ struct ospf_opaque_functab *functab;
+ u_char key = GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr));
+
+ if ((funclist = ospf_get_opaque_funclist (lsa->data->type)) != NULL)
+ for (node = listhead (funclist); node; nextnode (node))
+ if ((functab = getdata (node)) != NULL)
+ if (functab->opaque_type == key)
+ return functab;
+
+ return NULL;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are management functions for self-originated LSA entries.
+ *------------------------------------------------------------------------*/
+
+/*
+ * Opaque-LSA control information per opaque-type.
+ * Single Opaque-Type may have multiple instances; each of them will be
+ * identified by their opaque-id.
+ */
+struct opaque_info_per_type
+{
+ u_char opaque_type;
+
+ enum { PROC_NORMAL, PROC_SUSPEND } status;
+
+ /*
+ * Thread for (re-)origination scheduling for this opaque-type.
+ *
+ * Initial origination of Opaque-LSAs is controlled by generic
+ * Opaque-LSA handling module so that same opaque-type entries are
+ * called all at once when certain conditions are met.
+ * However, there might be cases that some Opaque-LSA clients need
+ * to (re-)originate their own Opaque-LSAs out-of-sync with others.
+ * This thread is prepared for that specific purpose.
+ */
+ struct thread *t_opaque_lsa_self;
+
+ /*
+ * Backpointer to an "owner" which is opaque-type dependent.
+ * type-9: struct ospf_interface
+ * type-10: struct ospf_area
+ * type-11: struct ospf
+ */
+ void *owner;
+
+ /* Collection of callback functions for this opaque-type. */
+ struct ospf_opaque_functab *functab;
+
+ /* List of Opaque-LSA control informations per opaque-id. */
+ list id_list;
+};
+
+/* Opaque-LSA control information per opaque-id. */
+struct opaque_info_per_id
+{
+ u_int32_t opaque_id;
+
+ /* Thread for refresh/flush scheduling for this opaque-type/id. */
+ struct thread *t_opaque_lsa_self;
+
+ /* Backpointer to Opaque-LSA control information per opaque-type. */
+ struct opaque_info_per_type *opqctl_type;
+
+ /* Here comes an actual Opaque-LSA entry for this opaque-type/id. */
+ struct ospf_lsa *lsa;
+};
+
+static struct opaque_info_per_type *register_opaque_info_per_type (struct ospf_opaque_functab *functab, struct ospf_lsa *new);
+static struct opaque_info_per_type *lookup_opaque_info_by_type (struct ospf_lsa *lsa);
+static struct opaque_info_per_id *register_opaque_info_per_id (struct opaque_info_per_type *oipt, struct ospf_lsa *new);
+static struct opaque_info_per_id *lookup_opaque_info_by_id (struct opaque_info_per_type *oipt, struct ospf_lsa *lsa);
+static struct opaque_info_per_id *register_opaque_lsa (struct ospf_lsa *new);
+
+
+static struct opaque_info_per_type *
+register_opaque_info_per_type (struct ospf_opaque_functab *functab,
+ struct ospf_lsa *new)
+{
+ struct ospf *top;
+ struct opaque_info_per_type *oipt;
+
+ if ((oipt = XCALLOC (MTYPE_OPAQUE_INFO_PER_TYPE,
+ sizeof (struct opaque_info_per_type))) == NULL)
+ {
+ zlog_warn ("register_opaque_info_per_type: XMALLOC: %s", strerror (errno));
+ goto out;
+ }
+
+ switch (new->data->type)
+ {
+ case OSPF_OPAQUE_LINK_LSA:
+ oipt->owner = new->oi;
+ listnode_add (new->oi->opaque_lsa_self, oipt);
+ break;
+ case OSPF_OPAQUE_AREA_LSA:
+ oipt->owner = new->area;
+ listnode_add (new->area->opaque_lsa_self, oipt);
+ break;
+ case OSPF_OPAQUE_AS_LSA:
+ top = ospf_top;
+ if (new->area != NULL && (top = new->area->top) == NULL)
+ {
+ free_opaque_info_per_type ((void *) oipt);
+ oipt = NULL;
+ goto out; /* This case may not exist. */
+ }
+ oipt->owner = top;
+ listnode_add (top->opaque_lsa_self, oipt);
+ break;
+ default:
+ free_opaque_info_per_type ((void *) oipt);
+ oipt = NULL;
+ goto out; /* This case may not exist. */
+ }
+
+ oipt->opaque_type = GET_OPAQUE_TYPE (ntohl (new->data->id.s_addr));
+ oipt->status = PROC_NORMAL;
+ oipt->t_opaque_lsa_self = NULL;
+ oipt->functab = functab;
+ functab->oipt = oipt;
+ oipt->id_list = list_new ();
+ oipt->id_list->del = free_opaque_info_per_id;
+
+out:
+ return oipt;
+}
+
+static void
+free_opaque_info_per_type (void *val)
+{
+ struct opaque_info_per_type *oipt = (struct opaque_info_per_type *) val;
+ struct opaque_info_per_id *oipi;
+ struct ospf_lsa *lsa;
+ listnode node;
+
+ /* Control information per opaque-id may still exist. */
+ for (node = listhead (oipt->id_list); node; nextnode (node))
+ {
+ if ((oipi = getdata (node)) == NULL)
+ continue;
+ if ((lsa = oipi->lsa) == NULL)
+ continue;
+ if (IS_LSA_MAXAGE (lsa))
+ continue;
+ ospf_opaque_lsa_flush_schedule (lsa);
+ }
+
+ OSPF_TIMER_OFF (oipt->t_opaque_lsa_self);
+ list_delete (oipt->id_list);
+ XFREE (MTYPE_OPAQUE_INFO_PER_TYPE, oipt);
+ return;
+}
+
+static struct opaque_info_per_type *
+lookup_opaque_info_by_type (struct ospf_lsa *lsa)
+{
+ struct ospf *top;
+ struct ospf_area *area;
+ struct ospf_interface *oi;
+ list listtop = NULL;
+ listnode node;
+ struct opaque_info_per_type *oipt = NULL;
+ u_char key = GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr));
+
+ switch (lsa->data->type)
+ {
+ case OSPF_OPAQUE_LINK_LSA:
+ if ((oi = lsa->oi) != NULL)
+ listtop = oi->opaque_lsa_self;
+ else
+ zlog_warn ("Type-9 Opaque-LSA: Reference to OI is missing?");
+ break;
+ case OSPF_OPAQUE_AREA_LSA:
+ if ((area = lsa->area) != NULL)
+ listtop = area->opaque_lsa_self;
+ else
+ zlog_warn ("Type-10 Opaque-LSA: Reference to AREA is missing?");
+ break;
+ case OSPF_OPAQUE_AS_LSA:
+ top = ospf_top;
+ if ((area = lsa->area) != NULL && (top = area->top) == NULL)
+ {
+ zlog_warn ("Type-11 Opaque-LSA: Reference to OSPF is missing?");
+ break; /* Unlikely to happen. */
+ }
+ listtop = top->opaque_lsa_self;
+ break;
+ default:
+ zlog_warn ("lookup_opaque_info_by_type: Unexpected LSA-type(%u)", lsa->data->type);
+ break;
+ }
+
+ if (listtop != NULL)
+ for (node = listhead (listtop); node; nextnode (node))
+ if ((oipt = getdata (node)) != NULL)
+ if (oipt->opaque_type == key)
+ return oipt;
+
+ return NULL;
+}
+
+static struct opaque_info_per_id *
+register_opaque_info_per_id (struct opaque_info_per_type *oipt,
+ struct ospf_lsa *new)
+{
+ struct opaque_info_per_id *oipi;
+
+ if ((oipi = XCALLOC (MTYPE_OPAQUE_INFO_PER_ID,
+ sizeof (struct opaque_info_per_id))) == NULL)
+ {
+ zlog_warn ("register_opaque_info_per_id: XMALLOC: %s", strerror (errno));
+ goto out;
+ }
+ oipi->opaque_id = GET_OPAQUE_ID (ntohl (new->data->id.s_addr));
+ oipi->t_opaque_lsa_self = NULL;
+ oipi->opqctl_type = oipt;
+ oipi->lsa = ospf_lsa_lock (new);
+
+ listnode_add (oipt->id_list, oipi);
+
+out:
+ return oipi;
+}
+
+static void
+free_opaque_info_per_id (void *val)
+{
+ struct opaque_info_per_id *oipi = (struct opaque_info_per_id *) val;
+
+ OSPF_TIMER_OFF (oipi->t_opaque_lsa_self);
+ if (oipi->lsa != NULL)
+ ospf_lsa_unlock (oipi->lsa);
+ XFREE (MTYPE_OPAQUE_INFO_PER_ID, oipi);
+ return;
+}
+
+static struct opaque_info_per_id *
+lookup_opaque_info_by_id (struct opaque_info_per_type *oipt,
+ struct ospf_lsa *lsa)
+{
+ listnode node;
+ struct opaque_info_per_id *oipi;
+ u_int32_t key = GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr));
+
+ for (node = listhead (oipt->id_list); node; nextnode (node))
+ if ((oipi = getdata (node)) != NULL)
+ if (oipi->opaque_id == key)
+ return oipi;
+
+ return NULL;
+}
+
+static struct opaque_info_per_id *
+register_opaque_lsa (struct ospf_lsa *new)
+{
+ struct ospf_opaque_functab *functab;
+ struct opaque_info_per_type *oipt;
+ struct opaque_info_per_id *oipi = NULL;
+
+ if ((functab = ospf_opaque_functab_lookup (new)) == NULL)
+ goto out;
+
+ if ((oipt = lookup_opaque_info_by_type (new)) == NULL
+ && (oipt = register_opaque_info_per_type (functab, new)) == NULL)
+ goto out;
+
+ if ((oipi = register_opaque_info_per_id (oipt, new)) == NULL)
+ goto out;
+
+out:
+ return oipi;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are (vty) configuration functions for Opaque-LSAs handling.
+ *------------------------------------------------------------------------*/
+
+DEFUN (capability_opaque,
+ capability_opaque_cmd,
+ "capability opaque",
+ "Enable specific OSPF feature\n"
+ "Opaque LSA\n")
+{
+ struct ospf *ospf = (struct ospf *) vty->index;
+
+ /* Turn on the "master switch" of opaque-lsa capability. */
+ if (!CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE))
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Opaque capability: OFF -> ON");
+
+ SET_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE);
+ ospf_renegotiate_optional_capabilities (ospf);
+ }
+ return CMD_SUCCESS;
+}
+
+ALIAS (capability_opaque,
+ ospf_opaque_capable_cmd,
+ "ospf opaque-lsa",
+ "OSPF specific commands\n"
+ "Enable the Opaque-LSA capability (rfc2370)\n")
+
+DEFUN (no_capability_opaque,
+ no_capability_opaque_cmd,
+ "no capability opaque",
+ NO_STR
+ "Enable specific OSPF feature\n"
+ "Opaque LSA\n")
+{
+ struct ospf *ospf = (struct ospf *) vty->index;
+
+ /* Turn off the "master switch" of opaque-lsa capability. */
+ if (CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE))
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Opaque capability: ON -> OFF");
+
+ UNSET_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE);
+ ospf_renegotiate_optional_capabilities (ospf);
+ }
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_capability_opaque,
+ no_ospf_opaque_capable_cmd,
+ "no ospf opaque-lsa",
+ NO_STR
+ "OSPF specific commands\n"
+ "Disable the Opaque-LSA capability (rfc2370)\n")
+
+static void
+ospf_opaque_register_vty (void)
+{
+ install_element (OSPF_NODE, &capability_opaque_cmd);
+ install_element (OSPF_NODE, &no_capability_opaque_cmd);
+ install_element (OSPF_NODE, &ospf_opaque_capable_cmd);
+ install_element (OSPF_NODE, &no_ospf_opaque_capable_cmd);
+ return;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are collection of user-registered function callers.
+ *------------------------------------------------------------------------*/
+
+static int
+opaque_lsa_new_if_callback (list funclist, struct interface *ifp)
+{
+ listnode node;
+ struct ospf_opaque_functab *functab;
+ int rc = -1;
+
+ for (node = listhead (funclist); node; nextnode (node))
+ if ((functab = getdata (node)) != NULL)
+ if (functab->new_if_hook != NULL)
+ if ((* functab->new_if_hook)(ifp) != 0)
+ goto out;
+ rc = 0;
+out:
+ return rc;
+}
+
+static int
+opaque_lsa_del_if_callback (list funclist, struct interface *ifp)
+{
+ listnode node;
+ struct ospf_opaque_functab *functab;
+ int rc = -1;
+
+ for (node = listhead (funclist); node; nextnode (node))
+ if ((functab = getdata (node)) != NULL)
+ if (functab->del_if_hook != NULL)
+ if ((* functab->del_if_hook)(ifp) != 0)
+ goto out;
+ rc = 0;
+out:
+ return rc;
+}
+
+static void
+opaque_lsa_ism_change_callback (list funclist,
+ struct ospf_interface *oi, int old_status)
+{
+ listnode node;
+ struct ospf_opaque_functab *functab;
+
+ for (node = listhead (funclist); node; nextnode (node))
+ if ((functab = getdata (node)) != NULL)
+ if (functab->ism_change_hook != NULL)
+ (* functab->ism_change_hook)(oi, old_status);
+ return;
+}
+
+static void
+opaque_lsa_nsm_change_callback (list funclist,
+ struct ospf_neighbor *nbr, int old_status)
+{
+ listnode node;
+ struct ospf_opaque_functab *functab;
+
+ for (node = listhead (funclist); node; nextnode (node))
+ if ((functab = getdata (node)) != NULL)
+ if (functab->nsm_change_hook != NULL)
+ (* functab->nsm_change_hook)(nbr, old_status);
+ return;
+}
+
+static void
+opaque_lsa_config_write_router_callback (list funclist, struct vty *vty)
+{
+ listnode node;
+ struct ospf_opaque_functab *functab;
+
+ for (node = listhead (funclist); node; nextnode (node))
+ if ((functab = getdata (node)) != NULL)
+ if (functab->config_write_router != NULL)
+ (* functab->config_write_router)(vty);
+ return;
+}
+
+static void
+opaque_lsa_config_write_if_callback (list funclist,
+ struct vty *vty, struct interface *ifp)
+{
+ listnode node;
+ struct ospf_opaque_functab *functab;
+
+ for (node = listhead (funclist); node; nextnode (node))
+ if ((functab = getdata (node)) != NULL)
+ if (functab->config_write_if != NULL)
+ (* functab->config_write_if)(vty, ifp);
+ return;
+}
+
+static void
+opaque_lsa_config_write_debug_callback (list funclist, struct vty *vty)
+{
+ listnode node;
+ struct ospf_opaque_functab *functab;
+
+ for (node = listhead (funclist); node; nextnode (node))
+ if ((functab = getdata (node)) != NULL)
+ if (functab->config_write_debug != NULL)
+ (* functab->config_write_debug)(vty);
+ return;
+}
+
+static int
+opaque_lsa_originate_callback (list funclist, void *lsa_type_dependent)
+{
+ listnode node;
+ struct ospf_opaque_functab *functab;
+ int rc = -1;
+
+ for (node = listhead (funclist); node; nextnode (node))
+ if ((functab = getdata (node)) != NULL)
+ if (functab->lsa_originator != NULL)
+ if ((* functab->lsa_originator)(lsa_type_dependent) != 0)
+ goto out;
+ rc = 0;
+out:
+ return rc;
+}
+
+static int
+new_lsa_callback (list funclist, struct ospf_lsa *lsa)
+{
+ listnode node;
+ struct ospf_opaque_functab *functab;
+ int rc = -1;
+
+ /* This function handles ALL types of LSAs, not only opaque ones. */
+ for (node = listhead (funclist); node; nextnode (node))
+ if ((functab = getdata (node)) != NULL)
+ if (functab->new_lsa_hook != NULL)
+ if ((* functab->new_lsa_hook)(lsa) != 0)
+ goto out;
+ rc = 0;
+out:
+ return rc;
+}
+
+static int
+del_lsa_callback (list funclist, struct ospf_lsa *lsa)
+{
+ listnode node;
+ struct ospf_opaque_functab *functab;
+ int rc = -1;
+
+ /* This function handles ALL types of LSAs, not only opaque ones. */
+ for (node = listhead (funclist); node; nextnode (node))
+ if ((functab = getdata (node)) != NULL)
+ if (functab->del_lsa_hook != NULL)
+ if ((* functab->del_lsa_hook)(lsa) != 0)
+ goto out;
+ rc = 0;
+out:
+ return rc;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are glue functions to call Opaque-LSA specific processing.
+ *------------------------------------------------------------------------*/
+
+int
+ospf_opaque_new_if (struct interface *ifp)
+{
+ list funclist;
+ int rc = -1;
+
+ funclist = ospf_opaque_type9_funclist;
+ if (opaque_lsa_new_if_callback (funclist, ifp) != 0)
+ goto out;
+
+ funclist = ospf_opaque_type10_funclist;
+ if (opaque_lsa_new_if_callback (funclist, ifp) != 0)
+ goto out;
+
+ funclist = ospf_opaque_type11_funclist;
+ if (opaque_lsa_new_if_callback (funclist, ifp) != 0)
+ goto out;
+
+ rc = 0;
+out:
+ return rc;
+}
+
+int
+ospf_opaque_del_if (struct interface *ifp)
+{
+ list funclist;
+ int rc = -1;
+
+ funclist = ospf_opaque_type9_funclist;
+ if (opaque_lsa_del_if_callback (funclist, ifp) != 0)
+ goto out;
+
+ funclist = ospf_opaque_type10_funclist;
+ if (opaque_lsa_del_if_callback (funclist, ifp) != 0)
+ goto out;
+
+ funclist = ospf_opaque_type11_funclist;
+ if (opaque_lsa_del_if_callback (funclist, ifp) != 0)
+ goto out;
+
+ rc = 0;
+out:
+ return rc;
+}
+
+void
+ospf_opaque_ism_change (struct ospf_interface *oi, int old_status)
+{
+ list funclist;
+
+ funclist = ospf_opaque_type9_funclist;
+ opaque_lsa_ism_change_callback (funclist, oi, old_status);
+
+ funclist = ospf_opaque_type10_funclist;
+ opaque_lsa_ism_change_callback (funclist, oi, old_status);
+
+ funclist = ospf_opaque_type11_funclist;
+ opaque_lsa_ism_change_callback (funclist, oi, old_status);
+
+ return;
+}
+
+void
+ospf_opaque_nsm_change (struct ospf_neighbor *nbr, int old_state)
+{
+ struct ospf *top;
+ list funclist;
+
+ if ((top = oi_to_top (nbr->oi)) == NULL)
+ goto out;
+
+ if (old_state != NSM_Full && nbr->state == NSM_Full)
+ {
+ if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
+ {
+ if (! CHECK_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT))
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Opaque-LSA: Now get operational!");
+
+ SET_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT);
+ }
+
+ ospf_opaque_lsa_originate_schedule (nbr->oi, NULL);
+ }
+ }
+ else
+ if (old_state == NSM_Full && nbr->state != NSM_Full)
+ {
+#ifdef NOTYET
+ /*
+ * If no more opaque-capable full-state neighbor remains in the
+ * flooding scope which corresponds to Opaque-LSA type, periodic
+ * LS flooding should be stopped.
+ */
+#endif /* NOTYET */
+ ;
+ }
+
+ funclist = ospf_opaque_type9_funclist;
+ opaque_lsa_nsm_change_callback (funclist, nbr, old_state);
+
+ funclist = ospf_opaque_type10_funclist;
+ opaque_lsa_nsm_change_callback (funclist, nbr, old_state);
+
+ funclist = ospf_opaque_type11_funclist;
+ opaque_lsa_nsm_change_callback (funclist, nbr, old_state);
+
+out:
+ return;
+}
+
+void
+ospf_opaque_config_write_router (struct vty *vty, struct ospf *ospf)
+{
+ list funclist;
+
+ if (CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE))
+ vty_out (vty, " capability opaque%s", VTY_NEWLINE);
+
+ funclist = ospf_opaque_type9_funclist;
+ opaque_lsa_config_write_router_callback (funclist, vty);
+
+ funclist = ospf_opaque_type10_funclist;
+ opaque_lsa_config_write_router_callback (funclist, vty);
+
+ funclist = ospf_opaque_type11_funclist;
+ opaque_lsa_config_write_router_callback (funclist, vty);
+
+ return;
+}
+
+void
+ospf_opaque_config_write_if (struct vty *vty, struct interface *ifp)
+{
+ list funclist;
+
+ funclist = ospf_opaque_type9_funclist;
+ opaque_lsa_config_write_if_callback (funclist, vty, ifp);
+
+ funclist = ospf_opaque_type10_funclist;
+ opaque_lsa_config_write_if_callback (funclist, vty, ifp);
+
+ funclist = ospf_opaque_type11_funclist;
+ opaque_lsa_config_write_if_callback (funclist, vty, ifp);
+
+ return;
+}
+
+void
+ospf_opaque_config_write_debug (struct vty *vty)
+{
+ list funclist;
+
+ funclist = ospf_opaque_type9_funclist;
+ opaque_lsa_config_write_debug_callback (funclist, vty);
+
+ funclist = ospf_opaque_type10_funclist;
+ opaque_lsa_config_write_debug_callback (funclist, vty);
+
+ funclist = ospf_opaque_type11_funclist;
+ opaque_lsa_config_write_debug_callback (funclist, vty);
+
+ return;
+}
+
+void
+show_opaque_info_detail (struct vty *vty, struct ospf_lsa *lsa)
+{
+ struct lsa_header *lsah = (struct lsa_header *) lsa->data;
+ u_int32_t lsid = ntohl (lsah->id.s_addr);
+ u_char opaque_type = GET_OPAQUE_TYPE (lsid);
+ u_int32_t opaque_id = GET_OPAQUE_ID (lsid);
+ struct ospf_opaque_functab *functab;
+
+ /* Switch output functionality by vty address. */
+ if (vty != NULL)
+ {
+ vty_out (vty, " Opaque-Type %u (%s)%s", opaque_type, ospf_opaque_type_name (opaque_type), VTY_NEWLINE);
+ vty_out (vty, " Opaque-ID 0x%x%s", opaque_id, VTY_NEWLINE);
+
+ vty_out (vty, " Opaque-Info: %u octets of data%s%s",
+ ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE,
+ VALID_OPAQUE_INFO_LEN(lsah) ? "" : "(Invalid length?)",
+ VTY_NEWLINE);
+ }
+ else
+ {
+ zlog_info (" Opaque-Type %u (%s)", opaque_type, ospf_opaque_type_name (opaque_type));
+ zlog_info (" Opaque-ID 0x%x", opaque_id);
+
+ zlog_info (" Opaque-Info: %u octets of data%s",
+ ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE,
+ VALID_OPAQUE_INFO_LEN(lsah) ? "" : "(Invalid length?)");
+ }
+
+ /* Call individual output functions. */
+ if ((functab = ospf_opaque_functab_lookup (lsa)) != NULL)
+ if (functab->show_opaque_info != NULL)
+ (* functab->show_opaque_info)(vty, lsa);
+
+ return;
+}
+
+void
+ospf_opaque_lsa_dump (struct stream *s, u_int16_t length)
+{
+ struct ospf_lsa lsa;
+
+ lsa.data = (struct lsa_header *) STREAM_PNT (s);
+ show_opaque_info_detail (NULL, &lsa);
+ return;
+}
+
+static int
+ospf_opaque_lsa_install_hook (struct ospf_lsa *lsa)
+{
+ list funclist;
+ int rc = -1;
+
+ /*
+ * Some Opaque-LSA user may want to monitor every LSA installation
+ * into the LSDB, regardless with target LSA type.
+ */
+ funclist = ospf_opaque_type9_funclist;
+ if (new_lsa_callback (funclist, lsa) != 0)
+ goto out;
+
+ funclist = ospf_opaque_type10_funclist;
+ if (new_lsa_callback (funclist, lsa) != 0)
+ goto out;
+
+ funclist = ospf_opaque_type11_funclist;
+ if (new_lsa_callback (funclist, lsa) != 0)
+ goto out;
+
+ rc = 0;
+out:
+ return rc;
+}
+
+static int
+ospf_opaque_lsa_delete_hook (struct ospf_lsa *lsa)
+{
+ list funclist;
+ int rc = -1;
+
+ /*
+ * Some Opaque-LSA user may want to monitor every LSA deletion
+ * from the LSDB, regardless with target LSA type.
+ */
+ funclist = ospf_opaque_type9_funclist;
+ if (del_lsa_callback (funclist, lsa) != 0)
+ goto out;
+
+ funclist = ospf_opaque_type10_funclist;
+ if (del_lsa_callback (funclist, lsa) != 0)
+ goto out;
+
+ funclist = ospf_opaque_type11_funclist;
+ if (del_lsa_callback (funclist, lsa) != 0)
+ goto out;
+
+ rc = 0;
+out:
+ return rc;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are Opaque-LSA origination/refresh management functions.
+ *------------------------------------------------------------------------*/
+
+static int ospf_opaque_type9_lsa_originate (struct thread *t);
+static int ospf_opaque_type10_lsa_originate (struct thread *t);
+static int ospf_opaque_type11_lsa_originate (struct thread *t);
+static void ospf_opaque_lsa_reoriginate_resume (list listtop, void *arg);
+
+void
+ospf_opaque_lsa_originate_schedule (struct ospf_interface *oi, int *delay0)
+{
+ struct ospf *top;
+ struct ospf_area *area;
+ listnode node;
+ struct opaque_info_per_type *oipt;
+ int delay = 0;
+
+ if ((top = oi_to_top (oi)) == NULL || (area = oi->area) == NULL)
+ {
+ zlog_warn ("ospf_opaque_lsa_originate_schedule: Invalid argument?");
+ goto out;
+ }
+
+ /* It may not a right time to schedule origination now. */
+ if (! CHECK_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT))
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_opaque_lsa_originate_schedule: Not operational.");
+ goto out; /* This is not an error. */
+ }
+ if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque))
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_opaque_lsa_originate_schedule: Under blockade.");
+ goto out; /* This is not an error, too. */
+ }
+
+ if (delay0 != NULL)
+ delay = *delay0;
+
+ /*
+ * There might be some entries that have been waiting for triggering
+ * of per opaque-type re-origination get resumed.
+ */
+ ospf_opaque_lsa_reoriginate_resume ( oi->opaque_lsa_self, (void *) oi);
+ ospf_opaque_lsa_reoriginate_resume (area->opaque_lsa_self, (void *) area);
+ ospf_opaque_lsa_reoriginate_resume ( top->opaque_lsa_self, (void *) top);
+
+ /*
+ * Now, schedule origination of all Opaque-LSAs per opaque-type.
+ */
+ if (! list_isempty (ospf_opaque_type9_funclist)
+ && list_isempty (oi->opaque_lsa_self)
+ && oi->t_opaque_lsa_self == NULL)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Schedule Type-9 Opaque-LSA origination in %d sec later.", delay);
+ oi->t_opaque_lsa_self =
+ thread_add_timer (master, ospf_opaque_type9_lsa_originate, oi, delay);
+ delay += OSPF_MIN_LS_INTERVAL;
+ }
+
+ if (! list_isempty (ospf_opaque_type10_funclist)
+ && list_isempty (area->opaque_lsa_self)
+ && area->t_opaque_lsa_self == NULL)
+ {
+ /*
+ * One AREA may contain multiple OIs, but above 2nd and 3rd
+ * conditions prevent from scheduling the originate function
+ * again and again.
+ */
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Schedule Type-10 Opaque-LSA origination in %d sec later.", delay);
+ area->t_opaque_lsa_self =
+ thread_add_timer (master, ospf_opaque_type10_lsa_originate,
+ area, delay);
+ delay += OSPF_MIN_LS_INTERVAL;
+ }
+
+ if (! list_isempty (ospf_opaque_type11_funclist)
+ && list_isempty (top->opaque_lsa_self)
+ && top->t_opaque_lsa_self == NULL)
+ {
+ /*
+ * One OSPF may contain multiple AREAs, but above 2nd and 3rd
+ * conditions prevent from scheduling the originate function
+ * again and again.
+ */
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Schedule Type-11 Opaque-LSA origination in %d sec later.", delay);
+ top->t_opaque_lsa_self =
+ thread_add_timer (master, ospf_opaque_type11_lsa_originate,
+ top, delay);
+ delay += OSPF_MIN_LS_INTERVAL;
+ }
+
+ /*
+ * Following section treats a special situation that this node's
+ * opaque capability has changed as "ON -> OFF -> ON".
+ */
+ if (! list_isempty (ospf_opaque_type9_funclist)
+ && ! list_isempty (oi->opaque_lsa_self))
+ {
+ for (node = listhead (oi->opaque_lsa_self); node; nextnode (node))
+ {
+ if ((oipt = getdata (node)) == NULL /* Something wrong? */
+ || oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */
+ || oipt->status == PROC_SUSPEND /* Cannot originate now. */
+ || ! list_isempty (oipt->id_list)) /* Handler is already active. */
+ continue;
+
+ ospf_opaque_lsa_reoriginate_schedule ((void *) oi,
+ OSPF_OPAQUE_LINK_LSA, oipt->opaque_type);
+ }
+ }
+
+ if (! list_isempty (ospf_opaque_type10_funclist)
+ && ! list_isempty (area->opaque_lsa_self))
+ {
+ for (node = listhead (area->opaque_lsa_self); node; nextnode (node))
+ {
+ if ((oipt = getdata (node)) == NULL /* Something wrong? */
+ || oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */
+ || oipt->status == PROC_SUSPEND /* Cannot originate now. */
+ || ! list_isempty (oipt->id_list)) /* Handler is already active. */
+ continue;
+
+ ospf_opaque_lsa_reoriginate_schedule ((void *) area,
+ OSPF_OPAQUE_AREA_LSA, oipt->opaque_type);
+ }
+ }
+
+ if (! list_isempty (ospf_opaque_type11_funclist)
+ && ! list_isempty (top->opaque_lsa_self))
+ {
+ for (node = listhead (top->opaque_lsa_self); node; nextnode (node))
+ {
+ if ((oipt = getdata (node)) == NULL /* Something wrong? */
+ || oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */
+ || oipt->status == PROC_SUSPEND /* Cannot originate now. */
+ || ! list_isempty (oipt->id_list)) /* Handler is already active. */
+ continue;
+
+ ospf_opaque_lsa_reoriginate_schedule ((void *) top,
+ OSPF_OPAQUE_AS_LSA, oipt->opaque_type);
+ }
+ }
+
+ if (delay0 != NULL)
+ *delay0 = delay;
+
+out:
+ return;
+}
+
+static int
+ospf_opaque_type9_lsa_originate (struct thread *t)
+{
+ struct ospf_interface *oi;
+ int rc;
+
+ oi = THREAD_ARG (t);
+ oi->t_opaque_lsa_self = NULL;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Timer[Type9-LSA]: Originate Opaque-LSAs for OI %s",
+ IF_NAME (oi));
+
+ rc = opaque_lsa_originate_callback (ospf_opaque_type9_funclist, oi);
+
+ return rc;
+}
+
+static int
+ospf_opaque_type10_lsa_originate (struct thread *t)
+{
+ struct ospf_area *area;
+ int rc;
+
+ area = THREAD_ARG (t);
+ area->t_opaque_lsa_self = NULL;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Timer[Type10-LSA]: Originate Opaque-LSAs for Area %s",
+ inet_ntoa (area->area_id));
+
+ rc = opaque_lsa_originate_callback (ospf_opaque_type10_funclist, area);
+
+ return rc;
+}
+
+static int
+ospf_opaque_type11_lsa_originate (struct thread *t)
+{
+ struct ospf *top;
+ int rc;
+
+ top = THREAD_ARG (t);
+ top->t_opaque_lsa_self = NULL;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Timer[Type11-LSA]: Originate AS-External Opaque-LSAs");
+
+ rc = opaque_lsa_originate_callback (ospf_opaque_type11_funclist, top);
+
+ return rc;
+}
+
+static void
+ospf_opaque_lsa_reoriginate_resume (list listtop, void *arg)
+{
+ listnode node;
+ struct opaque_info_per_type *oipt;
+ struct ospf_opaque_functab *functab;
+
+ if (listtop == NULL)
+ goto out;
+
+ /*
+ * Pickup oipt entries those which in SUSPEND status, and give
+ * them a chance to start re-origination now.
+ */
+ for (node = listhead (listtop); node; nextnode (node))
+ {
+ if ((oipt = getdata (node)) == NULL
+ || oipt->status != PROC_SUSPEND)
+ continue;
+
+ oipt->status = PROC_NORMAL;
+
+ if ((functab = oipt->functab) == NULL
+ || functab->lsa_originator == NULL)
+ continue;
+
+ if ((* functab->lsa_originator)(arg) != 0)
+ {
+ zlog_warn ("ospf_opaque_lsa_reoriginate_resume: Failed (opaque-type=%u)", oipt->opaque_type);
+ continue;
+ }
+ }
+
+out:
+ return;
+}
+
+struct ospf_lsa *
+ospf_opaque_lsa_install (struct ospf_lsa *lsa, int rt_recalc)
+{
+ struct ospf_lsa *new = NULL;
+ struct opaque_info_per_type *oipt;
+ struct opaque_info_per_id *oipi;
+ struct ospf *top;
+
+ /* Don't take "rt_recalc" into consideration for now. *//* XXX */
+
+ if (! IS_LSA_SELF (lsa))
+ {
+ new = lsa; /* Don't touch this LSA. */
+ goto out;
+ }
+
+ if (IS_DEBUG_OSPF (lsa, LSA_INSTALL))
+ zlog_info ("Install Type-%u Opaque-LSA: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)));
+
+ /* Replace the existing lsa with the new one. */
+ if ((oipt = lookup_opaque_info_by_type (lsa)) != NULL
+ && (oipi = lookup_opaque_info_by_id (oipt, lsa)) != NULL)
+ {
+ ospf_lsa_unlock (oipi->lsa);
+ oipi->lsa = ospf_lsa_lock (lsa);
+ }
+ /* Register the new lsa entry and get its control info. */
+ else
+ if ((oipi = register_opaque_lsa (lsa)) == NULL)
+ {
+ zlog_warn ("ospf_opaque_lsa_install: register_opaque_lsa() ?");
+ goto out;
+ }
+
+ /*
+ * Make use of a common mechanism (ospf_lsa_refresh_walker)
+ * for periodic refresh of self-originated Opaque-LSAs.
+ */
+ switch (lsa->data->type)
+ {
+ case OSPF_OPAQUE_LINK_LSA:
+ case OSPF_OPAQUE_AREA_LSA:
+ if (lsa->area == NULL || (top = lsa->area->top) == NULL)
+ {
+ /* Above conditions must have passed. */
+ zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?");
+ goto out;
+ }
+ break;
+ case OSPF_OPAQUE_AS_LSA:
+ top = ospf_top;
+ if (lsa->area != NULL && (top = lsa->area->top) == NULL)
+ {
+ /* Above conditions must have passed. */
+ zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?");
+ goto out;
+ }
+ break;
+ default:
+ zlog_warn ("ospf_opaque_lsa_install: Unexpected LSA-type(%u)", lsa->data->type);
+ goto out;
+ }
+
+ ospf_refresher_register_lsa (top, lsa);
+ new = lsa;
+
+out:
+ return new;
+}
+
+void
+ospf_opaque_lsa_refresh (struct ospf_lsa *lsa)
+{
+ struct ospf_opaque_functab *functab;
+
+ if ((functab = ospf_opaque_functab_lookup (lsa)) == NULL
+ || functab->lsa_refresher == NULL)
+ {
+ /*
+ * Though this LSA seems to have originated on this node, the
+ * handling module for this "lsa-type and opaque-type" was
+ * already deleted sometime ago.
+ * Anyway, this node still has a responsibility to flush this
+ * LSA from the routing domain.
+ */
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("LSA[Type%d:%s]: Flush stray Opaque-LSA", lsa->data->type, inet_ntoa (lsa->data->id));
+
+ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
+ ospf_lsa_maxage (lsa);
+ }
+ else
+ (* functab->lsa_refresher)(lsa);
+
+ return;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are re-origination/refresh/flush operations of Opaque-LSAs,
+ * triggered by external interventions (vty session, signaling, etc).
+ *------------------------------------------------------------------------*/
+
+#define OSPF_OPAQUE_TIMER_ON(T,F,L,V) \
+ if (!(T)) \
+ (T) = thread_add_timer (master, (F), (L), (V))
+
+static struct ospf_lsa *pseudo_lsa (struct ospf_interface *oi, struct ospf_area *area, u_char lsa_type, u_char opaque_type);
+static int ospf_opaque_type9_lsa_reoriginate_timer (struct thread *t);
+static int ospf_opaque_type10_lsa_reoriginate_timer (struct thread *t);
+static int ospf_opaque_type11_lsa_reoriginate_timer (struct thread *t);
+static int ospf_opaque_lsa_refresh_timer (struct thread *t);
+
+void
+ospf_opaque_lsa_reoriginate_schedule (void *lsa_type_dependent,
+ u_char lsa_type, u_char opaque_type)
+{
+ struct ospf *top;
+ struct ospf_area dummy, *area = NULL;
+ struct ospf_interface *oi = NULL;
+
+ struct ospf_lsa *lsa;
+ struct opaque_info_per_type *oipt;
+ int (* func)(struct thread *t) = NULL;
+ int delay;
+
+ switch (lsa_type)
+ {
+ case OSPF_OPAQUE_LINK_LSA:
+ if ((oi = (struct ospf_interface *) lsa_type_dependent) == NULL)
+ {
+ zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Type-9 Opaque-LSA: Invalid parameter?");
+ goto out;
+ }
+ if ((top = oi_to_top (oi)) == NULL)
+ {
+ zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: OI(%s) -> TOP?", IF_NAME (oi));
+ goto out;
+ }
+ if (! list_isempty (ospf_opaque_type9_funclist)
+ && list_isempty (oi->opaque_lsa_self)
+ && oi->t_opaque_lsa_self != NULL)
+ {
+ zlog_warn ("Type-9 Opaque-LSA (opaque_type=%u): Common origination for OI(%s) has already started", opaque_type, IF_NAME (oi));
+ goto out;
+ }
+ func = ospf_opaque_type9_lsa_reoriginate_timer;
+ break;
+ case OSPF_OPAQUE_AREA_LSA:
+ if ((area = (struct ospf_area *) lsa_type_dependent) == NULL)
+ {
+ zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Type-10 Opaque-LSA: Invalid parameter?");
+ goto out;
+ }
+ if ((top = area->top) == NULL)
+ {
+ zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: AREA(%s) -> TOP?", inet_ntoa (area->area_id));
+ goto out;
+ }
+ if (! list_isempty (ospf_opaque_type10_funclist)
+ && list_isempty (area->opaque_lsa_self)
+ && area->t_opaque_lsa_self != NULL)
+ {
+ zlog_warn ("Type-10 Opaque-LSA (opaque_type=%u): Common origination for AREA(%s) has already started", opaque_type, inet_ntoa (area->area_id));
+ goto out;
+ }
+ func = ospf_opaque_type10_lsa_reoriginate_timer;
+ break;
+ case OSPF_OPAQUE_AS_LSA:
+ if ((top = (struct ospf *) lsa_type_dependent) == NULL)
+ {
+ zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Type-11 Opaque-LSA: Invalid parameter?");
+ goto out;
+ }
+ if (! list_isempty (ospf_opaque_type11_funclist)
+ && list_isempty (top->opaque_lsa_self)
+ && top->t_opaque_lsa_self != NULL)
+ {
+ zlog_warn ("Type-11 Opaque-LSA (opaque_type=%u): Common origination has already started", opaque_type);
+ goto out;
+ }
+
+ /* Fake "area" to pass "ospf" to a lookup function later. */
+ dummy.top = top;
+ area = &dummy;
+
+ func = ospf_opaque_type11_lsa_reoriginate_timer;
+ break;
+ default:
+ zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Unexpected LSA-type(%u)", lsa_type);
+ goto out;
+ }
+
+ /* It may not a right time to schedule reorigination now. */
+ if (! CHECK_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT))
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_opaque_lsa_reoriginate_schedule: Not operational.");
+ goto out; /* This is not an error. */
+ }
+ if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque))
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_opaque_lsa_reoriginate_schedule: Under blockade.");
+ goto out; /* This is not an error, too. */
+ }
+
+ /* Generate a dummy lsa to be passed for a lookup function. */
+ lsa = pseudo_lsa (oi, area, lsa_type, opaque_type);
+
+ if ((oipt = lookup_opaque_info_by_type (lsa)) == NULL)
+ {
+ struct ospf_opaque_functab *functab;
+ if ((functab = ospf_opaque_functab_lookup (lsa)) == NULL)
+ {
+ zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: No associated function?: lsa_type(%u), opaque_type(%u)", lsa_type, opaque_type);
+ goto out;
+ }
+ if ((oipt = register_opaque_info_per_type (functab, lsa)) == NULL)
+ {
+ zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Cannot get a control info?: lsa_type(%u), opaque_type(%u)", lsa_type, opaque_type);
+ goto out;
+ }
+ }
+
+ if (oipt->t_opaque_lsa_self != NULL)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Type-%u Opaque-LSA has already scheduled to RE-ORIGINATE: [opaque-type=%u]", lsa_type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)));
+ goto out;
+ }
+
+ /*
+ * Different from initial origination time, in which various conditions
+ * (opaque capability, neighbor status etc) are assured by caller of
+ * the originating function "ospf_opaque_lsa_originate_schedule ()",
+ * it is highly possible that these conditions might not be satisfied
+ * at the time of re-origination function is to be called.
+ */
+ delay = OSPF_MIN_LS_INTERVAL; /* XXX */
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Schedule Type-%u Opaque-LSA to RE-ORIGINATE in %d sec later: [opaque-type=%u]", lsa_type, delay, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)));
+
+ OSPF_OPAQUE_TIMER_ON (oipt->t_opaque_lsa_self, func, oipt, delay);
+
+out:
+ return;
+}
+
+static struct ospf_lsa *
+pseudo_lsa (struct ospf_interface *oi, struct ospf_area *area,
+ u_char lsa_type, u_char opaque_type)
+{
+ static struct ospf_lsa lsa = { 0 };
+ static struct lsa_header lsah = { 0 };
+ u_int32_t tmp;
+
+ lsa.oi = oi;
+ lsa.area = area;
+ lsa.data = &lsah;
+
+ lsah.type = lsa_type;
+ tmp = SET_OPAQUE_LSID (opaque_type, 0); /* Opaque-ID is unused here. */
+ lsah.id.s_addr = htonl (tmp);
+
+ return &lsa;
+}
+
+static int
+ospf_opaque_type9_lsa_reoriginate_timer (struct thread *t)
+{
+ struct opaque_info_per_type *oipt;
+ struct ospf_opaque_functab *functab;
+ struct ospf *top;
+ struct ospf_interface *oi;
+ int rc = -1;
+
+ oipt = THREAD_ARG (t);
+ oipt->t_opaque_lsa_self = NULL;
+
+ if ((functab = oipt->functab) == NULL
+ || functab->lsa_originator == NULL)
+ {
+ zlog_warn ("ospf_opaque_type9_lsa_reoriginate_timer: No associated function?");
+ goto out;
+ }
+
+ oi = (struct ospf_interface *) oipt->owner;
+ if ((top = oi_to_top (oi)) == NULL)
+ {
+ zlog_warn ("ospf_opaque_type9_lsa_reoriginate_timer: Something wrong?");
+ goto out;
+ }
+
+ if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE)
+ || ! ospf_if_is_enable (oi)
+ || ospf_opaque_capable_nbr_count (oi->nbrs, NSM_Full) == 0)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Suspend re-origination of Type-9 Opaque-LSAs (opaque-type=%u) for a while...", oipt->opaque_type);
+
+ oipt->status = PROC_SUSPEND;
+ rc = 0;
+ goto out;
+ }
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Timer[Type9-LSA]: Re-originate Opaque-LSAs (opaque-type=%u) for OI (%s)", oipt->opaque_type, IF_NAME (oi));
+
+ rc = (* functab->lsa_originator)(oi);
+out:
+ return rc;
+}
+
+static int
+ospf_opaque_type10_lsa_reoriginate_timer (struct thread *t)
+{
+ struct opaque_info_per_type *oipt;
+ struct ospf_opaque_functab *functab;
+ listnode node;
+ struct ospf *top;
+ struct ospf_area *area;
+ struct ospf_interface *oi;
+ int n, rc = -1;
+
+ oipt = THREAD_ARG (t);
+ oipt->t_opaque_lsa_self = NULL;
+
+ if ((functab = oipt->functab) == NULL
+ || functab->lsa_originator == NULL)
+ {
+ zlog_warn ("ospf_opaque_type10_lsa_reoriginate_timer: No associated function?");
+ goto out;
+ }
+
+ area = (struct ospf_area *) oipt->owner;
+ if (area == NULL || (top = area->top) == NULL)
+ {
+ zlog_warn ("ospf_opaque_type10_lsa_reoriginate_timer: Something wrong?");
+ goto out;
+ }
+
+ /* There must be at least one "opaque-capable, full-state" neighbor. */
+ n = 0;
+ for (node = listhead (area->oiflist); node; nextnode (node))
+ {
+ if ((oi = getdata (node)) == NULL)
+ continue;
+ if ((n = ospf_opaque_capable_nbr_count (oi->nbrs, NSM_Full)) > 0)
+ break;
+ }
+
+ if (n == 0 || ! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE))
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Suspend re-origination of Type-10 Opaque-LSAs (opaque-type=%u) for a while...", oipt->opaque_type);
+
+ oipt->status = PROC_SUSPEND;
+ rc = 0;
+ goto out;
+ }
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Timer[Type10-LSA]: Re-originate Opaque-LSAs (opaque-type=%u) for Area %s", oipt->opaque_type, inet_ntoa (area->area_id));
+
+ rc = (* functab->lsa_originator)(area);
+out:
+ return rc;
+}
+
+static int
+ospf_opaque_type11_lsa_reoriginate_timer (struct thread *t)
+{
+ struct opaque_info_per_type *oipt;
+ struct ospf_opaque_functab *functab;
+ struct ospf *top;
+ int rc = -1;
+
+ oipt = THREAD_ARG (t);
+ oipt->t_opaque_lsa_self = NULL;
+
+ if ((functab = oipt->functab) == NULL
+ || functab->lsa_originator == NULL)
+ {
+ zlog_warn ("ospf_opaque_type11_lsa_reoriginate_timer: No associated function?");
+ goto out;
+ }
+
+ if ((top = (struct ospf *) oipt->owner) == NULL)
+ {
+ zlog_warn ("ospf_opaque_type11_lsa_reoriginate_timer: Something wrong?");
+ goto out;
+ }
+
+ if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE))
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Suspend re-origination of Type-11 Opaque-LSAs (opaque-type=%u) for a while...", oipt->opaque_type);
+
+ oipt->status = PROC_SUSPEND;
+ rc = 0;
+ goto out;
+ }
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Timer[Type11-LSA]: Re-originate Opaque-LSAs (opaque-type=%u).", oipt->opaque_type);
+
+ rc = (* functab->lsa_originator)(top);
+out:
+ return rc;
+}
+
+extern int ospf_lsa_refresh_delay (struct ospf_lsa *); /* ospf_lsa.c */
+
+void
+ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa0)
+{
+ struct opaque_info_per_type *oipt;
+ struct opaque_info_per_id *oipi;
+ struct ospf_lsa *lsa;
+ int delay;
+
+ if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL
+ || (oipi = lookup_opaque_info_by_id (oipt, lsa0)) == NULL)
+ {
+ zlog_warn ("ospf_opaque_lsa_refresh_schedule: Invalid parameter?");
+ goto out;
+ }
+
+ /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */
+ if ((lsa = oipi->lsa) == NULL)
+ {
+ zlog_warn ("ospf_opaque_lsa_refresh_schedule: Something wrong?");
+ goto out;
+ }
+
+ if (oipi->t_opaque_lsa_self != NULL)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Type-%u Opaque-LSA has already scheduled to REFRESH: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)));
+ goto out;
+ }
+
+ /* Delete this lsa from neighbor retransmit-list. */
+ switch (lsa->data->type)
+ {
+ case OSPF_OPAQUE_LINK_LSA:
+ case OSPF_OPAQUE_AREA_LSA:
+ ospf_ls_retransmit_delete_nbr_all (lsa->area, lsa);
+ break;
+ case OSPF_OPAQUE_AS_LSA:
+ ospf_ls_retransmit_delete_nbr_all (NULL, lsa);
+ break;
+ default:
+ zlog_warn ("ospf_opaque_lsa_refresh_schedule: Unexpected LSA-type(%u)", lsa->data->type);
+ goto out;
+ }
+
+ delay = ospf_lsa_refresh_delay (lsa);
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Schedule Type-%u Opaque-LSA to REFRESH in %d sec later: [opaque-type=%u, opaque-id=%x]", lsa->data->type, delay, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)));
+
+ OSPF_OPAQUE_TIMER_ON (oipi->t_opaque_lsa_self,
+ ospf_opaque_lsa_refresh_timer, oipi, delay);
+out:
+ return;
+}
+
+static int
+ospf_opaque_lsa_refresh_timer (struct thread *t)
+{
+ struct opaque_info_per_id *oipi;
+ struct ospf_opaque_functab *functab;
+ struct ospf_lsa *lsa;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Timer[Opaque-LSA]: (Opaque-LSA Refresh expire)");
+
+ oipi = THREAD_ARG (t);
+ oipi->t_opaque_lsa_self = NULL;
+
+ if ((lsa = oipi->lsa) != NULL)
+ if ((functab = oipi->opqctl_type->functab) != NULL)
+ if (functab->lsa_refresher != NULL)
+ (* functab->lsa_refresher)(lsa);
+
+ return 0;
+}
+
+void
+ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa0)
+{
+ struct opaque_info_per_type *oipt;
+ struct opaque_info_per_id *oipi;
+ struct ospf_lsa *lsa;
+
+ if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL
+ || (oipi = lookup_opaque_info_by_id (oipt, lsa0)) == NULL)
+ {
+ zlog_warn ("ospf_opaque_lsa_flush_schedule: Invalid parameter?");
+ goto out;
+ }
+
+ /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */
+ if ((lsa = oipi->lsa) == NULL)
+ {
+ zlog_warn ("ospf_opaque_lsa_flush_schedule: Something wrong?");
+ goto out;
+ }
+
+ /* Delete this lsa from neighbor retransmit-list. */
+ switch (lsa->data->type)
+ {
+ case OSPF_OPAQUE_LINK_LSA:
+ case OSPF_OPAQUE_AREA_LSA:
+ ospf_ls_retransmit_delete_nbr_all (lsa->area, lsa);
+ break;
+ case OSPF_OPAQUE_AS_LSA:
+ ospf_ls_retransmit_delete_nbr_all (NULL, lsa);
+ break;
+ default:
+ zlog_warn ("ospf_opaque_lsa_flush_schedule: Unexpected LSA-type(%u)", lsa->data->type);
+ goto out;
+ }
+
+ /* Dequeue listnode entry from the list. */
+ listnode_delete (oipt->id_list, oipi);
+
+ /* Avoid misjudgement in the next lookup. */
+ if (listcount (oipt->id_list) == 0)
+ oipt->id_list->head = oipt->id_list->tail = NULL;
+
+ /* Disassociate internal control information with the given lsa. */
+ oipi->lsa = NULL;
+ free_opaque_info_per_id ((void *) oipi);
+
+ /* Force given lsa's age to MaxAge. */
+ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Schedule Type-%u Opaque-LSA to FLUSH: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)));
+
+ /* This lsa will be flushed and removed eventually. */
+ ospf_lsa_maxage (lsa);
+
+out:
+ return;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are control functions to block origination after restart.
+ *------------------------------------------------------------------------*/
+
+static void ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs, struct ospf_neighbor *inbr, struct ospf_lsa *lsa);
+static void ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi);
+static void ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area);
+static void ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top);
+static unsigned long ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type);
+
+void
+ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, list lsas)
+{
+ struct ospf *top;
+ struct ospf_area *area;
+ struct ospf_interface *oi;
+ listnode node1, node2;
+ struct ospf_lsa *lsa;
+
+ if ((top = oi_to_top (nbr->oi)) == NULL)
+ goto out;
+
+ /*
+ * If an instance of self-originated Opaque-LSA is found in the given
+ * LSA list, and it is not installed to LSDB yet, exclude it from the
+ * list "nbr->ls_req". In this way, it is assured that an LSReq message,
+ * which might be sent in the process of flooding, will not request for
+ * the LSA to be flushed immediately; otherwise, depending on timing,
+ * an LSUpd message will carry instances of target LSAs with MaxAge,
+ * while other LSUpd message might carry old LSA instances (non-MaxAge).
+ * Obviously, the latter would trigger miserable situations that repeat
+ * installation and removal of unwanted LSAs indefinitely.
+ */
+ for (node1 = listhead (lsas); node1; nextnode (node1))
+ {
+ if ((lsa = getdata (node1)) == NULL)
+ continue;
+
+ /* Filter out unwanted LSAs. */
+ if (! IS_OPAQUE_LSA (lsa->data->type))
+ continue;
+ if (! IPV4_ADDR_SAME (&lsa->data->adv_router, &top->router_id))
+ continue;
+
+ /*
+ * Don't touch an LSA which has MaxAge; two possible cases.
+ *
+ * 1) This LSA has originally flushed by myself (received LSUpd
+ * message's router-id is equal to my router-id), and flooded
+ * back by an opaque-capable router.
+ *
+ * 2) This LSA has expired in an opaque-capable router and thus
+ * flushed by the router.
+ */
+ if (IS_LSA_MAXAGE (lsa))
+ continue;
+
+ /* If the LSA has installed in the LSDB, nothing to do here. */
+ if (ospf_lsa_lookup_by_header (nbr->oi->area, lsa->data) != NULL)
+ continue;
+
+ /* Ok, here we go. */
+ switch (lsa->data->type)
+ {
+ case OSPF_OPAQUE_LINK_LSA:
+ oi = nbr->oi;
+ ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa);
+ break;
+ case OSPF_OPAQUE_AREA_LSA:
+ area = nbr->oi->area;
+ for (node2 = listhead (area->oiflist); node2; nextnode (node2))
+ {
+ if ((oi = getdata (node2)) == NULL)
+ continue;
+ ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa);
+ }
+ break;
+ case OSPF_OPAQUE_AS_LSA:
+ for (node2 = listhead (top->oiflist); node2; nextnode (node2))
+ {
+ if ((oi = getdata (node2)) == NULL)
+ continue;
+ ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+out:
+ return;
+}
+
+static void
+ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs,
+ struct ospf_neighbor *inbr,
+ struct ospf_lsa *lsa)
+{
+ struct route_node *rn;
+ struct ospf_neighbor *onbr;
+ struct ospf_lsa *ls_req;
+
+ for (rn = route_top (nbrs); rn; rn = route_next (rn))
+ {
+ if ((onbr = rn->info) == NULL)
+ continue;
+ if (onbr == inbr)
+ continue;
+ if ((ls_req = ospf_ls_request_lookup (onbr, lsa)) == NULL)
+ continue;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("LSA[%s]: Exclude this entry from LSReq to send.", dump_lsa_key (lsa));
+
+ ospf_ls_request_delete (onbr, ls_req);
+/* ospf_check_nbr_loading (onbr);*//* XXX */
+ }
+
+ return;
+}
+
+void
+ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, list lsas)
+{
+ struct ospf *top;
+ listnode node, next;
+ struct ospf_lsa *lsa;
+ u_char before;
+
+ if ((top = oi_to_top (nbr->oi)) == NULL)
+ goto out;
+
+ before = IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque);
+
+ for (node = listhead (lsas); node; node = next)
+ {
+ next = node->next;
+
+ if ((lsa = getdata (node)) == NULL)
+ continue;
+
+ listnode_delete (lsas, lsa);
+
+ /*
+ * Since these LSA entries are not yet installed into corresponding
+ * LSDB, just flush them without calling ospf_ls_maxage() afterward.
+ */
+ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
+ switch (lsa->data->type)
+ {
+ case OSPF_OPAQUE_LINK_LSA:
+ SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT);
+ ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa);
+ break;
+ case OSPF_OPAQUE_AREA_LSA:
+ SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT);
+ ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa);
+ break;
+ case OSPF_OPAQUE_AS_LSA:
+ SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT);
+ ospf_flood_through_as (NULL/*inbr*/, lsa);
+ break;
+ default:
+ zlog_warn ("ospf_opaque_self_originated_lsa_received: Unexpected LSA-type(%u)", lsa->data->type);
+ goto out;
+ }
+
+ ospf_lsa_discard (lsa); /* List "lsas" will be deleted by caller. */
+ }
+
+ if (before == 0 && IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque))
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Block Opaque-LSA origination: OFF -> ON");
+ }
+
+out:
+ return;
+}
+
+void
+ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, list acks)
+{
+ struct ospf *top;
+ listnode node;
+ struct ospf_lsa *lsa;
+ char type9_lsa_rcv = 0, type10_lsa_rcv = 0, type11_lsa_rcv = 0;
+
+ if ((top = oi_to_top (nbr->oi)) == NULL)
+ goto out;
+
+ for (node = listhead (acks); node; nextnode (node))
+ {
+ if ((lsa = getdata (node)) == NULL)
+ continue;
+
+ switch (lsa->data->type)
+ {
+ case OSPF_OPAQUE_LINK_LSA:
+ type9_lsa_rcv = 1;
+ /* Callback function... */
+ break;
+ case OSPF_OPAQUE_AREA_LSA:
+ type10_lsa_rcv = 1;
+ /* Callback function... */
+ break;
+ case OSPF_OPAQUE_AS_LSA:
+ type11_lsa_rcv = 1;
+ /* Callback function... */
+ break;
+ default:
+ zlog_warn ("ospf_opaque_ls_ack_received: Unexpected LSA-type(%u)", lsa->data->type);
+ goto out;
+ }
+ }
+
+ if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque))
+ {
+ int delay;
+ struct ospf_interface *oi;
+
+ if (type9_lsa_rcv
+ && CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT))
+ ospf_opaque_type9_lsa_rxmt_nbr_check (nbr->oi);
+
+ if (type10_lsa_rcv
+ && CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT))
+ ospf_opaque_type10_lsa_rxmt_nbr_check (nbr->oi->area);
+
+ if (type11_lsa_rcv
+ && CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT))
+ ospf_opaque_type11_lsa_rxmt_nbr_check (top);
+
+ if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque))
+ goto out; /* Blocking still in progress. */
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Block Opaque-LSA origination: ON -> OFF");
+
+ if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE))
+ goto out; /* Opaque capability condition must have changed. */
+
+ /* Ok, let's start origination of Opaque-LSAs. */
+ delay = OSPF_MIN_LS_INTERVAL;
+ for (node = listhead (top->oiflist); node; nextnode (node))
+ {
+ if ((oi = getdata (node)) == NULL)
+ continue;
+
+ if (! ospf_if_is_enable (oi)
+ || ospf_opaque_capable_nbr_count (oi->nbrs, NSM_Full) == 0)
+ continue;
+
+ ospf_opaque_lsa_originate_schedule (oi, &delay);
+ }
+ }
+
+out:
+ return;
+}
+
+static void
+ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi)
+{
+ unsigned long n;
+
+ n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_LINK_LSA);
+ if (n == 0)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Self-originated type-9 Opaque-LSAs: OI(%s): Flush completed", IF_NAME (oi));
+
+ UNSET_FLAG (oi->area->top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT);
+ }
+ return;
+}
+
+static void
+ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area)
+{
+ listnode node;
+ struct ospf_interface *oi;
+ unsigned long n = 0;
+
+ for (node = listhead (area->oiflist); node; nextnode (node))
+ {
+ if ((oi = getdata (node)) == NULL)
+ continue;
+
+ if (area->area_id.s_addr != OSPF_AREA_BACKBONE
+ && oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ continue;
+
+ n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_AREA_LSA);
+ if (n > 0)
+ break;
+ }
+
+ if (n == 0)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Self-originated type-10 Opaque-LSAs: AREA(%s): Flush completed", inet_ntoa (area->area_id));
+
+ UNSET_FLAG (area->top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT);
+ }
+
+ return;
+}
+
+static void
+ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top)
+{
+ listnode node;
+ struct ospf_interface *oi;
+ unsigned long n = 0;
+
+ for (node = listhead (top->oiflist); node; nextnode (node))
+ {
+ if ((oi = getdata (node)) == NULL)
+ continue;
+
+ switch (oi->type)
+ {
+ case OSPF_IFTYPE_VIRTUALLINK:
+ continue;
+ default:
+ break;
+ }
+
+ n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_AS_LSA);
+ if (n > 0)
+ goto out;
+ }
+
+ if (n == 0)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Self-originated type-11 Opaque-LSAs: Flush completed");
+
+ UNSET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT);
+ }
+
+out:
+ return;
+}
+
+static unsigned long
+ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type)
+{
+ struct route_node *rn;
+ struct ospf_neighbor *nbr;
+ struct ospf *top;
+ unsigned long n = 0;
+
+ for (rn = route_top (nbrs); rn; rn = route_next (rn))
+ {
+ if ((nbr = rn->info) == NULL)
+ continue;
+ if ((top = oi_to_top (nbr->oi)) == NULL)
+ continue;
+ if (IPV4_ADDR_SAME (&nbr->router_id, &top->router_id))
+ continue;
+ n += ospf_ls_retransmit_count_self (nbr, lsa_type);
+ }
+
+ return n;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are util functions; probably be used by Opaque-LSAs only...
+ *------------------------------------------------------------------------*/
+
+void
+htonf (float *src, float *dst)
+{
+ u_int32_t lu1, lu2;
+
+ memcpy (&lu1, src, sizeof (u_int32_t));
+ lu2 = htonl (lu1);
+ memcpy (dst, &lu2, sizeof (u_int32_t));
+ return;
+}
+
+void
+ntohf (float *src, float *dst)
+{
+ u_int32_t lu1, lu2;
+
+ memcpy (&lu1, src, sizeof (u_int32_t));
+ lu2 = ntohl (lu1);
+ memcpy (dst, &lu2, sizeof (u_int32_t));
+ return;
+}
+
+struct ospf *
+oi_to_top (struct ospf_interface *oi)
+{
+ struct ospf *top = NULL;
+ struct ospf_area *area;
+
+ if (oi == NULL || (area = oi->area) == NULL || (top = area->top) == NULL)
+ zlog_warn ("Broken relationship for \"OI -> AREA -> OSPF\"?");
+
+ return top;
+}
+
+#endif /* HAVE_OPAQUE_LSA */
diff --git a/ospfd/ospf_opaque.h b/ospfd/ospf_opaque.h
new file mode 100644
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.
+ * <http://www.iana.org/assignments/ospf-opaque-types>
+ */
+#define OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA 1
+#define OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC 2
+#define OPAQUE_TYPE_GRACE_LSA 3
+
+/* Followings types are proposed in internet-draft documents. */
+#define OPAQUE_TYPE_8021_QOSPF 129
+#define OPAQUE_TYPE_SECONDARY_NEIGHBOR_DISCOVERY 224
+#define OPAQUE_TYPE_FLOODGATE 225
+
+/* Ugly hack to make use of an unallocated value for wildcard matching! */
+#define OPAQUE_TYPE_WILDCARD 0
+
+#define OPAQUE_TYPE_RANGE_UNASSIGNED(type) \
+ ( 4 <= (type) && (type) <= 127)
+
+#define OPAQUE_TYPE_RANGE_RESERVED(type) \
+ (127 < (type) && (type) <= 255)
+
+#define VALID_OPAQUE_INFO_LEN(lsahdr) \
+ ((ntohs((lsahdr)->length) >= sizeof (struct lsa_header)) && \
+ ((ntohs((lsahdr)->length) % sizeof (u_int32_t)) == 0))
+
+/* Prototypes. */
+struct vty;
+struct stream;
+
+extern void ospf_opaque_init (void);
+extern void ospf_opaque_term (void);
+extern int ospf_opaque_type9_lsa_init (struct ospf_interface *oi);
+extern void ospf_opaque_type9_lsa_term (struct ospf_interface *oi);
+extern int ospf_opaque_type10_lsa_init (struct ospf_area *area);
+extern void ospf_opaque_type10_lsa_term (struct ospf_area *area);
+extern int ospf_opaque_type11_lsa_init (struct ospf *ospf);
+extern void ospf_opaque_type11_lsa_term (struct ospf *ospf);
+
+extern int
+ospf_register_opaque_functab (
+ u_char lsa_type,
+ u_char opaque_type,
+ int (* new_if_hook)(struct interface *ifp),
+ int (* del_if_hook)(struct interface *ifp),
+ void (* ism_change_hook)(struct ospf_interface *oi, int old_status),
+ void (* nsm_change_hook)(struct ospf_neighbor *nbr, int old_status),
+ void (* config_write_router)(struct vty *vty),
+ void (* config_write_if )(struct vty *vty, struct interface *ifp),
+ void (* config_write_debug )(struct vty *vty),
+ void (* show_opaque_info )(struct vty *vty, struct ospf_lsa *lsa),
+ int (* lsa_originator)(void *arg),
+ void (* lsa_refresher )(struct ospf_lsa *lsa),
+ int (* new_lsa_hook)(struct ospf_lsa *lsa),
+ int (* del_lsa_hook)(struct ospf_lsa *lsa)
+);
+extern void ospf_delete_opaque_functab (u_char lsa_type, u_char opaque_type);
+
+extern int ospf_opaque_new_if (struct interface *ifp);
+extern int ospf_opaque_del_if (struct interface *ifp);
+extern void ospf_opaque_ism_change (struct ospf_interface *oi, int old_status);
+extern void ospf_opaque_nsm_change (struct ospf_neighbor *nbr, int old_status);
+extern void ospf_opaque_config_write_router (struct vty *vty, struct ospf *);
+extern void ospf_opaque_config_write_if (struct vty *vty, struct interface *ifp);
+extern void ospf_opaque_config_write_debug (struct vty *vty);
+extern void show_opaque_info_detail (struct vty *vty, struct ospf_lsa *lsa);
+extern void ospf_opaque_lsa_dump (struct stream *s, u_int16_t length);
+
+extern void ospf_opaque_lsa_originate_schedule (struct ospf_interface *oi, int *init_delay);
+extern struct ospf_lsa *ospf_opaque_lsa_install (struct ospf_lsa *new, int rt_recalc);
+extern void ospf_opaque_lsa_refresh (struct ospf_lsa *lsa);
+
+extern void ospf_opaque_lsa_reoriginate_schedule (void *lsa_type_dependent, u_char lsa_type, u_char opaque_type);
+extern void ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa);
+extern void ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa);
+
+extern void ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, list lsas);
+extern void ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, list lsas);
+extern void ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, list acks);
+
+extern void htonf (float *src, float *dst);
+extern void ntohf (float *src, float *dst);
+extern struct ospf *oi_to_top (struct ospf_interface *oi);
+
+#endif /* _ZEBRA_OSPF_OPAQUE_H */
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
new file mode 100644
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 <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "sockunion.h"
+#include "stream.h"
+#include "log.h"
+#include "md5-gnu.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_network.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_dump.h"
+
+static void ospf_ls_ack_send_list (struct ospf_interface *, list,
+ struct in_addr);
+
+/* Packet Type String. */
+char *ospf_packet_type_str[] =
+{
+ "unknown",
+ "Hello",
+ "Database Description",
+ "Link State Request",
+ "Link State Update",
+ "Link State Acknowledgment",
+};
+
+extern int in_cksum (void *ptr, int nbytes);
+
+/* OSPF authentication checking function */
+int
+ospf_auth_type (struct ospf_interface *oi)
+{
+ int auth_type;
+
+ if (OSPF_IF_PARAM (oi, auth_type) == OSPF_AUTH_NOTSET)
+ auth_type = oi->area->auth_type;
+ else
+ auth_type = OSPF_IF_PARAM (oi, auth_type);
+
+ /* Handle case where MD5 key list is not configured aka Cisco */
+ if (auth_type == OSPF_AUTH_CRYPTOGRAPHIC &&
+ list_isempty (OSPF_IF_PARAM (oi, auth_crypt)))
+ return OSPF_AUTH_NULL;
+
+ return auth_type;
+
+}
+
+/* forward output pointer. */
+void
+ospf_output_forward (struct stream *s, int size)
+{
+ s->putp += size;
+}
+
+struct ospf_packet *
+ospf_packet_new (size_t size)
+{
+ struct ospf_packet *new;
+
+ new = XCALLOC (MTYPE_OSPF_PACKET, sizeof (struct ospf_packet));
+ new->s = stream_new (size);
+
+ return new;
+}
+
+void
+ospf_packet_free (struct ospf_packet *op)
+{
+ if (op->s)
+ stream_free (op->s);
+
+ XFREE (MTYPE_OSPF_PACKET, op);
+
+ op = NULL;
+}
+
+struct ospf_fifo *
+ospf_fifo_new ()
+{
+ struct ospf_fifo *new;
+
+ new = XCALLOC (MTYPE_OSPF_FIFO, sizeof (struct ospf_fifo));
+ return new;
+}
+
+/* Add new packet to fifo. */
+void
+ospf_fifo_push (struct ospf_fifo *fifo, struct ospf_packet *op)
+{
+ if (fifo->tail)
+ fifo->tail->next = op;
+ else
+ fifo->head = op;
+
+ fifo->tail = op;
+
+ fifo->count++;
+}
+
+/* Delete first packet from fifo. */
+struct ospf_packet *
+ospf_fifo_pop (struct ospf_fifo *fifo)
+{
+ struct ospf_packet *op;
+
+ op = fifo->head;
+
+ if (op)
+ {
+ fifo->head = op->next;
+
+ if (fifo->head == NULL)
+ fifo->tail = NULL;
+
+ fifo->count--;
+ }
+
+ return op;
+}
+
+/* Return first fifo entry. */
+struct ospf_packet *
+ospf_fifo_head (struct ospf_fifo *fifo)
+{
+ return fifo->head;
+}
+
+/* Flush ospf packet fifo. */
+void
+ospf_fifo_flush (struct ospf_fifo *fifo)
+{
+ struct ospf_packet *op;
+ struct ospf_packet *next;
+
+ for (op = fifo->head; op; op = next)
+ {
+ next = op->next;
+ ospf_packet_free (op);
+ }
+ fifo->head = fifo->tail = NULL;
+ fifo->count = 0;
+}
+
+/* Free ospf packet fifo. */
+void
+ospf_fifo_free (struct ospf_fifo *fifo)
+{
+ ospf_fifo_flush (fifo);
+
+ XFREE (MTYPE_OSPF_FIFO, fifo);
+}
+
+void
+ospf_packet_add (struct ospf_interface *oi, struct ospf_packet *op)
+{
+ /* Add packet to end of queue. */
+ ospf_fifo_push (oi->obuf, op);
+
+ /* Debug of packet fifo*/
+ /* ospf_fifo_debug (oi->obuf); */
+}
+
+void
+ospf_packet_delete (struct ospf_interface *oi)
+{
+ struct ospf_packet *op;
+
+ op = ospf_fifo_pop (oi->obuf);
+
+ if (op)
+ ospf_packet_free (op);
+}
+
+struct stream *
+ospf_stream_copy (struct stream *new, struct stream *s)
+{
+ new->endp = s->endp;
+ new->putp = s->putp;
+ new->getp = s->getp;
+
+ memcpy (new->data, s->data, stream_get_endp (s));
+
+ return new;
+}
+
+struct ospf_packet *
+ospf_packet_dup (struct ospf_packet *op)
+{
+ struct ospf_packet *new;
+
+ new = ospf_packet_new (op->length);
+ ospf_stream_copy (new->s, op->s);
+
+ new->dst = op->dst;
+ new->length = op->length;
+
+ return new;
+}
+
+int
+ospf_packet_max (struct ospf_interface *oi)
+{
+ int max;
+
+ if ( ospf_auth_type (oi) == OSPF_AUTH_CRYPTOGRAPHIC)
+ max = oi->ifp->mtu - OSPF_AUTH_MD5_SIZE - 88;
+ else
+ max = oi->ifp->mtu - 88;
+
+ return max;
+}
+
+
+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 <netinet/ip_input.c>.
+ */
+ ip_len = ip_len + (iph.ip_hl << 2);
+#endif
+
+ ibuf = stream_new (ip_len);
+ iov.iov_base = STREAM_DATA (ibuf);
+ iov.iov_len = ip_len;
+ ret = recvmsg (fd, &msgh, 0);
+
+ cmsg = CMSG_FIRSTHDR (&msgh);
+
+ if (cmsg != NULL && //cmsg->cmsg_len == sizeof (*pktinfo) &&
+ cmsg->cmsg_level == IPPROTO_IP &&
+#if defined (IP_PKTINFO)
+ cmsg->cmsg_type == IP_PKTINFO
+#elif defined (IP_RECVIF)
+ cmsg->cmsg_type == IP_RECVIF
+#else
+ 0
+#endif
+ )
+ {
+#if defined (IP_PKTINFO)
+ pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
+ ifindex = pktinfo->ipi_ifindex;
+#elif defined (IP_RECVIF)
+ pktinfo = (struct sockaddr_dl *)CMSG_DATA(cmsg);
+ ifindex = pktinfo->sdl_index;
+#else
+ ifindex = 0;
+#endif
+ }
+
+ *ifp = if_lookup_by_index (ifindex);
+
+ if (ret != ip_len)
+ {
+ zlog_warn ("ospf_recv_packet short read. "
+ "ip_len %d bytes read %d", ip_len, ret);
+ stream_free (ibuf);
+ return NULL;
+ }
+
+ return ibuf;
+}
+
+struct ospf_interface *
+ospf_associate_packet_vl (struct interface *ifp, struct ospf_interface *oi,
+ struct ip *iph, struct ospf_header *ospfh)
+{
+ struct ospf_interface *rcv_oi;
+ listnode node;
+ struct ospf_vl_data *vl_data;
+ struct ospf_area *vl_area;
+
+ if (IN_MULTICAST (ntohl (iph->ip_dst.s_addr)) ||
+ !OSPF_IS_AREA_BACKBONE (ospfh))
+ return oi;
+
+ if ((rcv_oi = oi) == NULL)
+ {
+ if ((rcv_oi = ospf_if_lookup_by_local_addr (ifp, iph->ip_dst)) == NULL)
+ return NULL;
+ }
+
+ for (node = listhead (ospf_top->vlinks); node; nextnode (node))
+ {
+ if ((vl_data = getdata (node)) == NULL)
+ continue;
+
+ vl_area = ospf_area_lookup_by_area_id (vl_data->vl_area_id);
+ if (!vl_area)
+ continue;
+
+ if (OSPF_AREA_SAME (&vl_area, &rcv_oi->area) &&
+ IPV4_ADDR_SAME (&vl_data->vl_peer, &ospfh->router_id))
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("associating packet with %s",
+ IF_NAME (vl_data->vl_oi));
+ if (! CHECK_FLAG (vl_data->vl_oi->ifp->flags, IFF_UP))
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("This VL is not up yet, sorry");
+ return NULL;
+ }
+
+ return vl_data->vl_oi;
+ }
+ }
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("couldn't find any VL to associate the packet with");
+
+ return oi;
+}
+
+int
+ospf_check_area_id (struct ospf_interface *oi, struct ospf_header *ospfh)
+{
+ /* Check match the Area ID of the receiving interface. */
+ if (OSPF_AREA_SAME (&oi->area, &ospfh))
+ return 1;
+
+ return 0;
+}
+
+/* Unbound socket will accept any Raw IP packets if proto is matched.
+ To prevent it, compare src IP address and i/f address with masking
+ i/f network mask. */
+int
+ospf_check_network_mask (struct ospf_interface *oi, struct in_addr ip_src)
+{
+ struct in_addr mask, me, him;
+
+ if (oi->type == OSPF_IFTYPE_POINTOPOINT ||
+ oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ return 1;
+
+ masklen2ip (oi->address->prefixlen, &mask);
+
+ me.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
+ him.s_addr = ip_src.s_addr & mask.s_addr;
+
+ if (IPV4_ADDR_SAME (&me, &him))
+ return 1;
+
+ return 0;
+}
+
+int
+ospf_check_auth (struct ospf_interface *oi, struct stream *ibuf,
+ struct ospf_header *ospfh)
+{
+ int ret = 0;
+ struct crypt_key *ck;
+
+ switch (ntohs (ospfh->auth_type))
+ {
+ case OSPF_AUTH_NULL:
+ ret = 1;
+ break;
+ case OSPF_AUTH_SIMPLE:
+ if (!memcmp (OSPF_IF_PARAM (oi, auth_simple), ospfh->u.auth_data, OSPF_AUTH_SIMPLE_SIZE))
+ ret = 1;
+ else
+ ret = 0;
+ break;
+ case OSPF_AUTH_CRYPTOGRAPHIC:
+ if ((ck = getdata (OSPF_IF_PARAM (oi,auth_crypt)->tail)) == NULL)
+ {
+ ret = 0;
+ break;
+ }
+
+ /* This is very basic, the digest processing is elsewhere */
+ if (ospfh->u.crypt.auth_data_len == OSPF_AUTH_MD5_SIZE &&
+ ospfh->u.crypt.key_id == ck->key_id &&
+ ntohs (ospfh->length) + OSPF_AUTH_SIMPLE_SIZE <= stream_get_size (ibuf))
+ ret = 1;
+ else
+ ret = 0;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+int
+ospf_check_sum (struct ospf_header *ospfh)
+{
+ u_int32_t ret;
+ u_int16_t sum;
+ int in_cksum (void *ptr, int nbytes);
+
+ /* clear auth_data for checksum. */
+ memset (ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE);
+
+ /* keep checksum and clear. */
+ sum = ospfh->checksum;
+ memset (&ospfh->checksum, 0, sizeof (u_int16_t));
+
+ /* calculate checksum. */
+ ret = in_cksum (ospfh, ntohs (ospfh->length));
+
+ if (ret != sum)
+ {
+ zlog_info ("ospf_check_sum(): checksum mismatch, my %X, his %X",
+ ret, sum);
+ return 0;
+ }
+
+ return 1;
+}
+
+/* OSPF Header verification. */
+int
+ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi,
+ struct ip *iph, struct ospf_header *ospfh)
+{
+ /* check version. */
+ if (ospfh->version != OSPF_VERSION)
+ {
+ zlog_warn ("interface %s: ospf_read version number mismatch.",
+ IF_NAME (oi));
+ return -1;
+ }
+
+ /* Check Area ID. */
+ if (!ospf_check_area_id (oi, ospfh))
+ {
+ zlog_warn ("interface %s: ospf_read invalid Area ID %s.",
+ IF_NAME (oi), inet_ntoa (ospfh->area_id));
+ return -1;
+ }
+
+ /* Check network mask, Silently discarded. */
+ if (! ospf_check_network_mask (oi, iph->ip_src))
+ {
+ zlog_warn ("interface %s: ospf_read network address is not same [%s]",
+ IF_NAME (oi), inet_ntoa (iph->ip_src));
+ return -1;
+ }
+
+ /* Check authentication. */
+ if (ospf_auth_type (oi) != ntohs (ospfh->auth_type))
+ {
+ zlog_warn ("interface %s: ospf_read authentication type mismatch.",
+ IF_NAME (oi));
+ return -1;
+ }
+
+ if (! ospf_check_auth (oi, ibuf, ospfh))
+ {
+ zlog_warn ("interface %s: ospf_read authentication failed.",
+ IF_NAME (oi));
+ return -1;
+ }
+
+ /* if check sum is invalid, packet is discarded. */
+ if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC)
+ {
+ if (! ospf_check_sum (ospfh))
+ {
+ zlog_warn ("interface %s: ospf_read packet checksum error %s",
+ IF_NAME (oi), inet_ntoa (ospfh->router_id));
+ return -1;
+ }
+ }
+ else
+ {
+ if (ospfh->checksum != 0)
+ return -1;
+ if (ospf_check_md5_digest (oi, ibuf, ntohs (ospfh->length)) == 0)
+ {
+ zlog_warn ("interface %s: ospf_read md5 authentication failed.",
+ IF_NAME (oi));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* Starting point of packet process function. */
+int
+ospf_read (struct thread *thread)
+{
+ int ret;
+ struct stream *ibuf;
+ struct ospf *top;
+ struct ospf_interface *oi;
+ struct ip *iph;
+ struct ospf_header *ospfh;
+ u_int16_t length;
+ struct interface *ifp;
+
+ /* first of all get interface pointer. */
+ top = THREAD_ARG (thread);
+ top->t_read = NULL;
+
+ /* read OSPF packet. */
+ ibuf = ospf_recv_packet (top->fd, &ifp);
+ if (ibuf == NULL)
+ return -1;
+
+ iph = (struct ip *) STREAM_DATA (ibuf);
+
+ /* prepare for next packet. */
+ top->t_read = thread_add_read (master, ospf_read, top, top->fd);
+
+ /* IP Header dump. */
+ /*
+ if (ospf_debug_packet & OSPF_DEBUG_RECV)
+ ospf_ip_header_dump (ibuf);
+ */
+ /* Self-originated packet should be discarded silently. */
+ if (ospf_if_lookup_by_local_addr (NULL, iph->ip_src))
+ {
+ stream_free (ibuf);
+ return 0;
+ }
+
+ /* Adjust size to message length. */
+ stream_forward (ibuf, iph->ip_hl * 4);
+
+ /* Get ospf packet header. */
+ ospfh = (struct ospf_header *) STREAM_PNT (ibuf);
+
+ /* associate packet with ospf interface */
+ oi = ospf_if_lookup_recv_interface (iph->ip_src);
+ if (ifp && oi && oi->ifp != ifp)
+ {
+ zlog_warn ("Packet from [%s] received on wrong link %s",
+ inet_ntoa (iph->ip_src), ifp->name);
+ stream_free (ibuf);
+ return 0;
+ }
+
+ if ((oi = ospf_associate_packet_vl (ifp, oi, iph, ospfh)) == NULL)
+ {
+ stream_free (ibuf);
+ return 0;
+ }
+
+ /*
+ * If the received packet is destined for AllDRouters, the packet
+ * should be accepted only if the received ospf interface state is
+ * either DR or Backup -- endo.
+ */
+ if (iph->ip_dst.s_addr == htonl (OSPF_ALLDROUTERS)
+ && (oi->state != ISM_DR && oi->state != ISM_Backup))
+ {
+ zlog_info ("Packet for AllDRouters from [%s] via [%s] (ISM: %s)",
+ inet_ntoa (iph->ip_src), IF_NAME (oi),
+ LOOKUP (ospf_ism_state_msg, oi->state));
+ stream_free (ibuf);
+ return 0;
+ }
+
+ /* Show debug receiving packet. */
+ if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
+ {
+ if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL))
+ {
+ zlog_info ("-----------------------------------------------------");
+ ospf_packet_dump (ibuf);
+ }
+
+ zlog_info ("%s received from [%s] via [%s]",
+ ospf_packet_type_str[ospfh->type],
+ inet_ntoa (ospfh->router_id), IF_NAME (oi));
+ zlog_info (" src [%s],", inet_ntoa (iph->ip_src));
+ zlog_info (" dst [%s]", inet_ntoa (iph->ip_dst));
+
+ if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL))
+ zlog_info ("-----------------------------------------------------");
+ }
+
+ /* Some header verification. */
+ ret = ospf_verify_header (ibuf, oi, iph, ospfh);
+ if (ret < 0)
+ {
+ stream_free (ibuf);
+ return ret;
+ }
+
+ stream_forward (ibuf, OSPF_HEADER_SIZE);
+
+ /* Adjust size to message length. */
+ length = ntohs (ospfh->length) - OSPF_HEADER_SIZE;
+
+ /* Read rest of the packet and call each sort of packet routine. */
+ switch (ospfh->type)
+ {
+ case OSPF_MSG_HELLO:
+ ospf_hello (iph, ospfh, ibuf, oi, length);
+ break;
+ case OSPF_MSG_DB_DESC:
+ ospf_db_desc (iph, ospfh, ibuf, oi, length);
+ break;
+ case OSPF_MSG_LS_REQ:
+ ospf_ls_req (iph, ospfh, ibuf, oi, length);
+ break;
+ case OSPF_MSG_LS_UPD:
+ ospf_ls_upd (iph, ospfh, ibuf, oi, length);
+ break;
+ case OSPF_MSG_LS_ACK:
+ ospf_ls_ack (iph, ospfh, ibuf, oi, length);
+ break;
+ default:
+ zlog (NULL, LOG_WARNING,
+ "interface %s: OSPF packet header type %d is illegal",
+ IF_NAME (oi), ospfh->type);
+ break;
+ }
+
+ stream_free (ibuf);
+ return 0;
+}
+
+/* Make OSPF header. */
+void
+ospf_make_header (int type, struct ospf_interface *oi, struct stream *s)
+{
+ struct ospf_header *ospfh;
+
+ ospfh = (struct ospf_header *) STREAM_DATA (s);
+
+ ospfh->version = (u_char) OSPF_VERSION;
+ ospfh->type = (u_char) type;
+
+ ospfh->router_id = ospf_top->router_id;
+
+ ospfh->checksum = 0;
+ ospfh->area_id = oi->area->area_id;
+ ospfh->auth_type = htons (ospf_auth_type (oi));
+
+ memset (ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE);
+
+ ospf_output_forward (s, OSPF_HEADER_SIZE);
+}
+
+/* Make Authentication Data. */
+int
+ospf_make_auth (struct ospf_interface *oi, struct ospf_header *ospfh)
+{
+ struct crypt_key *ck;
+
+ switch (ospf_auth_type (oi))
+ {
+ case OSPF_AUTH_NULL:
+ /* memset (ospfh->u.auth_data, 0, sizeof (ospfh->u.auth_data)); */
+ break;
+ case OSPF_AUTH_SIMPLE:
+ memcpy (ospfh->u.auth_data, OSPF_IF_PARAM (oi, auth_simple),
+ OSPF_AUTH_SIMPLE_SIZE);
+ break;
+ case OSPF_AUTH_CRYPTOGRAPHIC:
+ /* If key is not set, then set 0. */
+ if (list_isempty (OSPF_IF_PARAM (oi, auth_crypt)))
+ {
+ ospfh->u.crypt.zero = 0;
+ ospfh->u.crypt.key_id = 0;
+ ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE;
+ }
+ else
+ {
+ ck = getdata (OSPF_IF_PARAM (oi, auth_crypt)->tail);
+ ospfh->u.crypt.zero = 0;
+ ospfh->u.crypt.key_id = ck->key_id;
+ ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE;
+ }
+ /* note: the seq is done in ospf_make_md5_digest() */
+ break;
+ default:
+ /* memset (ospfh->u.auth_data, 0, sizeof (ospfh->u.auth_data)); */
+ break;
+ }
+
+ return 0;
+}
+
+/* Fill rest of OSPF header. */
+void
+ospf_fill_header (struct ospf_interface *oi,
+ struct stream *s, u_int16_t length)
+{
+ struct ospf_header *ospfh;
+
+ ospfh = (struct ospf_header *) STREAM_DATA (s);
+
+ /* Fill length. */
+ ospfh->length = htons (length);
+
+ /* Calculate checksum. */
+ if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC)
+ ospfh->checksum = in_cksum (ospfh, length);
+ else
+ ospfh->checksum = 0;
+
+ /* Add Authentication Data. */
+ ospf_make_auth (oi, ospfh);
+}
+
+int
+ospf_make_hello (struct ospf_interface *oi, struct stream *s)
+{
+ struct ospf_neighbor *nbr;
+ struct route_node *rn;
+ u_int16_t length = OSPF_HELLO_MIN_SIZE;
+ struct in_addr mask;
+ unsigned long p;
+ int flag = 0;
+
+ /* Set netmask of interface. */
+ if (oi->type != OSPF_IFTYPE_POINTOPOINT &&
+ oi->type != OSPF_IFTYPE_VIRTUALLINK)
+ masklen2ip (oi->address->prefixlen, &mask);
+ else
+ memset ((char *) &mask, 0, sizeof (struct in_addr));
+ stream_put_ipv4 (s, mask.s_addr);
+
+ /* Set Hello Interval. */
+ stream_putw (s, OSPF_IF_PARAM (oi, v_hello));
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("make_hello: options: %x, int: %s",
+ OPTIONS(oi), IF_NAME (oi));
+
+ /* Set Options. */
+ stream_putc (s, OPTIONS (oi));
+
+ /* Set Router Priority. */
+ stream_putc (s, PRIORITY (oi));
+
+ /* Set Router Dead Interval. */
+ stream_putl (s, OSPF_IF_PARAM (oi, v_wait));
+
+ /* Set Designated Router. */
+ stream_put_ipv4 (s, DR (oi).s_addr);
+
+ p = s->putp;
+
+ /* Set Backup Designated Router. */
+ stream_put_ipv4 (s, BDR (oi).s_addr);
+
+ /* Add neighbor seen. */
+ for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+ if ((nbr = rn->info) != NULL)
+ /* ignore 0.0.0.0 node. */
+ if (nbr->router_id.s_addr != 0)
+ if (nbr->state != NSM_Attempt)
+ /* ignore Down neighbor. */
+ if (nbr->state != NSM_Down)
+ /* this is myself for DR election. */
+ if (!IPV4_ADDR_SAME (&nbr->router_id, &ospf_top->router_id))
+ {
+ /* Check neighbor is sane? */
+ if (nbr->d_router.s_addr != 0 &&
+ IPV4_ADDR_SAME (&nbr->d_router, &oi->address->u.prefix4) &&
+ IPV4_ADDR_SAME (&nbr->bd_router, &oi->address->u.prefix4))
+ flag = 1;
+
+ stream_put_ipv4 (s, nbr->router_id.s_addr);
+ length += 4;
+ }
+
+ /* Let neighbor generate BackupSeen. */
+ if (flag == 1)
+ {
+ stream_set_putp (s, p);
+ stream_put_ipv4 (s, 0);
+ }
+
+ return length;
+}
+
+int
+ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr,
+ struct stream *s)
+{
+ struct ospf_lsa *lsa;
+ u_int16_t length = OSPF_DB_DESC_MIN_SIZE;
+ u_char options;
+ unsigned long pp;
+ int i;
+ struct ospf_lsdb *lsdb;
+
+ /* Set Interface MTU. */
+ if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ stream_putw (s, 0);
+ else
+ stream_putw (s, oi->ifp->mtu);
+
+ /* Set Options. */
+ options = OPTIONS (oi);
+#ifdef HAVE_OPAQUE_LSA
+ if (CHECK_FLAG (ospf_top->config, OSPF_OPAQUE_CAPABLE))
+ {
+ if (IS_SET_DD_I (nbr->dd_flags)
+ || CHECK_FLAG (nbr->options, OSPF_OPTION_O))
+ /*
+ * Set O-bit in the outgoing DD packet for capablity negotiation,
+ * if one of following case is applicable.
+ *
+ * 1) WaitTimer expiration event triggered the neighbor state to
+ * change to Exstart, but no (valid) DD packet has received
+ * from the neighbor yet.
+ *
+ * 2) At least one DD packet with O-bit on has received from the
+ * neighbor.
+ */
+ SET_FLAG (options, OSPF_OPTION_O);
+ }
+#endif /* HAVE_OPAQUE_LSA */
+ stream_putc (s, options);
+
+ /* Keep pointer to flags. */
+ pp = stream_get_putp (s);
+ stream_putc (s, nbr->dd_flags);
+
+ /* Set DD Sequence Number. */
+ stream_putl (s, nbr->dd_seqnum);
+
+ if (ospf_db_summary_isempty (nbr))
+ {
+ if (nbr->state >= NSM_Exchange)
+ {
+ nbr->dd_flags &= ~OSPF_DD_FLAG_M;
+ /* Set DD flags again */
+ stream_set_putp (s, pp);
+ stream_putc (s, nbr->dd_flags);
+ }
+ return length;
+ }
+
+ /* Describe LSA Header from Database Summary List. */
+ lsdb = &nbr->db_sum;
+
+ for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
+ {
+ struct route_table *table = lsdb->type[i].db;
+ struct route_node *rn;
+
+ for (rn = route_top (table); rn; rn = route_next (rn))
+ if ((lsa = rn->info) != NULL)
+ {
+#ifdef HAVE_OPAQUE_LSA
+ if (IS_OPAQUE_LSA (lsa->data->type)
+ && (! CHECK_FLAG (options, OSPF_OPTION_O)))
+ {
+ /* Suppress advertising opaque-informations. */
+ /* Remove LSA from DB summary list. */
+ ospf_lsdb_delete (lsdb, lsa);
+ continue;
+ }
+#endif /* HAVE_OPAQUE_LSA */
+
+ if (!CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD))
+ {
+ struct lsa_header *lsah;
+ u_int16_t ls_age;
+
+ /* DD packet overflows interface MTU. */
+ if (length + OSPF_LSA_HEADER_SIZE > OSPF_PACKET_MAX (oi))
+ break;
+
+ /* Keep pointer to LS age. */
+ lsah = (struct lsa_header *) (STREAM_DATA (s) +
+ stream_get_putp (s));
+
+ /* Proceed stream pointer. */
+ stream_put (s, lsa->data, OSPF_LSA_HEADER_SIZE);
+ length += OSPF_LSA_HEADER_SIZE;
+
+ /* Set LS age. */
+ ls_age = LS_AGE (lsa);
+ lsah->ls_age = htons (ls_age);
+
+ }
+
+ /* Remove LSA from DB summary list. */
+ ospf_lsdb_delete (lsdb, lsa);
+ }
+ }
+
+ return length;
+}
+
+int
+ospf_make_ls_req_func (struct stream *s, u_int16_t *length,
+ unsigned long delta, struct ospf_neighbor *nbr,
+ struct ospf_lsa *lsa)
+{
+ struct ospf_interface *oi;
+
+ oi = nbr->oi;
+
+ /* LS Request packet overflows interface MTU. */
+ if (*length + delta > OSPF_PACKET_MAX(oi))
+ return 0;
+
+ stream_putl (s, lsa->data->type);
+ stream_put_ipv4 (s, lsa->data->id.s_addr);
+ stream_put_ipv4 (s, lsa->data->adv_router.s_addr);
+
+ ospf_lsa_unlock (nbr->ls_req_last);
+ nbr->ls_req_last = ospf_lsa_lock (lsa);
+
+ *length += 12;
+ return 1;
+}
+
+int
+ospf_make_ls_req (struct ospf_neighbor *nbr, struct stream *s)
+{
+ struct ospf_lsa *lsa;
+ u_int16_t length = OSPF_LS_REQ_MIN_SIZE;
+ unsigned long delta = stream_get_putp(s)+12;
+ struct route_table *table;
+ struct route_node *rn;
+ int i;
+ struct ospf_lsdb *lsdb;
+
+ lsdb = &nbr->ls_req;
+
+ for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
+ {
+ table = lsdb->type[i].db;
+ for (rn = route_top (table); rn; rn = route_next (rn))
+ if ((lsa = (rn->info)) != NULL)
+ if (ospf_make_ls_req_func (s, &length, delta, nbr, lsa) == 0)
+ {
+ route_unlock_node (rn);
+ break;
+ }
+ }
+ return length;
+}
+
+int
+ls_age_increment (struct ospf_lsa *lsa, int delay)
+{
+ int age;
+
+ age = IS_LSA_MAXAGE (lsa) ? OSPF_LSA_MAXAGE : LS_AGE (lsa) + delay;
+
+ return (age > OSPF_LSA_MAXAGE ? OSPF_LSA_MAXAGE : age);
+}
+
+int
+ospf_make_ls_upd (struct ospf_interface *oi, list update, struct stream *s)
+{
+ struct ospf_lsa *lsa;
+ listnode node;
+ u_int16_t length = OSPF_LS_UPD_MIN_SIZE;
+ unsigned long delta = stream_get_putp (s);
+ unsigned long pp;
+ int count = 0;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info("ospf_make_ls_upd: Start");
+
+ pp = stream_get_putp (s);
+ ospf_output_forward (s, 4);
+
+ while ((node = listhead (update)) != NULL)
+ {
+ struct lsa_header *lsah;
+ u_int16_t ls_age;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info("ospf_make_ls_upd: List Iteration");
+
+ lsa = getdata (node);
+ assert (lsa);
+ assert (lsa->data);
+
+ /* Check packet size. */
+ if (length + delta + ntohs (lsa->data->length) > OSPF_PACKET_MAX (oi))
+ break;
+
+ /* Keep pointer to LS age. */
+ lsah = (struct lsa_header *) (STREAM_DATA (s) + stream_get_putp (s));
+
+ /* Put LSA to Link State Request. */
+ stream_put (s, lsa->data, ntohs (lsa->data->length));
+
+ /* Set LS age. */
+ /* each hop must increment an lsa_age by transmit_delay
+ of OSPF interface */
+ ls_age = ls_age_increment (lsa, OSPF_IF_PARAM (oi, transmit_delay));
+ lsah->ls_age = htons (ls_age);
+
+ length += ntohs (lsa->data->length);
+ count++;
+
+ list_delete_node (update, node);
+ ospf_lsa_unlock (lsa);
+ }
+
+ /* Now set #LSAs. */
+ stream_set_putp (s, pp);
+ stream_putl (s, count);
+
+ stream_set_putp (s, s->endp);
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info("ospf_make_ls_upd: Stop");
+ return length;
+}
+
+int
+ospf_make_ls_ack (struct ospf_interface *oi, list ack, struct stream *s)
+{
+ list rm_list;
+ listnode node;
+ u_int16_t length = OSPF_LS_ACK_MIN_SIZE;
+ unsigned long delta = stream_get_putp(s) + 24;
+ struct ospf_lsa *lsa;
+
+ rm_list = list_new ();
+
+ for (node = listhead (ack); node; nextnode (node))
+ {
+ lsa = getdata (node);
+ assert (lsa);
+
+ if (length + delta > OSPF_PACKET_MAX (oi))
+ break;
+
+ stream_put (s, lsa->data, OSPF_LSA_HEADER_SIZE);
+ length += OSPF_LSA_HEADER_SIZE;
+
+ listnode_add (rm_list, lsa);
+ }
+
+ /* Remove LSA from LS-Ack list. */
+ for (node = listhead (rm_list); node; nextnode (node))
+ {
+ lsa = (struct ospf_lsa *) getdata (node);
+
+ listnode_delete (ack, lsa);
+ ospf_lsa_unlock (lsa);
+ }
+
+ list_delete (rm_list);
+
+ return length;
+}
+
+void
+ospf_hello_send_sub (struct ospf_interface *oi, struct in_addr *addr)
+{
+ struct ospf_packet *op;
+ u_int16_t length = OSPF_HEADER_SIZE;
+
+ op = ospf_packet_new (oi->ifp->mtu);
+
+ /* Prepare OSPF common header. */
+ ospf_make_header (OSPF_MSG_HELLO, oi, op->s);
+
+ /* Prepare OSPF Hello body. */
+ length += ospf_make_hello (oi, op->s);
+
+ /* Fill OSPF header. */
+ ospf_fill_header (oi, op->s, length);
+
+ /* Set packet length. */
+ op->length = length;
+
+ op->dst.s_addr = addr->s_addr;
+
+ /* Add packet to the interface output queue. */
+ ospf_packet_add (oi, op);
+
+ /* Hook thread to write packet. */
+ OSPF_ISM_WRITE_ON ();
+}
+
+void
+ospf_poll_send (struct ospf_nbr_nbma *nbr_nbma)
+{
+ struct ospf_interface *oi;
+
+ oi = nbr_nbma->oi;
+ assert(oi);
+
+ /* If this is passive interface, do not send OSPF Hello. */
+ if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE)
+ return;
+
+ if (oi->type != OSPF_IFTYPE_NBMA)
+ return;
+
+ if (nbr_nbma->nbr != NULL && nbr_nbma->nbr->state != NSM_Down)
+ return;
+
+ if (PRIORITY(oi) == 0)
+ return;
+
+ if (nbr_nbma->priority == 0
+ && oi->state != ISM_DR && oi->state != ISM_Backup)
+ return;
+
+ ospf_hello_send_sub (oi, &nbr_nbma->addr);
+}
+
+int
+ospf_poll_timer (struct thread *thread)
+{
+ struct ospf_nbr_nbma *nbr_nbma;
+
+ nbr_nbma = THREAD_ARG (thread);
+ nbr_nbma->t_poll = NULL;
+
+ if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
+ zlog (NULL, LOG_INFO, "NSM[%s:%s]: Timer (Poll timer expire)",
+ IF_NAME (nbr_nbma->oi), inet_ntoa (nbr_nbma->addr));
+
+ ospf_poll_send (nbr_nbma);
+
+ if (nbr_nbma->v_poll > 0)
+ OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer,
+ nbr_nbma->v_poll);
+
+ return 0;
+}
+
+
+int
+ospf_hello_reply_timer (struct thread *thread)
+{
+ struct ospf_neighbor *nbr;
+
+ nbr = THREAD_ARG (thread);
+ nbr->t_hello_reply = NULL;
+
+ assert (nbr->oi);
+
+ if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
+ zlog (NULL, LOG_INFO, "NSM[%s:%s]: Timer (hello-reply timer expire)",
+ IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
+
+ ospf_hello_send_sub (nbr->oi, &nbr->address.u.prefix4);
+
+ return 0;
+}
+
+/* Send OSPF Hello. */
+void
+ospf_hello_send (struct ospf_interface *oi)
+{
+ struct ospf_packet *op;
+ u_int16_t length = OSPF_HEADER_SIZE;
+
+ /* If this is passive interface, do not send OSPF Hello. */
+ if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE)
+ return;
+
+ op = ospf_packet_new (oi->ifp->mtu);
+
+ /* Prepare OSPF common header. */
+ ospf_make_header (OSPF_MSG_HELLO, oi, op->s);
+
+ /* Prepare OSPF Hello body. */
+ length += ospf_make_hello (oi, op->s);
+
+ /* Fill OSPF header. */
+ ospf_fill_header (oi, op->s, length);
+
+ /* Set packet length. */
+ op->length = length;
+
+ if (oi->type == OSPF_IFTYPE_NBMA)
+ {
+ struct ospf_neighbor *nbr;
+ struct route_node *rn;
+
+ for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+ if ((nbr = rn->info))
+ if (nbr != oi->nbr_self)
+ if (nbr->state != NSM_Down)
+ {
+ /* RFC 2328 Section 9.5.1
+ If the router is not eligible to become Designated Router,
+ it must periodically send Hello Packets to both the
+ Designated Router and the Backup Designated Router (if they
+ exist). */
+ if (PRIORITY(oi) == 0 &&
+ IPV4_ADDR_CMP(&DR(oi), &nbr->address.u.prefix4) &&
+ IPV4_ADDR_CMP(&BDR(oi), &nbr->address.u.prefix4))
+ continue;
+
+ /* If the router is eligible to become Designated Router, it
+ must periodically send Hello Packets to all neighbors that
+ are also eligible. In addition, if the router is itself the
+ Designated Router or Backup Designated Router, it must also
+ send periodic Hello Packets to all other neighbors. */
+
+ if (nbr->priority == 0 && oi->state == ISM_DROther)
+ continue;
+ /* if oi->state == Waiting, send hello to all neighbors */
+ {
+ struct ospf_packet *op_dup;
+
+ op_dup = ospf_packet_dup(op);
+ op_dup->dst = nbr->address.u.prefix4;
+
+ /* Add packet to the interface output queue. */
+ ospf_packet_add (oi, op_dup);
+
+ OSPF_ISM_WRITE_ON ();
+ }
+
+ }
+ ospf_packet_free (op);
+ }
+ else
+ {
+ /* Decide destination address. */
+ if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ op->dst.s_addr = oi->vl_data->peer_addr.s_addr;
+ else
+ op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
+
+ /* Add packet to the interface output queue. */
+ ospf_packet_add (oi, op);
+
+ /* Hook thread to write packet. */
+ OSPF_ISM_WRITE_ON ();
+ }
+}
+
+/* Send OSPF Database Description. */
+void
+ospf_db_desc_send (struct ospf_neighbor *nbr)
+{
+ struct ospf_interface *oi;
+ struct ospf_packet *op;
+ u_int16_t length = OSPF_HEADER_SIZE;
+
+ oi = nbr->oi;
+ op = ospf_packet_new (oi->ifp->mtu);
+
+ /* Prepare OSPF common header. */
+ ospf_make_header (OSPF_MSG_DB_DESC, oi, op->s);
+
+ /* Prepare OSPF Database Description body. */
+ length += ospf_make_db_desc (oi, nbr, op->s);
+
+ /* Fill OSPF header. */
+ ospf_fill_header (oi, op->s, length);
+
+ /* Set packet length. */
+ op->length = length;
+
+ /* Decide destination address. */
+ op->dst = nbr->address.u.prefix4;
+
+ /* Add packet to the interface output queue. */
+ ospf_packet_add (oi, op);
+
+ /* Hook thread to write packet. */
+ OSPF_ISM_WRITE_ON ();
+
+ /* Remove old DD packet, then copy new one and keep in neighbor structure. */
+ if (nbr->last_send)
+ ospf_packet_free (nbr->last_send);
+ nbr->last_send = ospf_packet_dup (op);
+ gettimeofday (&nbr->last_send_ts, NULL);
+}
+
+/* Re-send Database Description. */
+void
+ospf_db_desc_resend (struct ospf_neighbor *nbr)
+{
+ struct ospf_interface *oi;
+
+ oi = nbr->oi;
+
+ /* Add packet to the interface output queue. */
+ ospf_packet_add (oi, ospf_packet_dup (nbr->last_send));
+
+ /* Hook thread to write packet. */
+ OSPF_ISM_WRITE_ON ();
+}
+
+/* Send Link State Request. */
+void
+ospf_ls_req_send (struct ospf_neighbor *nbr)
+{
+ struct ospf_interface *oi;
+ struct ospf_packet *op;
+ u_int16_t length = OSPF_HEADER_SIZE;
+
+ oi = nbr->oi;
+ op = ospf_packet_new (oi->ifp->mtu);
+
+ /* Prepare OSPF common header. */
+ ospf_make_header (OSPF_MSG_LS_REQ, oi, op->s);
+
+ /* Prepare OSPF Link State Request body. */
+ length += ospf_make_ls_req (nbr, op->s);
+ if (length == OSPF_HEADER_SIZE)
+ {
+ ospf_packet_free (op);
+ return;
+ }
+
+ /* Fill OSPF header. */
+ ospf_fill_header (oi, op->s, length);
+
+ /* Set packet length. */
+ op->length = length;
+
+ /* Decide destination address. */
+ op->dst = nbr->address.u.prefix4;
+
+ /* Add packet to the interface output queue. */
+ ospf_packet_add (oi, op);
+
+ /* Hook thread to write packet. */
+ OSPF_ISM_WRITE_ON ();
+
+ /* Add Link State Request Retransmission Timer. */
+ OSPF_NSM_TIMER_ON (nbr->t_ls_req, ospf_ls_req_timer, nbr->v_ls_req);
+}
+
+/* Send Link State Update with an LSA. */
+void
+ospf_ls_upd_send_lsa (struct ospf_neighbor *nbr, struct ospf_lsa *lsa,
+ int flag)
+{
+ list update;
+
+ update = list_new ();
+
+ listnode_add (update, lsa);
+ ospf_ls_upd_send (nbr, update, flag);
+
+ list_delete (update);
+}
+
+static void
+ospf_ls_upd_queue_send (struct ospf_interface *oi, list update,
+ struct in_addr addr)
+{
+ struct ospf_packet *op;
+ u_int16_t length = OSPF_HEADER_SIZE;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("listcount = %d, dst %s", listcount (update), inet_ntoa(addr));
+
+ op = ospf_packet_new (oi->ifp->mtu);
+
+ /* Prepare OSPF common header. */
+ ospf_make_header (OSPF_MSG_LS_UPD, oi, op->s);
+
+ /* Prepare OSPF Link State Update body. */
+ /* Includes Type-7 translation. */
+ length += ospf_make_ls_upd (oi, update, op->s);
+
+ /* Fill OSPF header. */
+ ospf_fill_header (oi, op->s, length);
+
+ /* Set packet length. */
+ op->length = length;
+
+ /* Decide destination address. */
+ op->dst.s_addr = addr.s_addr;
+
+ /* Add packet to the interface output queue. */
+ ospf_packet_add (oi, op);
+
+ /* Hook thread to write packet. */
+ OSPF_ISM_WRITE_ON ();
+}
+
+static int
+ospf_ls_upd_send_queue_event (struct thread *thread)
+{
+ struct ospf_interface *oi = THREAD_ARG(thread);
+ struct route_node *rn;
+
+ oi->t_ls_upd_event = NULL;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_ls_upd_send_queue start");
+
+ for (rn = route_top (oi->ls_upd_queue); rn; rn = route_next (rn))
+ {
+ if (rn->info == NULL)
+ continue;
+
+ while (!list_isempty ((list)rn->info))
+ ospf_ls_upd_queue_send (oi, rn->info, rn->p.u.prefix4);
+
+ list_delete (rn->info);
+ rn->info = NULL;
+
+ route_unlock_node (rn);
+ }
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_ls_upd_send_queue stop");
+ return 0;
+}
+
+void
+ospf_ls_upd_send (struct ospf_neighbor *nbr, list update, int flag)
+{
+ struct ospf_interface *oi;
+ struct prefix_ipv4 p;
+ struct route_node *rn;
+ listnode n;
+
+ oi = nbr->oi;
+
+ p.family = AF_INET;
+ p.prefixlen = IPV4_MAX_BITLEN;
+
+ /* Decide destination address. */
+ if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ p.prefix = oi->vl_data->peer_addr;
+ else if (flag == OSPF_SEND_PACKET_DIRECT)
+ p.prefix = nbr->address.u.prefix4;
+ else if (oi->state == ISM_DR || oi->state == ISM_Backup)
+ p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS);
+ else if ((oi->type == OSPF_IFTYPE_POINTOPOINT)
+ && (flag == OSPF_SEND_PACKET_INDIRECT))
+ p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS);
+ else
+ p.prefix.s_addr = htonl (OSPF_ALLDROUTERS);
+
+ if (oi->type == OSPF_IFTYPE_NBMA)
+ {
+ if (flag == OSPF_SEND_PACKET_INDIRECT)
+ zlog_warn ("* LS-Update is directly sent on NBMA network.");
+ if (IPV4_ADDR_SAME(&oi->address->u.prefix4, &p.prefix.s_addr))
+ zlog_warn ("* LS-Update is sent to myself.");
+ }
+
+ rn = route_node_get (oi->ls_upd_queue, (struct prefix *) &p);
+
+ if (rn->info == NULL)
+ rn->info = list_new ();
+
+ for (n = listhead (update); n; nextnode (n))
+ listnode_add (rn->info, ospf_lsa_lock (getdata (n)));
+
+ if (oi->t_ls_upd_event == NULL)
+ oi->t_ls_upd_event =
+ thread_add_event (master, ospf_ls_upd_send_queue_event, oi, 0);
+}
+
+static void
+ospf_ls_ack_send_list (struct ospf_interface *oi, list ack, struct in_addr dst)
+{
+ struct ospf_packet *op;
+ u_int16_t length = OSPF_HEADER_SIZE;
+
+ op = ospf_packet_new (oi->ifp->mtu);
+
+ /* Prepare OSPF common header. */
+ ospf_make_header (OSPF_MSG_LS_ACK, oi, op->s);
+
+ /* Prepare OSPF Link State Acknowledgment body. */
+ length += ospf_make_ls_ack (oi, ack, op->s);
+
+ /* Fill OSPF header. */
+ ospf_fill_header (oi, op->s, length);
+
+ /* Set packet length. */
+ op->length = length;
+
+ /* Set destination IP address. */
+ op->dst = dst;
+
+ /* Add packet to the interface output queue. */
+ ospf_packet_add (oi, op);
+
+ /* Hook thread to write packet. */
+ OSPF_ISM_WRITE_ON ();
+}
+
+static int
+ospf_ls_ack_send_event (struct thread *thread)
+{
+ struct ospf_interface *oi = THREAD_ARG (thread);
+
+ oi->t_ls_ack_direct = NULL;
+
+ while (listcount (oi->ls_ack_direct.ls_ack))
+ ospf_ls_ack_send_list (oi, oi->ls_ack_direct.ls_ack,
+ oi->ls_ack_direct.dst);
+
+ return 0;
+}
+
+void
+ospf_ls_ack_send (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
+{
+ struct ospf_interface *oi = nbr->oi;
+
+ if (listcount (oi->ls_ack_direct.ls_ack) == 0)
+ oi->ls_ack_direct.dst = nbr->address.u.prefix4;
+
+ listnode_add (oi->ls_ack_direct.ls_ack, ospf_lsa_lock (lsa));
+
+ if (oi->t_ls_ack_direct == NULL)
+ oi->t_ls_ack_direct =
+ thread_add_event (master, ospf_ls_ack_send_event, oi, 0);
+}
+
+/* Send Link State Acknowledgment delayed. */
+void
+ospf_ls_ack_send_delayed (struct ospf_interface *oi)
+{
+ struct in_addr dst;
+
+ /* Decide destination address. */
+ /* RFC2328 Section 13.5 On non-broadcast
+ networks, delayed Link State Acknowledgment packets must be
+ unicast separately over each adjacency (i.e., neighbor whose
+ state is >= Exchange). */
+ if (oi->type == OSPF_IFTYPE_NBMA)
+ {
+ struct ospf_neighbor *nbr;
+ struct route_node *rn;
+
+ for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+ if ((nbr = rn->info) != NULL)
+ if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange)
+ while (listcount (oi->ls_ack))
+ ospf_ls_ack_send_list (oi, oi->ls_ack, nbr->address.u.prefix4);
+ return;
+ }
+ if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ dst.s_addr = oi->vl_data->peer_addr.s_addr;
+ else if (oi->state == ISM_DR || oi->state == ISM_Backup)
+ dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
+ else if (oi->type == OSPF_IFTYPE_POINTOPOINT)
+ dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
+ else
+ dst.s_addr = htonl (OSPF_ALLDROUTERS);
+
+ while (listcount (oi->ls_ack))
+ ospf_ls_ack_send_list (oi, oi->ls_ack, dst);
+}
diff --git a/ospfd/ospf_packet.h b/ospfd/ospf_packet.h
new file mode 100644
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 <zebra.h>
+
+#include "prefix.h"
+#include "table.h"
+#include "memory.h"
+#include "linklist.h"
+#include "log.h"
+#include "if.h"
+#include "command.h"
+#include "sockunion.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_dump.h"
+
+struct ospf_route *
+ospf_route_new ()
+{
+ struct ospf_route *new;
+
+ new = XCALLOC (MTYPE_OSPF_ROUTE, sizeof (struct ospf_route));
+
+ new->ctime = time (NULL);
+ new->mtime = new->ctime;
+
+ return new;
+}
+
+void
+ospf_route_free (struct ospf_route *or)
+{
+ listnode node;
+
+ if (or->path)
+ {
+ for (node = listhead (or->path); node; nextnode (node))
+ ospf_path_free (node->data);
+
+ list_delete (or->path);
+ }
+
+ XFREE (MTYPE_OSPF_ROUTE, or);
+}
+
+struct ospf_path *
+ospf_path_new ()
+{
+ struct ospf_path *new;
+
+ new = XCALLOC (MTYPE_OSPF_PATH, sizeof (struct ospf_path));
+
+ return new;
+}
+
+struct ospf_path *
+ospf_path_dup (struct ospf_path *path)
+{
+ struct ospf_path *new;
+
+ new = ospf_path_new ();
+ memcpy (new, path, sizeof (struct ospf_path));
+
+ return new;
+}
+
+void
+ospf_path_free (struct ospf_path *op)
+{
+ XFREE (MTYPE_OSPF_PATH, op);
+}
+
+void
+ospf_route_delete (struct route_table *rt)
+{
+ struct route_node *rn;
+ struct ospf_route *or;
+
+ for (rn = route_top (rt); rn; rn = route_next (rn))
+ if ((or = rn->info) != NULL)
+ {
+ if (or->type == OSPF_DESTINATION_NETWORK)
+ ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p,
+ or);
+ else if (or->type == OSPF_DESTINATION_DISCARD)
+ ospf_zebra_delete_discard ((struct prefix_ipv4 *) &rn->p);
+ }
+}
+
+void
+ospf_route_table_free (struct route_table *rt)
+{
+ struct route_node *rn;
+ struct ospf_route *or;
+
+ for (rn = route_top (rt); rn; rn = route_next (rn))
+ if ((or = rn->info) != NULL)
+ {
+ ospf_route_free (or);
+
+ rn->info = NULL;
+ route_unlock_node (rn);
+ }
+
+ route_table_finish (rt);
+}
+
+/* If a prefix and a nexthop match any route in the routing table,
+ then return 1, otherwise return 0. */
+int
+ospf_route_match_same (struct route_table *rt, struct prefix_ipv4 *prefix,
+ struct ospf_route *newor)
+{
+ struct route_node *rn;
+ struct ospf_route *or;
+ struct ospf_path *op;
+ struct ospf_path *newop;
+ listnode n1;
+ listnode n2;
+
+ if (! rt || ! prefix)
+ return 0;
+
+ rn = route_node_lookup (rt, (struct prefix *) prefix);
+ if (! rn || ! rn->info)
+ return 0;
+
+ route_unlock_node (rn);
+
+ or = rn->info;
+ if (or->type == newor->type && or->cost == newor->cost)
+ {
+ if (or->type == OSPF_DESTINATION_NETWORK)
+ {
+ if (or->path->count != newor->path->count)
+ return 0;
+
+ /* Check each path. */
+ for (n1 = listhead (or->path), n2 = listhead (newor->path);
+ n1 && n2; nextnode (n1), nextnode (n2))
+ {
+ op = getdata (n1);
+ newop = getdata (n2);
+
+ if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop))
+ return 0;
+ }
+ return 1;
+ }
+ else if (prefix_same (&rn->p, (struct prefix *) prefix))
+ return 1;
+ }
+ return 0;
+}
+
+/* rt: Old, cmprt: New */
+void
+ospf_route_delete_uniq (struct route_table *rt, struct route_table *cmprt)
+{
+ struct route_node *rn;
+ struct ospf_route *or;
+
+ for (rn = route_top (rt); rn; rn = route_next (rn))
+ if ((or = rn->info) != NULL)
+ if (or->path_type == OSPF_PATH_INTRA_AREA ||
+ or->path_type == OSPF_PATH_INTER_AREA)
+ {
+ if (or->type == OSPF_DESTINATION_NETWORK)
+ {
+ if (! ospf_route_match_same (cmprt,
+ (struct prefix_ipv4 *) &rn->p, or))
+ ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
+ }
+ else if (or->type == OSPF_DESTINATION_DISCARD)
+ if (! ospf_route_match_same (cmprt,
+ (struct prefix_ipv4 *) &rn->p, or))
+ ospf_zebra_delete_discard ((struct prefix_ipv4 *) &rn->p);
+ }
+}
+
+/* Install routes to table. */
+void
+ospf_route_install (struct route_table *rt)
+{
+ struct route_node *rn;
+ struct ospf_route *or;
+
+ /* rt contains new routing table, new_table contains an old one.
+ updating pointers */
+ if (ospf_top->old_table)
+ ospf_route_table_free (ospf_top->old_table);
+
+ ospf_top->old_table = ospf_top->new_table;
+ ospf_top->new_table = rt;
+
+ /* Delete old routes. */
+ if (ospf_top->old_table)
+ ospf_route_delete_uniq (ospf_top->old_table, rt);
+
+ /* Install new routes. */
+ for (rn = route_top (rt); rn; rn = route_next (rn))
+ if ((or = rn->info) != NULL)
+ {
+ if (or->type == OSPF_DESTINATION_NETWORK)
+ {
+ if (! ospf_route_match_same (ospf_top->old_table,
+ (struct prefix_ipv4 *)&rn->p, or))
+ ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or);
+ }
+ else if (or->type == OSPF_DESTINATION_DISCARD)
+ if (! ospf_route_match_same (ospf_top->old_table,
+ (struct prefix_ipv4 *) &rn->p, or))
+ ospf_zebra_add_discard ((struct prefix_ipv4 *) &rn->p);
+ }
+}
+
+void
+ospf_intra_route_add (struct route_table *rt, struct vertex *v,
+ struct ospf_area *area)
+{
+ struct route_node *rn;
+ struct ospf_route *or;
+ struct prefix_ipv4 p;
+ struct ospf_path *path;
+ struct vertex_nexthop *nexthop;
+ listnode nnode;
+
+ p.family = AF_INET;
+ p.prefix = v->id;
+ if (v->type == OSPF_VERTEX_ROUTER)
+ p.prefixlen = IPV4_MAX_BITLEN;
+ else
+ {
+ struct network_lsa *lsa = (struct network_lsa *) v->lsa;
+ p.prefixlen = ip_masklen (lsa->mask);
+ }
+ apply_mask_ipv4 (&p);
+
+ rn = route_node_get (rt, (struct prefix *) &p);
+ if (rn->info)
+ {
+ zlog_warn ("Same routing information exists for %s", inet_ntoa (v->id));
+ route_unlock_node (rn);
+ return;
+ }
+
+ or = ospf_route_new ();
+
+ if (v->type == OSPF_VERTEX_NETWORK)
+ {
+ or->type = OSPF_DESTINATION_NETWORK;
+ or->path = list_new ();
+
+ for (nnode = listhead (v->nexthop); nnode; nextnode (nnode))
+ {
+ nexthop = getdata (nnode);
+ path = ospf_path_new ();
+ path->nexthop = nexthop->router;
+ listnode_add (or->path, path);
+ }
+ }
+ else
+ or->type = OSPF_DESTINATION_ROUTER;
+
+ or->id = v->id;
+ or->u.std.area_id = area->area_id;
+#ifdef HAVE_NSSA
+ or->u.std.external_routing= area->external_routing;
+#endif /* HAVE_NSSA */
+ or->path_type = OSPF_PATH_INTRA_AREA;
+ or->cost = v->distance;
+
+ rn->info = or;
+}
+
+/* RFC2328 16.1. (4). For "router". */
+void
+ospf_intra_add_router (struct route_table *rt, struct vertex *v,
+ struct ospf_area *area)
+{
+ struct route_node *rn;
+ struct ospf_route *or;
+ struct prefix_ipv4 p;
+ struct router_lsa *lsa;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_intra_add_router: Start");
+
+ lsa = (struct router_lsa *) v->lsa;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_intra_add_router: LS ID: %s",
+ inet_ntoa (lsa->header.id));
+
+ ospf_vl_up_check (area, lsa->header.id, v);
+
+ if (!CHECK_FLAG (lsa->flags, ROUTER_LSA_SHORTCUT))
+ area->shortcut_capability = 0;
+
+ /* If the newly added vertex is an area border router or AS boundary
+ router, a routing table entry is added whose destination type is
+ "router". */
+ if (! IS_ROUTER_LSA_BORDER (lsa) && ! IS_ROUTER_LSA_EXTERNAL (lsa))
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_intra_add_router: "
+ "this router is neither ASBR nor ABR, skipping it");
+ return;
+ }
+
+ /* Update ABR and ASBR count in this area. */
+ if (IS_ROUTER_LSA_BORDER (lsa))
+ area->abr_count++;
+ if (IS_ROUTER_LSA_EXTERNAL (lsa))
+ area->asbr_count++;
+
+ /* The Options field found in the associated router-LSA is copied
+ into the routing table entry's Optional capabilities field. Call
+ the newly added vertex Router X. */
+ or = ospf_route_new ();
+
+ or->id = v->id;
+ or->u.std.area_id = area->area_id;
+#ifdef HAVE_NSSA
+ or->u.std.external_routing = area->external_routing;
+#endif /* HAVE_NSSA */
+ or->path_type = OSPF_PATH_INTRA_AREA;
+ or->cost = v->distance;
+ or->type = OSPF_DESTINATION_ROUTER;
+ or->u.std.origin = (struct lsa_header *) lsa;
+ or->u.std.options = lsa->header.options;
+ or->u.std.flags = lsa->flags;
+
+ /* If Router X is the endpoint of one of the calculating router's
+ virtual links, and the virtual link uses Area A as Transit area:
+ the virtual link is declared up, the IP address of the virtual
+ interface is set to the IP address of the outgoing interface
+ calculated above for Router X, and the virtual neighbor's IP
+ address is set to Router X's interface address (contained in
+ Router X's router-LSA) that points back to the root of the
+ shortest- path tree; equivalently, this is the interface that
+ points back to Router X's parent vertex on the shortest-path tree
+ (similar to the calculation in Section 16.1.1). */
+
+ p.family = AF_INET;
+ p.prefix = v->id;
+ p.prefixlen = IPV4_MAX_BITLEN;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_intra_add_router: talking about %s/%d",
+ inet_ntoa (p.prefix), p.prefixlen);
+
+ rn = route_node_get (rt, (struct prefix *) &p);
+
+ /* Note that we keep all routes to ABRs and ASBRs, not only the best */
+ if (rn->info == NULL)
+ rn->info = list_new ();
+ else
+ route_unlock_node (rn);
+
+ ospf_route_copy_nexthops_from_vertex (or, v);
+
+ listnode_add (rn->info, or);
+
+ zlog_info ("ospf_intra_add_router: Start");
+}
+
+/* RFC2328 16.1. (4). For transit network. */
+void
+ospf_intra_add_transit (struct route_table *rt, struct vertex *v,
+ struct ospf_area *area)
+{
+ struct route_node *rn;
+ struct ospf_route *or;
+ struct prefix_ipv4 p;
+ struct network_lsa *lsa;
+
+ lsa = (struct network_lsa*) v->lsa;
+
+ /* If the newly added vertex is a transit network, the routing table
+ entry for the network is located. The entry's Destination ID is
+ the IP network number, which can be obtained by masking the
+ Vertex ID (Link State ID) with its associated subnet mask (found
+ in the body of the associated network-LSA). */
+ p.family = AF_INET;
+ p.prefix = v->id;
+ p.prefixlen = ip_masklen (lsa->mask);
+ apply_mask_ipv4 (&p);
+
+ rn = route_node_get (rt, (struct prefix *) &p);
+
+ /* If the routing table entry already exists (i.e., there is already
+ an intra-area route to the destination installed in the routing
+ table), multiple vertices have mapped to the same IP network.
+ For example, this can occur when a new Designated Router is being
+ established. In this case, the current routing table entry
+ should be overwritten if and only if the newly found path is just
+ as short and the current routing table entry's Link State Origin
+ has a smaller Link State ID than the newly added vertex' LSA. */
+ if (rn->info)
+ {
+ struct ospf_route *cur_or;
+
+ route_unlock_node (rn);
+ cur_or = rn->info;
+
+ if (v->distance > cur_or->cost ||
+ IPV4_ADDR_CMP (&cur_or->u.std.origin->id, &lsa->header.id) > 0)
+ return;
+
+ ospf_route_free (rn->info);
+ }
+
+ or = ospf_route_new ();
+
+ or->id = v->id;
+ or->u.std.area_id = area->area_id;
+#ifdef HAVE_NSSA
+ or->u.std.external_routing = area->external_routing;
+#endif /* HAVE_NSSA */
+ or->path_type = OSPF_PATH_INTRA_AREA;
+ or->cost = v->distance;
+ or->type = OSPF_DESTINATION_NETWORK;
+ or->u.std.origin = (struct lsa_header *) lsa;
+
+ ospf_route_copy_nexthops_from_vertex (or, v);
+
+ rn->info = or;
+}
+
+/* RFC2328 16.1. second stage. */
+void
+ospf_intra_add_stub (struct route_table *rt, struct router_lsa_link *link,
+ struct vertex *v, struct ospf_area *area)
+{
+ u_int32_t cost;
+ struct route_node *rn;
+ struct ospf_route *or;
+ struct prefix_ipv4 p;
+ struct router_lsa *lsa;
+ struct ospf_interface *oi;
+ struct ospf_path *path;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_intra_add_stub(): Start");
+
+ lsa = (struct router_lsa *) v->lsa;
+
+ p.family = AF_INET;
+ p.prefix = link->link_id;
+ p.prefixlen = ip_masklen (link->link_data);
+ apply_mask_ipv4 (&p);
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_intra_add_stub(): processing route to %s/%d",
+ inet_ntoa (p.prefix), p.prefixlen);
+
+ /* (1) Calculate the distance D of stub network from the root. D is
+ equal to the distance from the root to the router vertex
+ (calculated in stage 1), plus the stub network link's advertised
+ cost. */
+ cost = v->distance + ntohs (link->m[0].metric);
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_intra_add_stub(): calculated cost is %d + %d = %d",
+ v->distance, ntohs(link->m[0].metric), cost);
+
+ rn = route_node_get (rt, (struct prefix *) &p);
+
+ /* Lookup current routing table. */
+ if (rn->info)
+ {
+ struct ospf_route *cur_or;
+
+ route_unlock_node (rn);
+
+ cur_or = rn->info;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_intra_add_stub(): "
+ "another route to the same prefix found");
+
+ /* Compare this distance to the current best cost to the stub
+ network. This is done by looking up the stub network's
+ current routing table entry. If the calculated distance D is
+ larger, go on to examine the next stub network link in the
+ LSA. */
+ if (cost > cur_or->cost)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_intra_add_stub(): old route is better, exit");
+ return;
+ }
+
+ /* (2) If this step is reached, the stub network's routing table
+ entry must be updated. Calculate the set of next hops that
+ would result from using the stub network link. This
+ calculation is shown in Section 16.1.1; input to this
+ calculation is the destination (the stub network) and the
+ parent vertex (the router vertex). If the distance D is the
+ same as the current routing table cost, simply add this set
+ of next hops to the routing table entry's list of next hops.
+ In this case, the routing table already has a Link State
+ Origin. If this Link State Origin is a router-LSA whose Link
+ State ID is smaller than V's Router ID, reset the Link State
+ Origin to V's router-LSA. */
+
+ if (cost == cur_or->cost)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_intra_add_stub(): routes are equal, merge");
+
+ ospf_route_copy_nexthops_from_vertex (cur_or, v);
+
+ if (IPV4_ADDR_CMP (&cur_or->u.std.origin->id, &lsa->header.id) < 0)
+ cur_or->u.std.origin = (struct lsa_header *) lsa;
+ return;
+ }
+
+ /* Otherwise D is smaller than the routing table cost.
+ Overwrite the current routing table entry by setting the
+ routing table entry's cost to D, and by setting the entry's
+ list of next hops to the newly calculated set. Set the
+ routing table entry's Link State Origin to V's router-LSA.
+ Then go on to examine the next stub network link. */
+
+ if (cost < cur_or->cost)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_intra_add_stub(): new route is better, set it");
+
+ cur_or->cost = cost;
+
+ list_delete (cur_or->path);
+ cur_or->path = NULL;
+
+ ospf_route_copy_nexthops_from_vertex (cur_or, v);
+
+ cur_or->u.std.origin = (struct lsa_header *) lsa;
+ return;
+ }
+ }
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_intra_add_stub(): installing new route");
+
+ or = ospf_route_new ();
+
+ or->id = v->id;
+ or->u.std.area_id = area->area_id;
+#ifdef HAVE_NSSA
+ or->u.std.external_routing = area->external_routing;
+#endif /* HAVE_NSSA */
+ or->path_type = OSPF_PATH_INTRA_AREA;
+ or->cost = cost;
+ or->type = OSPF_DESTINATION_NETWORK;
+ or->u.std.origin = (struct lsa_header *) lsa;
+ or->path = list_new ();
+
+ /* Nexthop is depend on connection type. */
+ if (v != area->spf)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_intra_add_stub(): this network is on remote router");
+ ospf_route_copy_nexthops_from_vertex (or, v);
+ }
+ else
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_intra_add_stub(): this network is on this router");
+
+ if ((oi = ospf_if_lookup_by_prefix (&p)))
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_intra_add_stub(): the interface is %s",
+ IF_NAME (oi));
+
+ path = ospf_path_new ();
+ path->nexthop.s_addr = 0;
+ path->oi = oi;
+ listnode_add (or->path, path);
+ }
+ else
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_intra_add_stub(): where's the interface ?");
+ }
+ }
+
+ rn->info = or;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info("ospf_intra_add_stub(): Stop");
+}
+
+char *ospf_path_type_str[] =
+{
+ "unknown-type",
+ "intra-area",
+ "inter-area",
+ "type1-external",
+ "type2-external"
+};
+
+void
+ospf_route_table_dump (struct route_table *rt)
+{
+ struct route_node *rn;
+ struct ospf_route *or;
+ char buf1[BUFSIZ];
+ char buf2[BUFSIZ];
+ listnode pnode;
+ struct ospf_path *path;
+
+#if 0
+ zlog_info ("Type Dest Area Path Type Cost Next Adv.");
+ zlog_info (" Hop(s) Router(s)");
+#endif /* 0 */
+
+ zlog_info ("========== OSPF routing table ==========");
+ for (rn = route_top (rt); rn; rn = route_next (rn))
+ if ((or = rn->info) != NULL)
+ {
+ if (or->type == OSPF_DESTINATION_NETWORK)
+ {
+ zlog_info ("N %s/%d\t%s\t%s\t%d",
+ inet_ntop (AF_INET, &rn->p.u.prefix4, buf1, BUFSIZ),
+ rn->p.prefixlen,
+ inet_ntop (AF_INET, &or->u.std.area_id, buf2,
+ BUFSIZ),
+ ospf_path_type_str[or->path_type],
+ or->cost);
+ for (pnode = listhead (or->path); pnode; nextnode (pnode))
+ {
+ path = getdata (pnode);
+ zlog_info (" -> %s", inet_ntoa (path->nexthop));
+ }
+ }
+ else
+ zlog_info ("R %s\t%s\t%s\t%d",
+ inet_ntop (AF_INET, &rn->p.u.prefix4, buf1, BUFSIZ),
+ inet_ntop (AF_INET, &or->u.std.area_id, buf2,
+ BUFSIZ),
+ ospf_path_type_str[or->path_type],
+ or->cost);
+ }
+ zlog_info ("========================================");
+}
+
+void
+ospf_terminate ()
+{
+ if (ospf_top)
+ {
+ if (ospf_top->new_table)
+ ospf_route_delete (ospf_top->new_table);
+ if (ospf_top->old_external_route)
+ ospf_route_delete (ospf_top->old_external_route);
+ }
+}
+
+/* This is 16.4.1 implementation.
+ o Intra-area paths using non-backbone areas are always the most preferred.
+ o The other paths, intra-area backbone paths and inter-area paths,
+ are of equal preference. */
+int
+ospf_asbr_route_cmp (struct ospf_route *r1, struct ospf_route *r2)
+{
+ u_char r1_type, r2_type;
+
+ r1_type = r1->path_type;
+ r2_type = r2->path_type;
+
+ /* If RFC1583Compat flag is on -- all paths are equal. */
+ if (CHECK_FLAG (ospf_top->config, OSPF_RFC1583_COMPATIBLE))
+ return 0;
+
+ /* r1/r2 itself is backbone, and it's Inter-area path. */
+ if (OSPF_IS_AREA_ID_BACKBONE (r1->u.std.area_id))
+ r1_type = OSPF_PATH_INTER_AREA;
+ if (OSPF_IS_AREA_ID_BACKBONE (r2->u.std.area_id))
+ r2_type = OSPF_PATH_INTER_AREA;
+
+ return (r1_type - r2_type);
+}
+
+/* Compare two routes.
+ ret < 0 -- r1 is better.
+ ret == 0 -- r1 and r2 are the same.
+ ret > 0 -- r2 is better. */
+int
+ospf_route_cmp (struct ospf_route *r1, struct ospf_route *r2)
+{
+ int ret = 0;
+
+ /* Path types of r1 and r2 are not the same. */
+ if ((ret = (r1->path_type - r2->path_type)))
+ return ret;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Route[Compare]: Path types are the same.");
+ /* Path types are the same, compare any cost. */
+ switch (r1->path_type)
+ {
+ case OSPF_PATH_INTRA_AREA:
+ case OSPF_PATH_INTER_AREA:
+ break;
+ case OSPF_PATH_TYPE1_EXTERNAL:
+ if (!CHECK_FLAG (ospf_top->config, OSPF_RFC1583_COMPATIBLE))
+ {
+ ret = ospf_asbr_route_cmp (r1->u.ext.asbr, r2->u.ext.asbr);
+ if (ret != 0)
+ return ret;
+ }
+ break;
+ case OSPF_PATH_TYPE2_EXTERNAL:
+ if ((ret = (r1->u.ext.type2_cost - r2->u.ext.type2_cost)))
+ return ret;
+
+ if (!CHECK_FLAG (ospf_top->config, OSPF_RFC1583_COMPATIBLE))
+ {
+ ret = ospf_asbr_route_cmp (r1->u.ext.asbr, r2->u.ext.asbr);
+ if (ret != 0)
+ return ret;
+ }
+ break;
+ }
+
+ /* Anyway, compare the costs. */
+ return (r1->cost - r2->cost);
+}
+
+int
+ospf_path_exist (struct list *plist, struct in_addr nexthop,
+ struct ospf_interface *oi)
+{
+ listnode node;
+ struct ospf_path *path;
+
+ for (node = listhead (plist); node; nextnode (node))
+ {
+ path = node->data;
+
+ if (IPV4_ADDR_SAME (&path->nexthop, &nexthop) && path->oi == oi)
+ return 1;
+ }
+ return 0;
+}
+
+void
+ospf_route_copy_nexthops_from_vertex (struct ospf_route *to,
+ struct vertex *v)
+{
+ listnode nnode;
+ struct ospf_path *path;
+ struct vertex_nexthop *nexthop;
+
+ if (to->path == NULL)
+ to->path = list_new ();
+
+ for (nnode = listhead (v->nexthop); nnode; nextnode (nnode))
+ {
+ nexthop = getdata (nnode);
+
+ if (nexthop->oi != NULL)
+ {
+ if (! ospf_path_exist (to->path, nexthop->router, nexthop->oi))
+ {
+ path = ospf_path_new ();
+ path->nexthop = nexthop->router;
+ path->oi = nexthop->oi;
+ listnode_add (to->path, path);
+ }
+ }
+ }
+}
+
+struct ospf_path *
+ospf_path_lookup (list plist, struct ospf_path *path)
+{
+ listnode node;
+
+ for (node = listhead (plist); node; nextnode (node))
+ {
+ struct ospf_path *op = node->data;
+
+ if (IPV4_ADDR_SAME (&op->nexthop, &path->nexthop) &&
+ IPV4_ADDR_SAME (&op->adv_router, &path->adv_router))
+ return op;
+ }
+
+ return NULL;
+}
+
+void
+ospf_route_copy_nexthops (struct ospf_route *to, list from)
+{
+ listnode node;
+
+ if (to->path == NULL)
+ to->path = list_new ();
+
+ for (node = listhead (from); node; nextnode (node))
+ /* The same routes are just discarded. */
+ if (!ospf_path_lookup (to->path, node->data))
+ listnode_add (to->path, ospf_path_dup (node->data));
+}
+
+void
+ospf_route_subst_nexthops (struct ospf_route *to, list from)
+{
+ listnode node;
+ struct ospf_path *op;
+
+ for (node = listhead (to->path); node; nextnode (node))
+ if ((op = getdata (node)) != NULL)
+ {
+ ospf_path_free (op);
+ node->data = NULL;
+ }
+
+ list_delete_all_node (to->path);
+ ospf_route_copy_nexthops (to, from);
+}
+
+void
+ospf_route_subst (struct route_node *rn, struct ospf_route *new_or,
+ struct ospf_route *over)
+{
+ route_lock_node (rn);
+ ospf_route_free (rn->info);
+
+ ospf_route_copy_nexthops (new_or, over->path);
+ rn->info = new_or;
+ route_unlock_node (rn);
+}
+
+void
+ospf_route_add (struct route_table *rt, struct prefix_ipv4 *p,
+ struct ospf_route *new_or, struct ospf_route *over)
+{
+ struct route_node *rn;
+
+ rn = route_node_get (rt, (struct prefix *) p);
+
+ ospf_route_copy_nexthops (new_or, over->path);
+
+ if (rn->info)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_route_add(): something's wrong !");
+ route_unlock_node (rn);
+ return;
+ }
+
+ rn->info = new_or;
+}
+
+void
+ospf_prune_unreachable_networks (struct route_table *rt)
+{
+ struct route_node *rn, *next;
+ struct ospf_route *or;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Pruning unreachable networks");
+
+ for (rn = route_top (rt); rn; rn = next)
+ {
+ next = route_next (rn);
+ if (rn->info != NULL)
+ {
+ or = rn->info;
+ if (listcount (or->path) == 0)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Pruning route to %s/%d",
+ inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
+
+ ospf_route_free (or);
+ rn->info = NULL;
+ route_unlock_node (rn);
+ }
+ }
+ }
+}
+
+void
+ospf_prune_unreachable_routers (struct route_table *rtrs)
+{
+ struct route_node *rn, *next;
+ struct ospf_route *or;
+ listnode node, nnext;
+ list paths;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Pruning unreachable routers");
+
+ for (rn = route_top (rtrs); rn; rn = next)
+ {
+ next = route_next (rn);
+ if ((paths = rn->info) == NULL)
+ continue;
+
+ for (node = listhead (paths); node; node = nnext)
+ {
+ nnext = node->next;
+
+ or = getdata (node);
+
+ if (listcount (or->path) == 0)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ {
+ zlog_info ("Pruning route to rtr %s",
+ inet_ntoa (rn->p.u.prefix4));
+ zlog_info (" via area %s",
+ inet_ntoa (or->u.std.area_id));
+ }
+
+ listnode_delete (paths, or);
+ ospf_route_free (or);
+ }
+ }
+
+ if (listcount (paths) == 0)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("Pruning router node %s", inet_ntoa (rn->p.u.prefix4));
+
+ list_delete (paths);
+ rn->info = NULL;
+ route_unlock_node (rn);
+ }
+ }
+}
+
+int
+ospf_add_discard_route (struct route_table *rt, struct ospf_area *area,
+ struct prefix_ipv4 *p)
+{
+ struct route_node *rn;
+ struct ospf_route *or, *new_or;
+
+ rn = route_node_get (rt, (struct prefix *) p);
+
+ if (rn == NULL)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_add_discard_route(): router installation error");
+ return 0;
+ }
+
+ if (rn->info) /* If the route to the same destination is found */
+ {
+ route_unlock_node (rn);
+
+ or = rn->info;
+
+ if (or->path_type == OSPF_PATH_INTRA_AREA)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_add_discard_route(): "
+ "an intra-area route exists");
+ return 0;
+ }
+
+ if (or->type == OSPF_DESTINATION_DISCARD)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_add_discard_route(): "
+ "discard entry already installed");
+ return 0;
+ }
+
+ ospf_route_free (rn->info);
+ }
+
+ new_or = ospf_route_new ();
+ new_or->type = OSPF_DESTINATION_DISCARD;
+ new_or->id.s_addr = 0;
+ new_or->cost = 0;
+ new_or->u.std.area_id = area->area_id;
+#ifdef HAVE_NSSA
+ new_or->u.std.external_routing = area->external_routing;
+#endif /* HAVE_NSSA */
+ new_or->path_type = OSPF_PATH_INTER_AREA;
+ rn->info = new_or;
+
+ ospf_zebra_add_discard (p);
+
+ return 1;
+}
+
+void
+ospf_delete_discard_route (struct prefix_ipv4 *p)
+{
+ ospf_zebra_delete_discard(p);
+}
+
diff --git a/ospfd/ospf_route.h b/ospfd/ospf_route.h
new file mode 100644
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 <zebra.h>
+
+#include "memory.h"
+#include "prefix.h"
+#include "table.h"
+#include "routemap.h"
+#include "command.h"
+#include "log.h"
+#include "plist.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_zebra.h"
+
+/* Hook function for updating route_map assignment. */
+void
+ospf_route_map_update (char *name)
+{
+ int type;
+
+ /* If OSPF instatnce does not exist, return right now. */
+ if (!ospf_top)
+ return;
+
+ /* Update route-map */
+ for (type = 0; type <= ZEBRA_ROUTE_MAX; type++)
+ {
+ if (ROUTEMAP_NAME (type) && strcmp (ROUTEMAP_NAME (type), name) == 0)
+ {
+ /* Keep old route-map. */
+ struct route_map *old = ROUTEMAP (type);
+
+ /* Update route-map. */
+ ROUTEMAP (type) = route_map_lookup_by_name (ROUTEMAP_NAME (type));
+
+ /* No update for this distribute type. */
+ if (old == NULL && ROUTEMAP (type) == NULL)
+ continue;
+
+ ospf_distribute_list_update (type);
+ }
+ }
+}
+
+void
+ospf_route_map_event (route_map_event_t event, char *name)
+{
+ int type;
+
+ /* If OSPF instatnce does not exist, return right now. */
+ if (!ospf_top)
+ return;
+
+ /* Update route-map. */
+ for (type = 0; type <= ZEBRA_ROUTE_MAX; type++)
+ {
+ if (ROUTEMAP_NAME (type) && ROUTEMAP (type) &&
+ !strcmp (ROUTEMAP_NAME (type), name))
+ {
+ ospf_distribute_list_update (type);
+ }
+ }
+}
+
+/* Delete rip route map rule. */
+int
+ospf_route_match_delete (struct vty *vty, struct route_map_index *index,
+ char *command, char *arg)
+{
+ int ret;
+
+ ret = route_map_delete_match (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+int
+ospf_route_match_add (struct vty *vty, struct route_map_index *index,
+ char *command, char *arg)
+{
+ int ret;
+
+ ret = route_map_add_match (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+int
+ospf_route_set_add (struct vty *vty, struct route_map_index *index,
+ char *command, char *arg)
+{
+ int ret;
+
+ ret = route_map_add_set (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+/* Delete rip route map rule. */
+int
+ospf_route_set_delete (struct vty *vty, struct route_map_index *index,
+ char *command, char *arg)
+{
+ int ret;
+
+ ret = route_map_delete_set (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+/* `match ip netxthop ' */
+/* Match function return 1 if match is success else return zero. */
+route_map_result_t
+route_match_ip_nexthop (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct access_list *alist;
+ struct external_info *ei = object;
+ struct prefix_ipv4 p;
+
+ if (type == RMAP_OSPF)
+ {
+ p.family = AF_INET;
+ p.prefix = ei->nexthop;
+ p.prefixlen = IPV4_MAX_BITLEN;
+
+ alist = access_list_lookup (AFI_IP, (char *) rule);
+ if (alist == NULL)
+ return RMAP_NOMATCH;
+
+ return (access_list_apply (alist, &p) == FILTER_DENY ?
+ RMAP_NOMATCH : RMAP_MATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+/* Route map `ip next-hop' match statement. `arg' should be
+ access-list name. */
+void *
+route_match_ip_nexthop_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `ip address' value. */
+void
+route_match_ip_nexthop_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for metric matching. */
+struct route_map_rule_cmd route_match_ip_nexthop_cmd =
+{
+ "ip next-hop",
+ route_match_ip_nexthop,
+ route_match_ip_nexthop_compile,
+ route_match_ip_nexthop_free
+};
+
+/* `match ip next-hop prefix-list PREFIX_LIST' */
+
+route_map_result_t
+route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct prefix_list *plist;
+ struct external_info *ei = object;
+ struct prefix_ipv4 p;
+
+ if (type == RMAP_OSPF)
+ {
+ p.family = AF_INET;
+ p.prefix = ei->nexthop;
+ p.prefixlen = IPV4_MAX_BITLEN;
+
+ plist = prefix_list_lookup (AFI_IP, (char *) rule);
+ if (plist == NULL)
+ return RMAP_NOMATCH;
+
+ return (prefix_list_apply (plist, &p) == PREFIX_DENY ?
+ RMAP_NOMATCH : RMAP_MATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+void *
+route_match_ip_next_hop_prefix_list_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_ip_next_hop_prefix_list_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd =
+{
+ "ip next-hop prefix-list",
+ route_match_ip_next_hop_prefix_list,
+ route_match_ip_next_hop_prefix_list_compile,
+ route_match_ip_next_hop_prefix_list_free
+};
+
+/* `match ip address IP_ACCESS_LIST' */
+/* Match function should return 1 if match is success else return
+ zero. */
+route_map_result_t
+route_match_ip_address (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct access_list *alist;
+ /* struct prefix_ipv4 match; */
+
+ if (type == RMAP_OSPF)
+ {
+ alist = access_list_lookup (AFI_IP, (char *) rule);
+ if (alist == NULL)
+ return RMAP_NOMATCH;
+
+ return (access_list_apply (alist, prefix) == FILTER_DENY ?
+ RMAP_NOMATCH : RMAP_MATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+/* Route map `ip address' match statement. `arg' should be
+ access-list name. */
+void *
+route_match_ip_address_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `ip address' value. */
+void
+route_match_ip_address_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip address matching. */
+struct route_map_rule_cmd route_match_ip_address_cmd =
+{
+ "ip address",
+ route_match_ip_address,
+ route_match_ip_address_compile,
+ route_match_ip_address_free
+};
+
+/* `match ip address prefix-list PREFIX_LIST' */
+route_map_result_t
+route_match_ip_address_prefix_list (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct prefix_list *plist;
+
+ if (type == RMAP_OSPF)
+ {
+ plist = prefix_list_lookup (AFI_IP, (char *) rule);
+ if (plist == NULL)
+ return RMAP_NOMATCH;
+
+ return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
+ RMAP_NOMATCH : RMAP_MATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+void *
+route_match_ip_address_prefix_list_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_ip_address_prefix_list_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd =
+{
+ "ip address prefix-list",
+ route_match_ip_address_prefix_list,
+ route_match_ip_address_prefix_list_compile,
+ route_match_ip_address_prefix_list_free
+};
+
+/* `match interface IFNAME' */
+/* Match function should return 1 if match is success else return
+ zero. */
+route_map_result_t
+route_match_interface (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct interface *ifp;
+ struct external_info *ei;
+
+ if (type == RMAP_OSPF)
+ {
+ ei = object;
+ ifp = if_lookup_by_name ((char *)rule);
+
+ if (ifp == NULL || ifp->ifindex != ei->ifindex)
+ return RMAP_NOMATCH;
+
+ return RMAP_MATCH;
+ }
+ return RMAP_NOMATCH;
+}
+
+/* Route map `interface' match statement. `arg' should be
+ interface name. */
+void *
+route_match_interface_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `interface' value. */
+void
+route_match_interface_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip address matching. */
+struct route_map_rule_cmd route_match_interface_cmd =
+{
+ "interface",
+ route_match_interface,
+ route_match_interface_compile,
+ route_match_interface_free
+};
+
+/* `set metric METRIC' */
+/* Set metric to attribute. */
+route_map_result_t
+route_set_metric (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ u_int32_t *metric;
+ struct external_info *ei;
+
+ if (type == RMAP_OSPF)
+ {
+ /* Fetch routemap's rule information. */
+ metric = rule;
+ ei = object;
+
+ /* Set metric out value. */
+ ei->route_map_set.metric = *metric;
+ }
+ return RMAP_OKAY;
+}
+
+/* set metric compilation. */
+void *
+route_set_metric_compile (char *arg)
+{
+ u_int32_t *metric;
+
+ metric = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+ *metric = atoi (arg);
+
+ if (*metric >= 0)
+ return metric;
+
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, metric);
+ return NULL;
+}
+
+/* Free route map's compiled `set metric' value. */
+void
+route_set_metric_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set metric rule structure. */
+struct route_map_rule_cmd route_set_metric_cmd =
+{
+ "metric",
+ route_set_metric,
+ route_set_metric_compile,
+ route_set_metric_free,
+};
+
+/* `set metric-type TYPE' */
+/* Set metric-type to attribute. */
+route_map_result_t
+route_set_metric_type (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ u_int32_t *metric_type;
+ struct external_info *ei;
+
+ if (type == RMAP_OSPF)
+ {
+ /* Fetch routemap's rule information. */
+ metric_type = rule;
+ ei = object;
+
+ /* Set metric out value. */
+ ei->route_map_set.metric_type = *metric_type;
+ }
+ return RMAP_OKAY;
+}
+
+/* set metric-type compilation. */
+void *
+route_set_metric_type_compile (char *arg)
+{
+ u_int32_t *metric_type;
+
+ metric_type = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+ if (strcmp (arg, "type-1") == 0)
+ *metric_type = EXTERNAL_METRIC_TYPE_1;
+ else if (strcmp (arg, "type-2") == 0)
+ *metric_type = EXTERNAL_METRIC_TYPE_2;
+
+ if (*metric_type == EXTERNAL_METRIC_TYPE_1 ||
+ *metric_type == EXTERNAL_METRIC_TYPE_2)
+ return metric_type;
+
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, metric_type);
+ return NULL;
+}
+
+/* Free route map's compiled `set metric-type' value. */
+void
+route_set_metric_type_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set metric rule structure. */
+struct route_map_rule_cmd route_set_metric_type_cmd =
+{
+ "metric-type",
+ route_set_metric_type,
+ route_set_metric_type_compile,
+ route_set_metric_type_free,
+};
+
+DEFUN (match_ip_nexthop,
+ match_ip_nexthop_cmd,
+ "match ip next-hop (<1-199>|<1300-2699>|WORD)",
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP access-list name\n")
+{
+ return ospf_route_match_add (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+DEFUN (no_match_ip_nexthop,
+ no_match_ip_nexthop_cmd,
+ "no match ip next-hop",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n")
+{
+ if (argc == 0)
+ return ospf_route_match_delete (vty, vty->index, "ip next-hop", NULL);
+
+ return ospf_route_match_delete (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+ALIAS (no_match_ip_nexthop,
+ no_match_ip_nexthop_val_cmd,
+ "no match ip next-hop (<1-199>|<1300-2699>|WORD)",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP access-list name\n")
+
+DEFUN (match_ip_next_hop_prefix_list,
+ match_ip_next_hop_prefix_list_cmd,
+ "match ip next-hop prefix-list WORD",
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ return ospf_route_match_add (vty, vty->index, "ip next-hop prefix-list",
+ argv[0]);
+}
+
+DEFUN (no_match_ip_next_hop_prefix_list,
+ no_match_ip_next_hop_prefix_list_cmd,
+ "no match ip next-hop prefix-list",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "Match entries of prefix-lists\n")
+{
+ if (argc == 0)
+ return ospf_route_match_delete (vty, vty->index, "ip next-hop prefix-list",
+ NULL);
+ return ospf_route_match_delete (vty, vty->index, "ip next-hop prefix-list",
+ argv[0]);
+}
+
+ALIAS (no_match_ip_next_hop_prefix_list,
+ no_match_ip_next_hop_prefix_list_val_cmd,
+ "no match ip next-hop prefix-list WORD",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+
+DEFUN (match_ip_address,
+ match_ip_address_cmd,
+ "match ip address (<1-199>|<1300-2699>|WORD)",
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP access-list name\n")
+{
+ return ospf_route_match_add (vty, vty->index, "ip address", argv[0]);
+}
+
+DEFUN (no_match_ip_address,
+ no_match_ip_address_cmd,
+ "no match ip address",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n")
+{
+ if (argc == 0)
+ return ospf_route_match_delete (vty, vty->index, "ip address", NULL);
+
+ return ospf_route_match_delete (vty, vty->index, "ip address", argv[0]);
+}
+
+ALIAS (no_match_ip_address,
+ no_match_ip_address_val_cmd,
+ "no match ip address (<1-199>|<1300-2699>|WORD)",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP access-list name\n")
+
+DEFUN (match_ip_address_prefix_list,
+ match_ip_address_prefix_list_cmd,
+ "match ip address prefix-list WORD",
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ return ospf_route_match_add (vty, vty->index, "ip address prefix-list",
+ argv[0]);
+}
+
+DEFUN (no_match_ip_address_prefix_list,
+ no_match_ip_address_prefix_list_cmd,
+ "no match ip address prefix-list",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n")
+{
+ if (argc == 0)
+ return ospf_route_match_delete (vty, vty->index, "ip address prefix-list",
+ NULL);
+ return ospf_route_match_delete (vty, vty->index, "ip address prefix-list",
+ argv[0]);
+}
+
+ALIAS (no_match_ip_address_prefix_list,
+ no_match_ip_address_prefix_list_val_cmd,
+ "no match ip address prefix-list WORD",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+
+DEFUN (match_interface,
+ match_interface_cmd,
+ "match interface WORD",
+ MATCH_STR
+ "Match first hop interface of route\n"
+ "Interface name\n")
+{
+ return ospf_route_match_add (vty, vty->index, "interface", argv[0]);
+}
+
+DEFUN (no_match_interface,
+ no_match_interface_cmd,
+ "no match interface",
+ NO_STR
+ MATCH_STR
+ "Match first hop interface of route\n")
+{
+ if (argc == 0)
+ return ospf_route_match_delete (vty, vty->index, "interface", NULL);
+
+ return ospf_route_match_delete (vty, vty->index, "interface", argv[0]);
+}
+
+ALIAS (no_match_interface,
+ no_match_interface_val_cmd,
+ "no match interface WORD",
+ NO_STR
+ MATCH_STR
+ "Match first hop interface of route\n"
+ "Interface name\n")
+
+DEFUN (set_metric,
+ set_metric_cmd,
+ "set metric <0-4294967295>",
+ SET_STR
+ "Metric value for destination routing protocol\n"
+ "Metric value\n")
+{
+ return ospf_route_set_add (vty, vty->index, "metric", argv[0]);
+}
+
+DEFUN (no_set_metric,
+ no_set_metric_cmd,
+ "no set metric",
+ NO_STR
+ SET_STR
+ "Metric value for destination routing protocol\n")
+{
+ if (argc == 0)
+ return ospf_route_set_delete (vty, vty->index, "metric", NULL);
+
+ return ospf_route_set_delete (vty, vty->index, "metric", argv[0]);
+}
+
+ALIAS (no_set_metric,
+ no_set_metric_val_cmd,
+ "no set metric <0-4294967295>",
+ NO_STR
+ SET_STR
+ "Metric value for destination routing protocol\n"
+ "Metric value\n")
+
+DEFUN (set_metric_type,
+ set_metric_type_cmd,
+ "set metric-type (type-1|type-2)",
+ SET_STR
+ "Type of metric for destination routing protocol\n"
+ "OSPF external type 1 metric\n"
+ "OSPF external type 2 metric\n")
+{
+ if (strcmp (argv[0], "1") == 0)
+ return ospf_route_set_add (vty, vty->index, "metric-type", "type-1");
+ if (strcmp (argv[0], "2") == 0)
+ return ospf_route_set_add (vty, vty->index, "metric-type", "type-2");
+
+ return ospf_route_set_add (vty, vty->index, "metric-type", argv[0]);
+}
+
+DEFUN (no_set_metric_type,
+ no_set_metric_type_cmd,
+ "no set metric-type",
+ NO_STR
+ SET_STR
+ "Type of metric for destination routing protocol\n")
+{
+ if (argc == 0)
+ return ospf_route_set_delete (vty, vty->index, "metric-type", NULL);
+
+ return ospf_route_set_delete (vty, vty->index, "metric-type", argv[0]);
+}
+
+ALIAS (no_set_metric_type,
+ no_set_metric_type_val_cmd,
+ "no set metric-type (type-1|type-2)",
+ NO_STR
+ SET_STR
+ "Type of metric for destination routing protocol\n"
+ "OSPF external type 1 metric\n"
+ "OSPF external type 2 metric\n")
+
+/* Route-map init */
+void
+ospf_route_map_init (void)
+{
+ route_map_init ();
+ route_map_init_vty ();
+
+ route_map_add_hook (ospf_route_map_update);
+ route_map_delete_hook (ospf_route_map_update);
+ route_map_event_hook (ospf_route_map_event);
+
+ route_map_install_match (&route_match_ip_nexthop_cmd);
+ route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd);
+ route_map_install_match (&route_match_ip_address_cmd);
+ route_map_install_match (&route_match_ip_address_prefix_list_cmd);
+ route_map_install_match (&route_match_interface_cmd);
+
+ route_map_install_set (&route_set_metric_cmd);
+ route_map_install_set (&route_set_metric_type_cmd);
+
+ install_element (RMAP_NODE, &match_ip_nexthop_cmd);
+ install_element (RMAP_NODE, &no_match_ip_nexthop_cmd);
+ install_element (RMAP_NODE, &no_match_ip_nexthop_val_cmd);
+ install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd);
+ install_element (RMAP_NODE, &match_ip_address_cmd);
+ install_element (RMAP_NODE, &no_match_ip_address_cmd);
+ install_element (RMAP_NODE, &no_match_ip_address_val_cmd);
+ install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd);
+ install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
+ install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd);
+ install_element (RMAP_NODE, &match_interface_cmd);
+ install_element (RMAP_NODE, &no_match_interface_cmd);
+ install_element (RMAP_NODE, &no_match_interface_val_cmd);
+
+ install_element (RMAP_NODE, &set_metric_cmd);
+ install_element (RMAP_NODE, &no_set_metric_cmd);
+ install_element (RMAP_NODE, &no_set_metric_val_cmd);
+ install_element (RMAP_NODE, &set_metric_type_cmd);
+ install_element (RMAP_NODE, &no_set_metric_type_cmd);
+ install_element (RMAP_NODE, &no_set_metric_type_val_cmd);
+}
diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c
new file mode 100644
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 <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#ifdef HAVE_SNMP
+#include <asn1.h>
+#include <snmp.h>
+#include <snmp_impl.h>
+
+#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "table.h"
+#include "command.h"
+#include "memory.h"
+#include "smux.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_flood.h"
+
+/* 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 <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_OSPF_SNMP_H
+#define _ZEBRA_OSPF_SNMP_H
+
+void ospf_snmp_if_update (struct interface *);
+void ospf_snmp_if_delete (struct interface *);
+
+void ospf_snmp_vl_add (struct ospf_vl_data *);
+void ospf_snmp_vl_delete (struct ospf_vl_data *);
+
+#endif /* _ZEBRA_OSPF_SNMP_H */
diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c
new file mode 100644
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 <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "hash.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "log.h"
+#include "sockunion.h" /* for inet_ntop () */
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ia.h"
+#include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospf_dump.h"
+
+#define DEBUG
+
+struct vertex_nexthop *
+vertex_nexthop_new (struct vertex *parent)
+{
+ struct vertex_nexthop *new;
+
+ new = XCALLOC (MTYPE_OSPF_NEXTHOP, sizeof (struct vertex_nexthop));
+ new->parent = parent;
+
+ return new;
+}
+
+void
+vertex_nexthop_free (struct vertex_nexthop *nh)
+{
+ XFREE (MTYPE_OSPF_NEXTHOP, nh);
+}
+
+struct vertex_nexthop *
+vertex_nexthop_dup (struct vertex_nexthop *nh)
+{
+ struct vertex_nexthop *new;
+
+ new = vertex_nexthop_new (nh->parent);
+
+ new->oi = nh->oi;
+ new->router = nh->router;
+
+ return new;
+}
+
+
+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 <zebra.h>
+
+#ifdef HAVE_OSPF_TE
+#ifndef HAVE_OPAQUE_LSA
+#error "Wrong configure option"
+#endif /* HAVE_OPAQUE_LSA */
+
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "memory.h"
+#include "command.h"
+#include "vty.h"
+#include "stream.h"
+#include "log.h"
+#include "thread.h"
+#include "hash.h"
+#include "sockunion.h" /* for inet_aton() */
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_te.h"
+
+/* Following structure are internal use only. */
+struct ospf_mpls_te
+{
+ enum { disabled, enabled } status;
+
+ /* List elements are zebra-interfaces (ifp), not ospf-interfaces (oi). */
+ list iflist;
+
+ /* Store Router-TLV in network byte order. */
+ struct te_tlv_router_addr router_addr;
+};
+
+struct mpls_te_link
+{
+ /*
+ * According to MPLS-TE (draft) specification, 24-bit Opaque-ID field
+ * is subdivided into 8-bit "unused" field and 16-bit "instance" field.
+ * In this implementation, each Link-TLV has its own instance.
+ */
+ u_int32_t instance;
+
+ /* Reference pointer to a Zebra-interface. */
+ struct interface *ifp;
+
+ /* Area info in which this MPLS-TE link belongs to. */
+ struct ospf_area *area;
+
+ /* Flags to manage this link parameters. */
+ u_int32_t flags;
+#define LPFLG_LOOKUP_DONE 0x1
+#define LPFLG_LSA_ENGAGED 0x2
+#define LPFLG_LSA_FORCED_REFRESH 0x4
+
+ /* Store Link-TLV in network byte order. */
+ struct te_tlv_link link_header;
+ struct te_link_subtlv_link_type link_type;
+ struct te_link_subtlv_link_id link_id;
+ struct te_link_subtlv_lclif_ipaddr *lclif_ipaddr;
+ struct te_link_subtlv_rmtif_ipaddr *rmtif_ipaddr;
+ struct te_link_subtlv_te_metric te_metric;
+ struct te_link_subtlv_max_bw max_bw;
+ struct te_link_subtlv_max_rsv_bw max_rsv_bw;
+ struct te_link_subtlv_unrsv_bw unrsv_bw;
+ struct te_link_subtlv_rsc_clsclr rsc_clsclr;
+};
+
+/*
+ * Global variable to manage Opaque-LSA/MPLS-TE on this node.
+ * Note that all parameter values are stored in network byte order.
+ */
+static struct ospf_mpls_te OspfMplsTE;
+
+enum oifstate {
+ OI_ANY, OI_DOWN, OI_UP
+};
+
+enum sched_opcode {
+ REORIGINATE_PER_AREA, REFRESH_THIS_LSA, FLUSH_THIS_LSA
+};
+
+/*------------------------------------------------------------------------*
+ * Followings are initialize/terminate functions for MPLS-TE handling.
+ *------------------------------------------------------------------------*/
+
+static int ospf_mpls_te_new_if (struct interface *ifp);
+static int ospf_mpls_te_del_if (struct interface *ifp);
+static void ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_status);
+static void ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_status);
+static void ospf_mpls_te_config_write_router (struct vty *vty);
+static void ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp);
+static void ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa);
+static int ospf_mpls_te_lsa_originate (void *arg);
+static void ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa);
+static void ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, enum sched_opcode);
+
+static void del_mpls_te_link (void *val);
+static void ospf_mpls_te_register_vty (void);
+
+int
+ospf_mpls_te_init (void)
+{
+ int rc;
+
+ rc = ospf_register_opaque_functab (
+ OSPF_OPAQUE_AREA_LSA,
+ OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA,
+ ospf_mpls_te_new_if,
+ ospf_mpls_te_del_if,
+ ospf_mpls_te_ism_change,
+ ospf_mpls_te_nsm_change,
+ ospf_mpls_te_config_write_router,
+ ospf_mpls_te_config_write_if,
+ NULL,/* ospf_mpls_te_config_write_debug */
+ ospf_mpls_te_show_info,
+ ospf_mpls_te_lsa_originate,
+ ospf_mpls_te_lsa_refresh,
+ NULL,/* ospf_mpls_te_new_lsa_hook */
+ NULL /* ospf_mpls_te_del_lsa_hook */);
+ if (rc != 0)
+ {
+ zlog_warn ("ospf_mpls_te_init: Failed to register functions");
+ goto out;
+ }
+
+ memset (&OspfMplsTE, 0, sizeof (struct ospf_mpls_te));
+ OspfMplsTE.status = disabled;
+ OspfMplsTE.iflist = list_new ();
+ OspfMplsTE.iflist->del = del_mpls_te_link;
+
+ ospf_mpls_te_register_vty ();
+
+out:
+ return rc;
+}
+
+void
+ospf_mpls_te_term (void)
+{
+ list_delete (OspfMplsTE.iflist);
+
+ OspfMplsTE.iflist = NULL;
+ OspfMplsTE.status = disabled;
+
+ ospf_delete_opaque_functab (OSPF_OPAQUE_AREA_LSA,
+ OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA);
+ return;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are control functions for MPLS-TE parameters management.
+ *------------------------------------------------------------------------*/
+
+static void
+del_mpls_te_link (void *val)
+{
+ XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, val);
+ return;
+}
+
+static u_int32_t
+get_mpls_te_instance_value ()
+{
+ static u_int32_t seqno = 0;
+
+ if (LEGAL_TE_INSTANCE_RANGE (seqno + 1))
+ seqno += 1;
+ else
+ seqno = 1; /* Avoid zero. */
+
+ return seqno;
+}
+
+static struct ospf_interface *
+lookup_oi_by_ifp (struct interface *ifp,
+ struct ospf_area *area, enum oifstate oifstate)
+{
+ struct ospf_interface *oi = NULL;
+ struct route_node *rn;
+
+ for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+ {
+ if ((oi = rn->info) == NULL)
+ continue;
+
+ switch (oifstate)
+ {
+ case OI_ANY:
+ break;
+ case OI_DOWN:
+ if (ospf_if_is_enable (oi))
+ continue;
+ break;
+ case OI_UP:
+ if (! ospf_if_is_enable (oi))
+ continue;
+ break;
+ default:
+ zlog_warn ("lookup_oi_by_ifp: Unknown oifstate: %x", oifstate);
+ goto out;
+ }
+
+ if (area == NULL || oi->area == area)
+ return oi;
+ }
+out:
+ return NULL;
+}
+
+static struct mpls_te_link *
+lookup_linkparams_by_ifp (struct interface *ifp)
+{
+ listnode node;
+ struct mpls_te_link *lp;
+
+ for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
+ if ((lp = getdata (node)) != NULL)
+ if (lp->ifp == ifp)
+ return lp;
+
+ return NULL;
+}
+
+static struct mpls_te_link *
+lookup_linkparams_by_instance (struct ospf_lsa *lsa)
+{
+ listnode node;
+ struct mpls_te_link *lp;
+ int key = GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr));
+
+ for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
+ if ((lp = getdata (node)) != NULL)
+ if (lp->instance == key)
+ return lp;
+
+ zlog_warn ("lookup_linkparams_by_instance: Entry not found: key(%x)", key);
+ return NULL;
+}
+
+static void
+ospf_mpls_te_foreach_area (
+ void (*func)(struct mpls_te_link *lp, enum sched_opcode),
+ enum sched_opcode sched_opcode)
+{
+ listnode node, node2;
+ struct mpls_te_link *lp;
+ struct ospf_area *area;
+
+ for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
+ {
+ if ((lp = getdata (node)) == NULL)
+ continue;
+ if ((area = lp->area) == NULL)
+ continue;
+ if (lp->flags & LPFLG_LOOKUP_DONE)
+ continue;
+
+ if (func != NULL)
+ (* func)(lp, sched_opcode);
+
+ for (node2 = nextnode (node); node2; nextnode (node2))
+ if ((lp = getdata (node2)) != NULL)
+ if (lp->area != NULL)
+ if (IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id))
+ lp->flags |= LPFLG_LOOKUP_DONE;
+ }
+
+ for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
+ if ((lp = getdata (node)) != NULL)
+ if (lp->area != NULL)
+ lp->flags &= ~LPFLG_LOOKUP_DONE;
+
+ return;
+}
+
+static void
+set_mpls_te_router_addr (struct in_addr ipv4)
+{
+ OspfMplsTE.router_addr.header.type = htons (TE_TLV_ROUTER_ADDR);
+ OspfMplsTE.router_addr.header.length = htons (sizeof (ipv4));
+ OspfMplsTE.router_addr.value = ipv4;
+ return;
+}
+
+static void
+set_linkparams_link_header (struct mpls_te_link *lp)
+{
+ struct te_tlv_header *tlvh;
+ u_int16_t length = 0;
+
+ /* TE_LINK_SUBTLV_LINK_TYPE */
+ if (ntohs (lp->link_type.header.type) != 0)
+ length += TLV_SIZE (&lp->link_type.header);
+
+ /* TE_LINK_SUBTLV_LINK_ID */
+ if (ntohs (lp->link_id.header.type) != 0)
+ length += TLV_SIZE (&lp->link_id.header);
+
+ /* TE_LINK_SUBTLV_LCLIF_IPADDR */
+ if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL
+ && ntohs (tlvh->type) != 0)
+ length += TLV_SIZE (tlvh);
+
+ /* TE_LINK_SUBTLV_RMTIF_IPADDR */
+ if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL
+ && ntohs (tlvh->type) != 0)
+ length += TLV_SIZE (tlvh);
+
+ /* TE_LINK_SUBTLV_TE_METRIC */
+ if (ntohs (lp->te_metric.header.type) != 0)
+ length += TLV_SIZE (&lp->te_metric.header);
+
+ /* TE_LINK_SUBTLV_MAX_BW */
+ if (ntohs (lp->max_bw.header.type) != 0)
+ length += TLV_SIZE (&lp->max_bw.header);
+
+ /* TE_LINK_SUBTLV_MAX_RSV_BW */
+ if (ntohs (lp->max_rsv_bw.header.type) != 0)
+ length += TLV_SIZE (&lp->max_rsv_bw.header);
+
+ /* TE_LINK_SUBTLV_UNRSV_BW */
+ if (ntohs (lp->unrsv_bw.header.type) != 0)
+ length += TLV_SIZE (&lp->unrsv_bw.header);
+
+ /* TE_LINK_SUBTLV_RSC_CLSCLR */
+ if (ntohs (lp->rsc_clsclr.header.type) != 0)
+ length += TLV_SIZE (&lp->rsc_clsclr.header);
+
+ lp->link_header.header.type = htons (TE_TLV_LINK);
+ lp->link_header.header.length = htons (length);
+
+ return;
+}
+
+static void
+set_linkparams_link_type (struct ospf_interface *oi, struct mpls_te_link *lp)
+{
+ lp->link_type.header.type = htons (TE_LINK_SUBTLV_LINK_TYPE);
+ lp->link_type.header.length = htons (sizeof (lp->link_type.link_type.value));
+
+ switch (oi->type)
+ {
+ case OSPF_IFTYPE_POINTOPOINT:
+ lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_PTP;
+ break;
+ case OSPF_IFTYPE_BROADCAST:
+ case OSPF_IFTYPE_NBMA:
+ lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_MA;
+ break;
+ default:
+ /* Not supported yet. *//* XXX */
+ lp->link_type.header.type = htons (0);
+ break;
+ }
+ return;
+}
+
+static void
+set_linkparams_link_id (struct ospf_interface *oi, struct mpls_te_link *lp)
+{
+ struct ospf_neighbor *nbr;
+ int done = 0;
+
+ lp->link_id.header.type = htons (TE_LINK_SUBTLV_LINK_ID);
+ lp->link_id.header.length = htons (sizeof (lp->link_id.value));
+
+ /*
+ * The Link ID is identical to the contents of the Link ID field
+ * in the Router LSA for these link types.
+ */
+ switch (oi->type)
+ {
+ case OSPF_IFTYPE_POINTOPOINT:
+ /* Take the router ID of the neighbor. */
+ if (((nbr = ospf_nbr_lookup_ptop (oi->nbrs, oi->area->top->router_id)))
+ && (nbr->state == NSM_Full))
+ {
+ lp->link_id.value = nbr->router_id;
+ done = 1;
+ }
+ break;
+ case OSPF_IFTYPE_BROADCAST:
+ case OSPF_IFTYPE_NBMA:
+ /* Take the interface address of the designated router. */
+ if ((nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &DR (oi))) == NULL)
+ break;
+
+ if (nbr->state == NSM_Full
+ || (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))
+ && ospf_nbr_count (oi->nbrs, NSM_Full) > 0))
+ {
+ lp->link_id.value = DR (oi);
+ done = 1;
+ }
+ break;
+ default:
+ /* Not supported yet. *//* XXX */
+ lp->link_id.header.type = htons (0);
+ break;
+ }
+
+ if (! done)
+ {
+ struct in_addr mask;
+ masklen2ip (oi->address->prefixlen, &mask);
+ lp->link_id.value.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
+ }
+ return;
+}
+
+static void
+set_linkparams_te_metric (struct mpls_te_link *lp, u_int32_t te_metric)
+{
+ lp->te_metric.header.type = htons (TE_LINK_SUBTLV_TE_METRIC);
+ lp->te_metric.header.length = htons (sizeof (lp->te_metric.value));
+ lp->te_metric.value = htonl (te_metric);
+ return;
+}
+
+static void
+set_linkparams_max_bw (struct mpls_te_link *lp, float *fp)
+{
+ lp->max_bw.header.type = htons (TE_LINK_SUBTLV_MAX_BW);
+ lp->max_bw.header.length = htons (sizeof (lp->max_bw.value));
+ htonf (fp, &lp->max_bw.value);
+ return;
+}
+
+static void
+set_linkparams_max_rsv_bw (struct mpls_te_link *lp, float *fp)
+{
+ lp->max_rsv_bw.header.type = htons (TE_LINK_SUBTLV_MAX_RSV_BW);
+ lp->max_rsv_bw.header.length = htons (sizeof (lp->max_rsv_bw.value));
+ htonf (fp, &lp->max_rsv_bw.value);
+ return;
+}
+
+static void
+set_linkparams_unrsv_bw (struct mpls_te_link *lp, int priority, float *fp)
+{
+ /* Note that TLV-length field is the size of array. */
+ lp->unrsv_bw.header.type = htons (TE_LINK_SUBTLV_UNRSV_BW);
+ lp->unrsv_bw.header.length = htons (sizeof (lp->unrsv_bw.value));
+ htonf (fp, &lp->unrsv_bw.value [priority]);
+ return;
+}
+
+static void
+set_linkparams_rsc_clsclr (struct mpls_te_link *lp, u_int32_t classcolor)
+{
+ lp->rsc_clsclr.header.type = htons (TE_LINK_SUBTLV_RSC_CLSCLR);
+ lp->rsc_clsclr.header.length = htons (sizeof (lp->rsc_clsclr.value));
+ lp->rsc_clsclr.value = htonl (classcolor);
+ return;
+}
+
+static void
+initialize_linkparams (struct mpls_te_link *lp)
+{
+ struct interface *ifp = lp->ifp;
+ struct ospf_interface *oi;
+ float fval;
+ int i;
+
+ if ((oi = lookup_oi_by_ifp (ifp, NULL, OI_ANY)) == NULL)
+ return;
+
+ /*
+ * Try to set initial values those can be derived from
+ * zebra-interface information.
+ */
+ set_linkparams_link_type (oi, lp);
+
+ /*
+ * Linux and *BSD kernel holds bandwidth parameter as an "int" type.
+ * We may have to reconsider, if "ifp->bandwidth" type changes to float.
+ */
+ fval = (float)((ifp->bandwidth ? ifp->bandwidth
+ : OSPF_DEFAULT_BANDWIDTH) * 1000 / 8);
+
+ set_linkparams_max_bw (lp, &fval);
+ set_linkparams_max_rsv_bw (lp, &fval);
+
+ for (i = 0; i < 8; i++)
+ set_linkparams_unrsv_bw (lp, i, &fval);
+
+ return;
+}
+
+static int
+is_mandated_params_set (struct mpls_te_link *lp)
+{
+ int rc = 0;
+
+ if (ntohs (OspfMplsTE.router_addr.header.type) == 0)
+ goto out;
+
+ if (ntohs (lp->link_type.header.type) == 0)
+ goto out;
+
+ if (ntohs (lp->link_id.header.type) == 0)
+ goto out;
+
+ rc = 1;
+out:
+ return rc;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are callback functions against generic Opaque-LSAs handling.
+ *------------------------------------------------------------------------*/
+
+static int
+ospf_mpls_te_new_if (struct interface *ifp)
+{
+ struct mpls_te_link *new;
+ int rc = -1;
+
+ if (lookup_linkparams_by_ifp (ifp) != NULL)
+ {
+ zlog_warn ("ospf_mpls_te_new_if: ifp(%p) already in use?", ifp);
+ rc = 0; /* Do nothing here. */
+ goto out;
+ }
+
+ if ((new = XMALLOC (MTYPE_OSPF_MPLS_TE_LINKPARAMS,
+ sizeof (struct mpls_te_link))) == NULL)
+ {
+ zlog_warn ("ospf_mpls_te_new_if: XMALLOC: %s", strerror (errno));
+ goto out;
+ }
+ memset (new, 0, sizeof (struct mpls_te_link));
+
+ new->area = NULL;
+ new->flags = 0;
+ new->instance = get_mpls_te_instance_value ();
+ new->ifp = ifp;
+
+ initialize_linkparams (new);
+
+ listnode_add (OspfMplsTE.iflist, new);
+
+ /* Schedule Opaque-LSA refresh. *//* XXX */
+
+ rc = 0;
+out:
+ return rc;
+}
+
+static int
+ospf_mpls_te_del_if (struct interface *ifp)
+{
+ struct mpls_te_link *lp;
+ int rc = -1;
+
+ if ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)
+ {
+ list iflist = OspfMplsTE.iflist;
+
+ /* Dequeue listnode entry from the list. */
+ listnode_delete (iflist, lp);
+
+ /* Avoid misjudgement in the next lookup. */
+ if (listcount (iflist) == 0)
+ iflist->head = iflist->tail = NULL;
+
+ XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, lp);
+ }
+
+ /* Schedule Opaque-LSA refresh. *//* XXX */
+
+ rc = 0;
+/*out:*/
+ return rc;
+}
+
+static void
+ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_state)
+{
+ struct te_link_subtlv_link_type old_type;
+ struct te_link_subtlv_link_id old_id;
+ struct mpls_te_link *lp;
+
+ if ((lp = lookup_linkparams_by_ifp (oi->ifp)) == NULL)
+ {
+ zlog_warn ("ospf_mpls_te_ism_change: Cannot get linkparams from OI(%s)?", IF_NAME (oi));
+ goto out;
+ }
+ if (oi->area == NULL || oi->area->top == NULL)
+ {
+ zlog_warn ("ospf_mpls_te_ism_change: Cannot refer to OSPF from OI(%s)?",
+IF_NAME (oi));
+ goto out;
+ }
+#ifdef notyet
+ if ((lp->area != NULL
+ && ! IPV4_ADDR_SAME (&lp->area->area_id, &oi->area->area_id))
+ || (lp->area != NULL && oi->area == NULL))
+ {
+ /* How should we consider this case? */
+ zlog_warn ("MPLS-TE: Area for OI(%s) has changed to [%s], flush previous LSAs", IF_NAME (oi), oi->area ? inet_ntoa (oi->area->area_id) : "N/A");
+ ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA);
+ }
+#endif
+ /* Keep Area information in conbination with linkparams. */
+ lp->area = oi->area;
+
+ switch (oi->state)
+ {
+ case ISM_PointToPoint:
+ case ISM_DROther:
+ case ISM_Backup:
+ case ISM_DR:
+ old_type = lp->link_type;
+ old_id = lp->link_id;
+
+ set_linkparams_link_type (oi, lp);
+ set_linkparams_link_id (oi, lp);
+
+ if ((ntohs (old_type.header.type) != ntohs (lp->link_type.header.type)
+ || old_type.link_type.value != lp->link_type.link_type.value)
+ || (ntohs (old_id.header.type) != ntohs (lp->link_id.header.type)
+ || ntohl (old_id.value.s_addr) != ntohl (lp->link_id.value.s_addr)))
+ {
+ if (lp->flags & LPFLG_LSA_ENGAGED)
+ ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
+ else
+ ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
+ }
+ break;
+ default:
+ lp->link_type.header.type = htons (0);
+ lp->link_id.header.type = htons (0);
+
+ if (lp->flags & LPFLG_LSA_ENGAGED)
+ ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA);
+ break;
+ }
+
+out:
+ return;
+}
+
+static void
+ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_state)
+{
+ /* So far, nothing to do here. */
+ return;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are OSPF protocol processing functions for MPLS-TE.
+ *------------------------------------------------------------------------*/
+
+static void
+build_tlv_header (struct stream *s, struct te_tlv_header *tlvh)
+{
+ stream_put (s, tlvh, sizeof (struct te_tlv_header));
+ return;
+}
+
+static void
+build_router_tlv (struct stream *s)
+{
+ struct te_tlv_header *tlvh = &OspfMplsTE.router_addr.header;
+ if (ntohs (tlvh->type) != 0)
+ {
+ build_tlv_header (s, tlvh);
+ stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+ }
+ return;
+}
+
+static void
+build_link_subtlv_link_type (struct stream *s, struct mpls_te_link *lp)
+{
+ struct te_tlv_header *tlvh = &lp->link_type.header;
+ if (ntohs (tlvh->type) != 0)
+ {
+ build_tlv_header (s, tlvh);
+ stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+ }
+ return;
+}
+
+static void
+build_link_subtlv_link_id (struct stream *s, struct mpls_te_link *lp)
+{
+ struct te_tlv_header *tlvh = &lp->link_id.header;
+ if (ntohs (tlvh->type) != 0)
+ {
+ build_tlv_header (s, tlvh);
+ stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+ }
+ return;
+}
+
+static void
+build_link_subtlv_lclif_ipaddr (struct stream *s, struct mpls_te_link *lp)
+{
+ struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->lclif_ipaddr;
+ if (tlvh != NULL && ntohs (tlvh->type) != 0)
+ {
+ build_tlv_header (s, tlvh);
+ stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+ }
+ return;
+}
+
+static void
+build_link_subtlv_rmtif_ipaddr (struct stream *s, struct mpls_te_link *lp)
+{
+ struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr;
+ if (tlvh != NULL && ntohs (tlvh->type) != 0)
+ {
+ build_tlv_header (s, tlvh);
+ stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+ }
+ return;
+}
+
+static void
+build_link_subtlv_te_metric (struct stream *s, struct mpls_te_link *lp)
+{
+ struct te_tlv_header *tlvh = &lp->te_metric.header;
+ if (ntohs (tlvh->type) != 0)
+ {
+ build_tlv_header (s, tlvh);
+ stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+ }
+ return;
+}
+
+static void
+build_link_subtlv_max_bw (struct stream *s, struct mpls_te_link *lp)
+{
+ struct te_tlv_header *tlvh = &lp->max_bw.header;
+ if (ntohs (tlvh->type) != 0)
+ {
+ build_tlv_header (s, tlvh);
+ stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+ }
+ return;
+}
+
+static void
+build_link_subtlv_max_rsv_bw (struct stream *s, struct mpls_te_link *lp)
+{
+ struct te_tlv_header *tlvh = &lp->max_rsv_bw.header;
+ if (ntohs (tlvh->type) != 0)
+ {
+ build_tlv_header (s, tlvh);
+ stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+ }
+ return;
+}
+
+static void
+build_link_subtlv_unrsv_bw (struct stream *s, struct mpls_te_link *lp)
+{
+ struct te_tlv_header *tlvh = &lp->unrsv_bw.header;
+ if (ntohs (tlvh->type) != 0)
+ {
+ build_tlv_header (s, tlvh);
+ stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+ }
+ return;
+}
+
+static void
+build_link_subtlv_rsc_clsclr (struct stream *s, struct mpls_te_link *lp)
+{
+ struct te_tlv_header *tlvh = &lp->rsc_clsclr.header;
+ if (ntohs (tlvh->type) != 0)
+ {
+ build_tlv_header (s, tlvh);
+ stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+ }
+ return;
+}
+
+static void
+build_link_tlv (struct stream *s, struct mpls_te_link *lp)
+{
+ set_linkparams_link_header (lp);
+ build_tlv_header (s, &lp->link_header.header);
+
+ build_link_subtlv_link_type (s, lp);
+ build_link_subtlv_link_id (s, lp);
+ build_link_subtlv_lclif_ipaddr (s, lp);
+ build_link_subtlv_rmtif_ipaddr (s, lp);
+ build_link_subtlv_te_metric (s, lp);
+ build_link_subtlv_max_bw (s, lp);
+ build_link_subtlv_max_rsv_bw (s, lp);
+ build_link_subtlv_unrsv_bw (s, lp);
+ build_link_subtlv_rsc_clsclr (s, lp);
+ return;
+}
+
+static void
+ospf_mpls_te_lsa_body_set (struct stream *s, struct mpls_te_link *lp)
+{
+ /*
+ * The router address TLV is type 1, and ...
+ * It must appear in exactly one
+ * Traffic Engineering LSA originated by a router.
+ */
+ build_router_tlv (s);
+
+ /*
+ * Only one Link TLV shall be carried in each LSA, allowing for fine
+ * granularity changes in topology.
+ */
+ build_link_tlv (s, lp);
+ return;
+}
+
+/* Create new opaque-LSA. */
+static struct ospf_lsa *
+ospf_mpls_te_lsa_new (struct ospf_area *area, struct mpls_te_link *lp)
+{
+ struct stream *s;
+ struct lsa_header *lsah;
+ struct ospf_lsa *new = NULL;
+ u_char options, lsa_type;
+ struct in_addr lsa_id;
+ u_int32_t tmp;
+ u_int16_t length;
+
+ /* Create a stream for LSA. */
+ if ((s = stream_new (OSPF_MAX_LSA_SIZE)) == NULL)
+ {
+ zlog_warn ("ospf_mpls_te_lsa_new: stream_new() ?");
+ goto out;
+ }
+ lsah = (struct lsa_header *) STREAM_DATA (s);
+
+ options = LSA_OPTIONS_GET (area);
+#ifdef HAVE_NSSA
+ options |= LSA_NSSA_GET (area);
+#endif /* HAVE_NSSA */
+ options |= OSPF_OPTION_O; /* Don't forget this :-) */
+
+ lsa_type = OSPF_OPAQUE_AREA_LSA;
+ tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance);
+ lsa_id.s_addr = htonl (tmp);
+
+ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+ zlog_info ("LSA[Type%d:%s]: Create an Opaque-LSA/MPLS-TE instance", lsa_type, inet_ntoa (lsa_id));
+
+ /* Set opaque-LSA header fields. */
+ lsa_header_set (s, options, lsa_type, lsa_id);
+
+ /* Set opaque-LSA body fields. */
+ ospf_mpls_te_lsa_body_set (s, lp);
+
+ /* Set length. */
+ length = stream_get_endp (s);
+ lsah->length = htons (length);
+
+ /* Now, create an OSPF LSA instance. */
+ if ((new = ospf_lsa_new ()) == NULL)
+ {
+ zlog_warn ("ospf_mpls_te_lsa_new: ospf_lsa_new() ?");
+ stream_free (s);
+ goto out;
+ }
+ if ((new->data = ospf_lsa_data_new (length)) == NULL)
+ {
+ zlog_warn ("ospf_mpls_te_lsa_new: ospf_lsa_data_new() ?");
+ ospf_lsa_free (new);
+ new = NULL;
+ stream_free (s);
+ goto out;
+ }
+
+ new->area = area;
+ SET_FLAG (new->flags, OSPF_LSA_SELF);
+ memcpy (new->data, lsah, length);
+ stream_free (s);
+
+out:
+ return new;
+}
+
+static int
+ospf_mpls_te_lsa_originate1 (struct ospf_area *area, struct mpls_te_link *lp)
+{
+ struct ospf_lsa *new;
+ int rc = -1;
+
+ /* Create new Opaque-LSA/MPLS-TE instance. */
+ if ((new = ospf_mpls_te_lsa_new (area, lp)) == NULL)
+ {
+ zlog_warn ("ospf_mpls_te_lsa_originate1: ospf_mpls_te_lsa_new() ?");
+ goto out;
+ }
+
+ /* Install this LSA into LSDB. */
+ if (ospf_lsa_install (NULL/*oi*/, new) == NULL)
+ {
+ zlog_warn ("ospf_mpls_te_lsa_originate1: ospf_lsa_install() ?");
+ ospf_lsa_free (new);
+ goto out;
+ }
+
+ /* Now this linkparameter entry has associated LSA. */
+ lp->flags |= LPFLG_LSA_ENGAGED;
+
+ /* Update new LSA origination count. */
+ area->top->lsa_originate_count++;
+
+ /* Flood new LSA through area. */
+ ospf_flood_through_area (area, NULL/*nbr*/, new);
+
+ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+ {
+ char area_id[INET_ADDRSTRLEN];
+ strcpy (area_id, inet_ntoa (area->area_id));
+ zlog_info ("LSA[Type%d:%s]: Originate Opaque-LSA/MPLS-TE: Area(%s), Link(%s)", new->data->type, inet_ntoa (new->data->id), area_id, lp->ifp->name);
+ ospf_lsa_header_dump (new->data);
+ }
+
+ rc = 0;
+out:
+ return rc;
+}
+
+static int
+ospf_mpls_te_lsa_originate (void *arg)
+{
+ struct ospf_area *area = (struct ospf_area *) arg;
+ listnode node;
+ struct mpls_te_link *lp;
+ int rc = -1;
+
+ if (OspfMplsTE.status == disabled)
+ {
+ zlog_info ("ospf_mpls_te_lsa_originate: MPLS-TE is disabled now.");
+ rc = 0; /* This is not an error case. */
+ goto out;
+ }
+
+ for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
+ {
+ if ((lp = getdata (node)) == NULL)
+ continue;
+ if (lp->area == NULL)
+ continue;
+ if (! IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id))
+ continue;
+
+ if (lp->flags & LPFLG_LSA_ENGAGED)
+ {
+ if (lp->flags & LPFLG_LSA_FORCED_REFRESH)
+ {
+ lp->flags &= ~LPFLG_LSA_FORCED_REFRESH;
+ ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
+ }
+ continue;
+ }
+ if (! is_mandated_params_set (lp))
+ {
+ zlog_warn ("ospf_mpls_te_lsa_originate: Link(%s) lacks some mandated MPLS-TE parameters.", lp->ifp ? lp->ifp->name : "?");
+ continue;
+ }
+
+ /* Ok, let's try to originate an LSA for this area and Link. */
+ if (ospf_mpls_te_lsa_originate1 (area, lp) != 0)
+ goto out;
+ }
+
+ rc = 0;
+out:
+ return rc;
+}
+
+static void
+ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa)
+{
+ struct mpls_te_link *lp;
+ struct ospf_area *area = lsa->area;
+ struct ospf_lsa *new = NULL;
+
+ if (OspfMplsTE.status == disabled)
+ {
+ /*
+ * This LSA must have flushed before due to MPLS-TE status change.
+ * It seems a slip among routers in the routing domain.
+ */
+ zlog_info ("ospf_mpls_te_lsa_refresh: MPLS-TE is disabled now.");
+ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */
+ }
+
+ /* At first, resolve lsa/lp relationship. */
+ if ((lp = lookup_linkparams_by_instance (lsa)) == NULL)
+ {
+ zlog_warn ("ospf_mpls_te_lsa_refresh: Invalid parameter?");
+ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */
+ }
+
+ /* If the lsa's age reached to MaxAge, start flushing procedure. */
+ if (IS_LSA_MAXAGE (lsa))
+ {
+ lp->flags &= ~LPFLG_LSA_ENGAGED;
+ ospf_opaque_lsa_flush_schedule (lsa);
+ goto out;
+ }
+
+ /* Create new Opaque-LSA/MPLS-TE instance. */
+ if ((new = ospf_mpls_te_lsa_new (area, lp)) == NULL)
+ {
+ zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_mpls_te_lsa_new() ?");
+ goto out;
+ }
+ new->data->ls_seqnum = lsa_seqnum_increment (lsa);
+
+ /* Install this LSA into LSDB. */
+ /* Given "lsa" will be freed in the next function. */
+ if (ospf_lsa_install (NULL/*oi*/, new) == NULL)
+ {
+ zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_lsa_install() ?");
+ ospf_lsa_free (new);
+ goto out;
+ }
+
+ /* Flood updated LSA through area. */
+ ospf_flood_through_area (area, NULL/*nbr*/, new);
+
+ /* Debug logging. */
+ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+ {
+ zlog_info ("LSA[Type%d:%s]: Refresh Opaque-LSA/MPLS-TE",
+ new->data->type, inet_ntoa (new->data->id));
+ ospf_lsa_header_dump (new->data);
+ }
+
+out:
+ return;
+}
+
+static void
+ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp,
+ enum sched_opcode opcode)
+{
+ struct ospf_lsa lsa;
+ struct lsa_header lsah;
+ u_int32_t tmp;
+
+ memset (&lsa, 0, sizeof (lsa));
+ memset (&lsah, 0, sizeof (lsah));
+
+ lsa.area = lp->area;
+ lsa.data = &lsah;
+ lsah.type = OSPF_OPAQUE_AREA_LSA;
+ tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance);
+ lsah.id.s_addr = htonl (tmp);
+
+ switch (opcode)
+ {
+ case REORIGINATE_PER_AREA:
+ ospf_opaque_lsa_reoriginate_schedule ((void *) lp->area,
+ OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA);
+ break;
+ case REFRESH_THIS_LSA:
+ ospf_opaque_lsa_refresh_schedule (&lsa);
+ break;
+ case FLUSH_THIS_LSA:
+ lp->flags &= ~LPFLG_LSA_ENGAGED;
+ ospf_opaque_lsa_flush_schedule (&lsa);
+ break;
+ default:
+ zlog_warn ("ospf_mpls_te_lsa_schedule: Unknown opcode (%u)", opcode);
+ break;
+ }
+
+ return;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are vty session control functions.
+ *------------------------------------------------------------------------*/
+
+static u_int16_t
+show_vty_router_addr (struct vty *vty, struct te_tlv_header *tlvh)
+{
+ struct te_tlv_router_addr *top = (struct te_tlv_router_addr *) tlvh;
+
+ if (vty != NULL)
+ vty_out (vty, " Router-Address: %s%s", inet_ntoa (top->value), VTY_NEWLINE);
+ else
+ zlog_info (" Router-Address: %s", inet_ntoa (top->value));
+
+ return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_link_header (struct vty *vty, struct te_tlv_header *tlvh)
+{
+ struct te_tlv_link *top = (struct te_tlv_link *) tlvh;
+
+ if (vty != NULL)
+ vty_out (vty, " Link: %u octets of data%s", ntohs (top->header.length), VTY_NEWLINE);
+ else
+ zlog_info (" Link: %u octets of data", ntohs (top->header.length));
+
+ return TLV_HDR_SIZE; /* Here is special, not "TLV_SIZE". */
+}
+
+static u_int16_t
+show_vty_link_subtlv_link_type (struct vty *vty, struct te_tlv_header *tlvh)
+{
+ struct te_link_subtlv_link_type *top;
+ const char *cp = "Unknown";
+
+ top = (struct te_link_subtlv_link_type *) tlvh;
+ switch (top->link_type.value)
+ {
+ case LINK_TYPE_SUBTLV_VALUE_PTP:
+ cp = "Point-to-point";
+ break;
+ case LINK_TYPE_SUBTLV_VALUE_MA:
+ cp = "Multiaccess";
+ break;
+ default:
+ break;
+ }
+
+ if (vty != NULL)
+ vty_out (vty, " Link-Type: %s (%u)%s", cp, top->link_type.value, VTY_NEWLINE);
+ else
+ zlog_info (" Link-Type: %s (%u)", cp, top->link_type.value);
+
+ return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_link_subtlv_link_id (struct vty *vty, struct te_tlv_header *tlvh)
+{
+ struct te_link_subtlv_link_id *top;
+
+ top = (struct te_link_subtlv_link_id *) tlvh;
+ if (vty != NULL)
+ vty_out (vty, " Link-ID: %s%s", inet_ntoa (top->value), VTY_NEWLINE);
+ else
+ zlog_info (" Link-ID: %s", inet_ntoa (top->value));
+
+ return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_link_subtlv_lclif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh)
+{
+ struct te_link_subtlv_lclif_ipaddr *top;
+ int i, n;
+
+ top = (struct te_link_subtlv_lclif_ipaddr *) tlvh;
+ n = ntohs (tlvh->length) / sizeof (top->value[0]);
+
+ if (vty != NULL)
+ vty_out (vty, " Local Interface IP Address(es): %d%s", n, VTY_NEWLINE);
+ else
+ zlog_info (" Local Interface IP Address(es): %d", n);
+
+ for (i = 0; i < n; i++)
+ {
+ if (vty != NULL)
+ vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE);
+ else
+ zlog_info (" #%d: %s", i, inet_ntoa (top->value[i]));
+ }
+ return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_link_subtlv_rmtif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh)
+{
+ struct te_link_subtlv_rmtif_ipaddr *top;
+ int i, n;
+
+ top = (struct te_link_subtlv_rmtif_ipaddr *) tlvh;
+ n = ntohs (tlvh->length) / sizeof (top->value[0]);
+ if (vty != NULL)
+ vty_out (vty, " Remote Interface IP Address(es): %d%s", n, VTY_NEWLINE);
+ else
+ zlog_info (" Remote Interface IP Address(es): %d", n);
+
+ for (i = 0; i < n; i++)
+ {
+ if (vty != NULL)
+ vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE);
+ else
+ zlog_info (" #%d: %s", i, inet_ntoa (top->value[i]));
+ }
+ return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_link_subtlv_te_metric (struct vty *vty, struct te_tlv_header *tlvh)
+{
+ struct te_link_subtlv_te_metric *top;
+
+ top = (struct te_link_subtlv_te_metric *) tlvh;
+ if (vty != NULL)
+ vty_out (vty, " Traffic Engineering Metric: %u%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE);
+ else
+ zlog_info (" Traffic Engineering Metric: %u", (u_int32_t) ntohl (top->value));
+
+ return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_link_subtlv_max_bw (struct vty *vty, struct te_tlv_header *tlvh)
+{
+ struct te_link_subtlv_max_bw *top;
+ float fval;
+
+ top = (struct te_link_subtlv_max_bw *) tlvh;
+ ntohf (&top->value, &fval);
+
+ if (vty != NULL)
+ vty_out (vty, " Maximum Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE);
+ else
+ zlog_info (" Maximum Bandwidth: %g (Bytes/sec)", fval);
+
+ return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_link_subtlv_max_rsv_bw (struct vty *vty, struct te_tlv_header *tlvh)
+{
+ struct te_link_subtlv_max_rsv_bw *top;
+ float fval;
+
+ top = (struct te_link_subtlv_max_rsv_bw *) tlvh;
+ ntohf (&top->value, &fval);
+
+ if (vty != NULL)
+ vty_out (vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE);
+ else
+ zlog_info (" Maximum Reservable Bandwidth: %g (Bytes/sec)", fval);
+
+ return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_link_subtlv_unrsv_bw (struct vty *vty, struct te_tlv_header *tlvh)
+{
+ struct te_link_subtlv_unrsv_bw *top;
+ float fval;
+ int i;
+
+ top = (struct te_link_subtlv_unrsv_bw *) tlvh;
+ for (i = 0; i < 8; i++)
+ {
+ ntohf (&top->value[i], &fval);
+ if (vty != NULL)
+ vty_out (vty, " Unreserved Bandwidth (pri %d): %g (Bytes/sec)%s", i, fval, VTY_NEWLINE);
+ else
+ zlog_info (" Unreserved Bandwidth (pri %d): %g (Bytes/sec)", i, fval);
+ }
+
+ return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_link_subtlv_rsc_clsclr (struct vty *vty, struct te_tlv_header *tlvh)
+{
+ struct te_link_subtlv_rsc_clsclr *top;
+
+ top = (struct te_link_subtlv_rsc_clsclr *) tlvh;
+ if (vty != NULL)
+ vty_out (vty, " Resource class/color: 0x%x%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE);
+ else
+ zlog_info (" Resource Class/Color: 0x%x", (u_int32_t) ntohl (top->value));
+
+ return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_unknown_tlv (struct vty *vty, struct te_tlv_header *tlvh)
+{
+ if (vty != NULL)
+ vty_out (vty, " Unknown TLV: [type(0x%x), length(0x%x)]%s", ntohs (tlvh->type), ntohs (tlvh->length), VTY_NEWLINE);
+ else
+ zlog_info (" Unknown TLV: [type(0x%x), length(0x%x)]", ntohs (tlvh->type), ntohs (tlvh->length));
+
+ return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+ospf_mpls_te_show_link_subtlv (struct vty *vty, struct te_tlv_header *tlvh0,
+ u_int16_t subtotal, u_int16_t total)
+{
+ struct te_tlv_header *tlvh, *next;
+ u_int16_t sum = subtotal;
+
+ for (tlvh = tlvh0; sum < total; tlvh = (next ? next : TLV_HDR_NEXT (tlvh)))
+ {
+ next = NULL;
+ switch (ntohs (tlvh->type))
+ {
+ case TE_LINK_SUBTLV_LINK_TYPE:
+ sum += show_vty_link_subtlv_link_type (vty, tlvh);
+ break;
+ case TE_LINK_SUBTLV_LINK_ID:
+ sum += show_vty_link_subtlv_link_id (vty, tlvh);
+ break;
+ case TE_LINK_SUBTLV_LCLIF_IPADDR:
+ sum += show_vty_link_subtlv_lclif_ipaddr (vty, tlvh);
+ break;
+ case TE_LINK_SUBTLV_RMTIF_IPADDR:
+ sum += show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh);
+ break;
+ case TE_LINK_SUBTLV_TE_METRIC:
+ sum += show_vty_link_subtlv_te_metric (vty, tlvh);
+ break;
+ case TE_LINK_SUBTLV_MAX_BW:
+ sum += show_vty_link_subtlv_max_bw (vty, tlvh);
+ break;
+ case TE_LINK_SUBTLV_MAX_RSV_BW:
+ sum += show_vty_link_subtlv_max_rsv_bw (vty, tlvh);
+ break;
+ case TE_LINK_SUBTLV_UNRSV_BW:
+ sum += show_vty_link_subtlv_unrsv_bw (vty, tlvh);
+ break;
+ case TE_LINK_SUBTLV_RSC_CLSCLR:
+ sum += show_vty_link_subtlv_rsc_clsclr (vty, tlvh);
+ break;
+ default:
+ sum += show_vty_unknown_tlv (vty, tlvh);
+ break;
+ }
+ }
+ return sum;
+}
+
+static void
+ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa)
+{
+ struct lsa_header *lsah = (struct lsa_header *) lsa->data;
+ struct te_tlv_header *tlvh, *next;
+ u_int16_t sum, total;
+ u_int16_t (* subfunc)(struct vty *vty, struct te_tlv_header *tlvh,
+ u_int16_t subtotal, u_int16_t total) = NULL;
+
+ sum = 0;
+ total = ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE;
+
+ for (tlvh = TLV_HDR_TOP (lsah); sum < total;
+ tlvh = (next ? next : TLV_HDR_NEXT (tlvh)))
+ {
+ if (subfunc != NULL)
+ {
+ sum = (* subfunc)(vty, tlvh, sum, total);
+ next = (struct te_tlv_header *)((char *) tlvh + sum);
+ subfunc = NULL;
+ continue;
+ }
+
+ next = NULL;
+ switch (ntohs (tlvh->type))
+ {
+ case TE_TLV_ROUTER_ADDR:
+ sum += show_vty_router_addr (vty, tlvh);
+ break;
+ case TE_TLV_LINK:
+ sum += show_vty_link_header (vty, tlvh);
+ subfunc = ospf_mpls_te_show_link_subtlv;
+ next = tlvh + 1;
+ break;
+ default:
+ sum += show_vty_unknown_tlv (vty, tlvh);
+ break;
+ }
+ }
+ return;
+}
+
+static void
+ospf_mpls_te_config_write_router (struct vty *vty)
+{
+ if (OspfMplsTE.status == enabled)
+ {
+ vty_out (vty, " mpls-te%s", VTY_NEWLINE);
+ vty_out (vty, " mpls-te router-address %s%s",
+ inet_ntoa (OspfMplsTE.router_addr.value), VTY_NEWLINE);
+ }
+ return;
+}
+
+static void
+ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp)
+{
+ struct mpls_te_link *lp;
+
+ if ((OspfMplsTE.status == enabled)
+ && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0)
+ && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL))
+ {
+ float fval;
+ int i;
+
+ vty_out (vty, " mpls-te link metric %u%s",
+ (u_int32_t) ntohl (lp->te_metric.value), VTY_NEWLINE);
+
+ ntohf (&lp->max_bw.value, &fval);
+ if (fval >= MPLS_TE_MINIMUM_BANDWIDTH)
+ vty_out (vty, " mpls-te link max-bw %g%s", fval, VTY_NEWLINE);
+
+ ntohf (&lp->max_rsv_bw.value, &fval);
+ if (fval >= MPLS_TE_MINIMUM_BANDWIDTH)
+ vty_out (vty, " mpls-te link max-rsv-bw %g%s", fval, VTY_NEWLINE);
+
+ for (i = 0; i < 8; i++)
+ {
+ ntohf (&lp->unrsv_bw.value[i], &fval);
+ if (fval >= MPLS_TE_MINIMUM_BANDWIDTH)
+ vty_out (vty, " mpls-te link unrsv-bw %d %g%s",
+ i, fval, VTY_NEWLINE);
+ }
+
+ vty_out (vty, " mpls-te link rsc-clsclr 0x%x%s",
+ (u_int32_t) ntohl (lp->rsc_clsclr.value), VTY_NEWLINE);
+ }
+ return;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are vty command functions.
+ *------------------------------------------------------------------------*/
+
+DEFUN (mpls_te,
+ mpls_te_cmd,
+ "mpls-te",
+ "Configure MPLS-TE parameters\n"
+ "Enable the MPLS-TE functionality\n")
+{
+ listnode node;
+ struct mpls_te_link *lp;
+
+ if (OspfMplsTE.status == enabled)
+ return CMD_SUCCESS;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("MPLS-TE: OFF -> ON");
+
+ OspfMplsTE.status = enabled;
+
+ /*
+ * Following code is intended to handle two cases;
+ *
+ * 1) MPLS-TE was disabled at startup time, but now become enabled.
+ * 2) MPLS-TE was once enabled then disabled, and now enabled again.
+ */
+ for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
+ if ((lp = getdata (node)) != NULL)
+ initialize_linkparams (lp);
+
+ ospf_mpls_te_foreach_area (ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (mpls_te,
+ mpls_te_on_cmd,
+ "mpls-te on",
+ "Configure MPLS-TE parameters\n"
+ "Enable the MPLS-TE functionality\n")
+
+DEFUN (no_mpls_te,
+ no_mpls_te_cmd,
+ "no mpls-te",
+ NO_STR
+ "Configure MPLS-TE parameters\n"
+ "Disable the MPLS-TE functionality\n")
+{
+ listnode node;
+ struct mpls_te_link *lp;
+
+ if (OspfMplsTE.status == disabled)
+ return CMD_SUCCESS;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("MPLS-TE: ON -> OFF");
+
+ OspfMplsTE.status = disabled;
+
+ for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
+ if ((lp = getdata (node)) != NULL)
+ if (lp->area != NULL)
+ if (lp->flags & LPFLG_LSA_ENGAGED)
+ ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (mpls_te_router_addr,
+ mpls_te_router_addr_cmd,
+ "mpls-te router-address A.B.C.D",
+ "MPLS-TE specific commands\n"
+ "Stable IP address of the advertising router\n"
+ "MPLS-TE router address in IPv4 address format\n")
+{
+ struct te_tlv_router_addr *ra = &OspfMplsTE.router_addr;
+ struct in_addr value;
+
+ if (! inet_aton (argv[0], &value))
+ {
+ vty_out (vty, "Please specify Router-Addr by A.B.C.D%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (ntohs (ra->header.type) == 0
+ || ntohl (ra->value.s_addr) != ntohl (value.s_addr))
+ {
+ listnode node;
+ struct mpls_te_link *lp;
+ int need_to_reoriginate = 0;
+
+ set_mpls_te_router_addr (value);
+
+ if (OspfMplsTE.status == disabled)
+ goto out;
+
+ for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
+ {
+ if ((lp = getdata (node)) == NULL)
+ continue;
+ if (lp->area == NULL)
+ continue;
+
+ if ((lp->flags & LPFLG_LSA_ENGAGED) == 0)
+ {
+ need_to_reoriginate = 1;
+ break;
+ }
+ }
+ for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
+ {
+ if ((lp = getdata (node)) == NULL)
+ continue;
+ if (lp->area == NULL)
+ continue;
+
+ if (need_to_reoriginate)
+ lp->flags |= LPFLG_LSA_FORCED_REFRESH;
+ else
+ ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
+ }
+
+ if (need_to_reoriginate)
+ ospf_mpls_te_foreach_area (
+ ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA);
+ }
+out:
+ return CMD_SUCCESS;
+}
+
+DEFUN (mpls_te_link_metric,
+ mpls_te_link_metric_cmd,
+ "mpls-te link metric <0-4294967295>",
+ "MPLS-TE specific commands\n"
+ "Configure MPLS-TE link parameters\n"
+ "Link metric for MPLS-TE purpose\n"
+ "Metric\n")
+{
+ struct interface *ifp = (struct interface *) vty->index;
+ struct mpls_te_link *lp;
+ u_int32_t value;
+
+ if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
+ {
+ vty_out (vty, "mpls_te_link_metric: Something wrong!%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ value = strtoul (argv[0], NULL, 10);
+
+ if (ntohs (lp->te_metric.header.type) == 0
+ || ntohl (lp->te_metric.value) != value)
+ {
+ set_linkparams_te_metric (lp, value);
+
+ if (OspfMplsTE.status == enabled)
+ if (lp->area != NULL)
+ {
+ if (lp->flags & LPFLG_LSA_ENGAGED)
+ ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
+ else
+ ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (mpls_te_link_maxbw,
+ mpls_te_link_maxbw_cmd,
+ "mpls-te link max-bw BANDWIDTH",
+ "MPLS-TE specific commands\n"
+ "Configure MPLS-TE link parameters\n"
+ "Maximum bandwidth that can be used\n"
+ "Bytes/second (IEEE floating point format)\n")
+{
+ struct interface *ifp = (struct interface *) vty->index;
+ struct mpls_te_link *lp;
+ float f1, f2;
+
+ if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
+ {
+ vty_out (vty, "mpls_te_link_maxbw: Something wrong!%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ntohf (&lp->max_bw.value, &f1);
+ if (sscanf (argv[0], "%g", &f2) != 1)
+ {
+ vty_out (vty, "mpls_te_link_maxbw: fscanf: %s%s", strerror (errno), VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (ntohs (lp->max_bw.header.type) == 0
+ || f1 != f2)
+ {
+ set_linkparams_max_bw (lp, &f2);
+
+ if (OspfMplsTE.status == enabled)
+ if (lp->area != NULL)
+ {
+ if (lp->flags & LPFLG_LSA_ENGAGED)
+ ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
+ else
+ ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (mpls_te_link_max_rsv_bw,
+ mpls_te_link_max_rsv_bw_cmd,
+ "mpls-te link max-rsv-bw BANDWIDTH",
+ "MPLS-TE specific commands\n"
+ "Configure MPLS-TE link parameters\n"
+ "Maximum bandwidth that may be reserved\n"
+ "Bytes/second (IEEE floating point format)\n")
+{
+ struct interface *ifp = (struct interface *) vty->index;
+ struct mpls_te_link *lp;
+ float f1, f2;
+
+ if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
+ {
+ vty_out (vty, "mpls_te_link_max_rsv_bw: Something wrong!%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ntohf (&lp->max_rsv_bw.value, &f1);
+ if (sscanf (argv[0], "%g", &f2) != 1)
+ {
+ vty_out (vty, "mpls_te_link_max_rsv_bw: fscanf: %s%s", strerror (errno), VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (ntohs (lp->max_rsv_bw.header.type) == 0
+ || f1 != f2)
+ {
+ set_linkparams_max_rsv_bw (lp, &f2);
+
+ if (OspfMplsTE.status == enabled)
+ if (lp->area != NULL)
+ {
+ if (lp->flags & LPFLG_LSA_ENGAGED)
+ ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
+ else
+ ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (mpls_te_link_unrsv_bw,
+ mpls_te_link_unrsv_bw_cmd,
+ "mpls-te link unrsv-bw <0-7> BANDWIDTH",
+ "MPLS-TE specific commands\n"
+ "Configure MPLS-TE link parameters\n"
+ "Unreserved bandwidth at each priority level\n"
+ "Priority\n"
+ "Bytes/second (IEEE floating point format)\n")
+{
+ struct interface *ifp = (struct interface *) vty->index;
+ struct mpls_te_link *lp;
+ int priority;
+ float f1, f2;
+
+ if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
+ {
+ vty_out (vty, "mpls_te_link_unrsv_bw: Something wrong!%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* We don't have to consider about range check here. */
+ if (sscanf (argv[0], "%d", &priority) != 1)
+ {
+ vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", strerror (errno), VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ntohf (&lp->unrsv_bw.value [priority], &f1);
+ if (sscanf (argv[1], "%g", &f2) != 1)
+ {
+ vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", strerror (errno), VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (ntohs (lp->unrsv_bw.header.type) == 0
+ || f1 != f2)
+ {
+ set_linkparams_unrsv_bw (lp, priority, &f2);
+
+ if (OspfMplsTE.status == enabled)
+ if (lp->area != NULL)
+ {
+ if (lp->flags & LPFLG_LSA_ENGAGED)
+ ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
+ else
+ ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (mpls_te_link_rsc_clsclr,
+ mpls_te_link_rsc_clsclr_cmd,
+ "mpls-te link rsc-clsclr BITPATTERN",
+ "MPLS-TE specific commands\n"
+ "Configure MPLS-TE link parameters\n"
+ "Administrative group membership\n"
+ "32-bit Hexadecimal value (ex. 0xa1)\n")
+{
+ struct interface *ifp = (struct interface *) vty->index;
+ struct mpls_te_link *lp;
+ unsigned long value;
+
+ if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
+ {
+ vty_out (vty, "mpls_te_link_rsc_clsclr: Something wrong!%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (sscanf (argv[0], "0x%lx", &value) != 1)
+ {
+ vty_out (vty, "mpls_te_link_rsc_clsclr: fscanf: %s%s", strerror (errno), VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (ntohs (lp->rsc_clsclr.header.type) == 0
+ || ntohl (lp->rsc_clsclr.value) != value)
+ {
+ set_linkparams_rsc_clsclr (lp, value);
+
+ if (OspfMplsTE.status == enabled)
+ if (lp->area != NULL)
+ {
+ if (lp->flags & LPFLG_LSA_ENGAGED)
+ ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
+ else
+ ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_mpls_te_router,
+ show_mpls_te_router_cmd,
+ "show mpls-te router",
+ SHOW_STR
+ "MPLS-TE information\n"
+ "Router information\n")
+{
+ if (OspfMplsTE.status == enabled)
+ {
+ vty_out (vty, "--- MPLS-TE router parameters ---%s",
+ VTY_NEWLINE);
+
+ if (ntohs (OspfMplsTE.router_addr.header.type) != 0)
+ show_vty_router_addr (vty, &OspfMplsTE.router_addr.header);
+ else if (vty != NULL)
+ vty_out (vty, " N/A%s", VTY_NEWLINE);
+ }
+ return CMD_SUCCESS;
+}
+
+static void
+show_mpls_te_link_sub (struct vty *vty, struct interface *ifp)
+{
+ struct mpls_te_link *lp;
+ struct te_tlv_header *tlvh;
+
+ if ((OspfMplsTE.status == enabled)
+ && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0)
+ && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL))
+ {
+ vty_out (vty, "-- MPLS-TE link parameters for %s --%s",
+ ifp->name, VTY_NEWLINE);
+
+ show_vty_link_subtlv_link_type (vty, &lp->link_type.header);
+ show_vty_link_subtlv_link_id (vty, &lp->link_id.header);
+
+ if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL)
+ show_vty_link_subtlv_lclif_ipaddr (vty, tlvh);
+ if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL)
+ show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh);
+
+ show_vty_link_subtlv_te_metric (vty, &lp->te_metric.header);
+
+ show_vty_link_subtlv_max_bw (vty, &lp->max_bw.header);
+ show_vty_link_subtlv_max_rsv_bw (vty, &lp->max_rsv_bw.header);
+ show_vty_link_subtlv_unrsv_bw (vty, &lp->unrsv_bw.header);
+ show_vty_link_subtlv_rsc_clsclr (vty, &lp->rsc_clsclr.header);
+ }
+ else
+ {
+ vty_out (vty, " %s: MPLS-TE is disabled on this interface%s",
+ ifp->name, VTY_NEWLINE);
+ }
+
+ return;
+}
+
+DEFUN (show_mpls_te_link,
+ show_mpls_te_link_cmd,
+ "show mpls-te interface [INTERFACE]",
+ SHOW_STR
+ "MPLS-TE information\n"
+ "Interface information\n"
+ "Interface name\n")
+{
+ struct interface *ifp;
+ listnode node;
+
+ /* Show All Interfaces. */
+ if (argc == 0)
+ for (node = listhead (iflist); node; nextnode (node))
+ show_mpls_te_link_sub (vty, node->data);
+ /* Interface name is specified. */
+ else
+ {
+ if ((ifp = if_lookup_by_name (argv[0])) == NULL)
+ vty_out (vty, "No such interface name%s", VTY_NEWLINE);
+ else
+ show_mpls_te_link_sub (vty, ifp);
+ }
+
+ return CMD_SUCCESS;
+}
+
+static void
+ospf_mpls_te_register_vty (void)
+{
+ install_element (VIEW_NODE, &show_mpls_te_router_cmd);
+ install_element (VIEW_NODE, &show_mpls_te_link_cmd);
+ install_element (ENABLE_NODE, &show_mpls_te_router_cmd);
+ install_element (ENABLE_NODE, &show_mpls_te_link_cmd);
+
+ install_element (OSPF_NODE, &mpls_te_cmd);
+ install_element (OSPF_NODE, &no_mpls_te_cmd);
+ install_element (OSPF_NODE, &mpls_te_on_cmd);
+ install_element (OSPF_NODE, &mpls_te_router_addr_cmd);
+
+ install_element (INTERFACE_NODE, &mpls_te_link_metric_cmd);
+ install_element (INTERFACE_NODE, &mpls_te_link_maxbw_cmd);
+ install_element (INTERFACE_NODE, &mpls_te_link_max_rsv_bw_cmd);
+ install_element (INTERFACE_NODE, &mpls_te_link_unrsv_bw_cmd);
+ install_element (INTERFACE_NODE, &mpls_te_link_rsc_clsclr_cmd);
+
+ return;
+}
+
+#endif /* HAVE_OSPF_TE */
diff --git a/ospfd/ospf_te.h b/ospfd/ospf_te.h
new file mode 100644
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->|<Resv'd>|<-- Instance --->|
+ *
+ *
+ * Type: IANA has assigned '1' for Traffic Engineering.
+ * MBZ: Reserved, must be set to zero.
+ * Instance: User may select an arbitrary 16-bit value.
+ *
+ */
+
+#define LEGAL_TE_INSTANCE_RANGE(i) (0 <= (i) && (i) <= 0xffff)
+
+/*
+ * 24 16 8 0
+ * +--------+--------+--------+--------+ ---
+ * | LS age |Options | 10 | A
+ * +--------+--------+--------+--------+ |
+ * | 1 | 0 | Instance | |
+ * +--------+--------+--------+--------+ |
+ * | Advertising router | | Standard (Opaque) LSA header;
+ * +--------+--------+--------+--------+ | Only type-10 is used.
+ * | LS sequence number | |
+ * +--------+--------+--------+--------+ |
+ * | LS checksum | Length | V
+ * +--------+--------+--------+--------+ ---
+ * | Type | Length | A
+ * +--------+--------+--------+--------+ | TLV part for TE; Values might be
+ * | Values ... | V structured as a set of sub-TLVs.
+ * +--------+--------+--------+--------+ ---
+ */
+
+/*
+ * Following section defines TLV (tag, length, value) structures,
+ * used for Traffic Engineering.
+ */
+struct te_tlv_header
+{
+ u_int16_t type; /* TE_TLV_XXX (see below) */
+ u_int16_t length; /* Value portion only, in octets */
+};
+
+#define TLV_HDR_SIZE \
+ sizeof (struct te_tlv_header)
+
+#define TLV_BODY_SIZE(tlvh) \
+ ROUNDUP (ntohs ((tlvh)->length), sizeof (u_int32_t))
+
+#define TLV_SIZE(tlvh) \
+ (TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh))
+
+#define TLV_HDR_TOP(lsah) \
+ (struct te_tlv_header *)((char *)(lsah) + OSPF_LSA_HEADER_SIZE)
+
+#define TLV_HDR_NEXT(tlvh) \
+ (struct te_tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh))
+
+/*
+ * Following section defines TLV body parts.
+ */
+/* Router Address TLV *//* Mandatory */
+#define TE_TLV_ROUTER_ADDR 1
+struct te_tlv_router_addr
+{
+ struct te_tlv_header header; /* Value length is 4 octets. */
+ struct in_addr value;
+};
+
+/* Link TLV */
+#define TE_TLV_LINK 2
+struct te_tlv_link
+{
+ struct te_tlv_header header;
+ /* A set of link-sub-TLVs will follow. */
+};
+
+/* Link Type Sub-TLV *//* Mandatory */
+#define TE_LINK_SUBTLV_LINK_TYPE 1
+struct te_link_subtlv_link_type
+{
+ struct te_tlv_header header; /* Value length is 1 octet. */
+ struct {
+#define LINK_TYPE_SUBTLV_VALUE_PTP 1
+#define LINK_TYPE_SUBTLV_VALUE_MA 2
+ u_char value;
+ u_char padding[3];
+ } link_type;
+};
+
+/* Link Sub-TLV: Link ID *//* Mandatory */
+#define TE_LINK_SUBTLV_LINK_ID 2
+struct te_link_subtlv_link_id
+{
+ struct te_tlv_header header; /* Value length is 4 octets. */
+ struct in_addr value; /* Same as router-lsa's link-id. */
+};
+
+/* Link Sub-TLV: Local Interface IP Address *//* Optional */
+#define TE_LINK_SUBTLV_LCLIF_IPADDR 3
+struct te_link_subtlv_lclif_ipaddr
+{
+ struct te_tlv_header header; /* Value length is 4 x N octets. */
+ struct in_addr value[1]; /* Local IP address(es). */
+};
+
+/* Link Sub-TLV: Remote Interface IP Address *//* Optional */
+#define TE_LINK_SUBTLV_RMTIF_IPADDR 4
+struct te_link_subtlv_rmtif_ipaddr
+{
+ struct te_tlv_header header; /* Value length is 4 x N octets. */
+ struct in_addr value[1]; /* Neighbor's IP address(es). */
+};
+
+/* Link Sub-TLV: Traffic Engineering Metric *//* Optional */
+#define TE_LINK_SUBTLV_TE_METRIC 5
+struct te_link_subtlv_te_metric
+{
+ struct te_tlv_header header; /* Value length is 4 octets. */
+ u_int32_t value; /* Link metric for TE purpose. */
+};
+
+/* Link Sub-TLV: Maximum Bandwidth *//* Optional */
+#define TE_LINK_SUBTLV_MAX_BW 6
+struct te_link_subtlv_max_bw
+{
+ struct te_tlv_header header; /* Value length is 4 octets. */
+ float value; /* bytes/sec */
+};
+
+/* Link Sub-TLV: Maximum Reservable Bandwidth *//* Optional */
+#define TE_LINK_SUBTLV_MAX_RSV_BW 7
+struct te_link_subtlv_max_rsv_bw
+{
+ struct te_tlv_header header; /* Value length is 4 octets. */
+ float value; /* bytes/sec */
+};
+
+/* Link Sub-TLV: Unreserved Bandwidth *//* Optional */
+#define TE_LINK_SUBTLV_UNRSV_BW 8
+struct te_link_subtlv_unrsv_bw
+{
+ struct te_tlv_header header; /* Value length is 32 octets. */
+ float value[8]; /* One for each priority level. */
+};
+
+/* Link Sub-TLV: Resource Class/Color *//* Optional */
+#define TE_LINK_SUBTLV_RSC_CLSCLR 9
+struct te_link_subtlv_rsc_clsclr
+{
+ struct te_tlv_header header; /* Value length is 4 octets. */
+ u_int32_t value; /* Admin. group membership. */
+};
+
+/* Here are "non-official" architechtual constants. */
+#define MPLS_TE_MINIMUM_BANDWIDTH 1.0 /* Reasonable? *//* XXX */
+
+/* Prototypes. */
+extern int ospf_mpls_te_init (void);
+extern void ospf_mpls_te_term (void);
+
+#endif /* _ZEBRA_OSPF_MPLS_TE_H */
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
new file mode 100644
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 <zebra.h>
+
+#include "memory.h"
+#include "thread.h"
+#include "prefix.h"
+#include "table.h"
+#include "vty.h"
+#include "command.h"
+#include "plist.h"
+#include "log.h"
+#include "zclient.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_zebra.h"
+/*#include "ospfd/ospf_routemap.h" */
+#include "ospfd/ospf_vty.h"
+#include "ospfd/ospf_dump.h"
+
+
+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 <grantma@anathoth.gen.nz>
+ Wed, 21 Feb 2001 15:13:52 +1300
+ */
+
+
+/* Configuration data for virtual links
+ */
+struct ospf_vl_config_data {
+ struct vty *vty; /* vty stuff */
+ struct in_addr area_id; /* area ID from command line */
+ int format; /* command line area ID format */
+ struct in_addr vl_peer; /* command line vl_peer */
+ int auth_type; /* Authehntication type, if given */
+ char *auth_key; /* simple password if present */
+ int crypto_key_id; /* Cryptographic key ID */
+ char *md5_key; /* MD5 authentication key */
+ int hello_interval; /* Obvious what these are... */
+ int retransmit_interval;
+ int transmit_delay;
+ int dead_interval;
+};
+
+void
+ospf_vl_config_data_init (struct ospf_vl_config_data *vl_config,
+ struct vty *vty)
+{
+ memset (vl_config, 0, sizeof (struct ospf_vl_config_data));
+ vl_config->auth_type = OSPF_AUTH_CMD_NOTSEEN;
+ vl_config->vty = vty;
+}
+
+struct ospf_vl_data *
+ospf_find_vl_data (struct ospf_vl_config_data *vl_config)
+{
+ struct ospf_area *area;
+ struct ospf_vl_data *vl_data;
+ struct vty *vty;
+ struct in_addr area_id;
+
+ vty = vl_config->vty;
+ area_id = vl_config->area_id;
+
+ if (area_id.s_addr == OSPF_AREA_BACKBONE)
+ {
+ vty_out (vty,
+ "Configuring VLs over the backbone is not allowed%s",
+ VTY_NEWLINE);
+ return NULL;
+ }
+ area = ospf_area_get (area_id, vl_config->format);
+
+ if (area->external_routing != OSPF_AREA_DEFAULT)
+ {
+ if (vl_config->format == OSPF_AREA_ID_FORMAT_ADDRESS)
+ vty_out (vty, "Area %s is %s%s",
+ inet_ntoa (area_id),
+#ifdef HAVE_NSSA
+ area->external_routing == OSPF_AREA_NSSA?"nssa":"stub",
+#else
+ "stub",
+#endif /* HAVE_NSSA */
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "Area %ld is %s%s",
+ (u_long)ntohl (area_id.s_addr),
+#ifdef HAVE_NSSA
+ area->external_routing == OSPF_AREA_NSSA?"nssa":"stub",
+#else
+ "stub",
+#endif /* HAVE_NSSA */
+ VTY_NEWLINE);
+ return NULL;
+ }
+
+ if ((vl_data = ospf_vl_lookup (area, vl_config->vl_peer)) == NULL)
+ {
+ vl_data = ospf_vl_data_new (area, vl_config->vl_peer);
+ if (vl_data->vl_oi == NULL)
+ {
+ vl_data->vl_oi = ospf_vl_new (vl_data);
+ ospf_vl_add (vl_data);
+ ospf_spf_calculate_schedule ();
+ }
+ }
+ return vl_data;
+}
+
+
+int
+ospf_vl_set_security (struct ospf_vl_data *vl_data,
+ struct ospf_vl_config_data *vl_config)
+{
+ struct crypt_key *ck;
+ struct vty *vty;
+ struct interface *ifp = vl_data->vl_oi->ifp;
+
+ vty = vl_config->vty;
+
+ if (vl_config->auth_type != OSPF_AUTH_CMD_NOTSEEN)
+ {
+ SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_type);
+ IF_DEF_PARAMS (ifp)->auth_type = vl_config->auth_type;
+ }
+
+ if (vl_config->auth_key)
+ {
+ memset(IF_DEF_PARAMS (ifp)->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE+1);
+ strncpy (IF_DEF_PARAMS (ifp)->auth_simple, vl_config->auth_key,
+ OSPF_AUTH_SIMPLE_SIZE);
+ }
+ else if (vl_config->md5_key)
+ {
+ if (ospf_crypt_key_lookup (IF_DEF_PARAMS (ifp)->auth_crypt, vl_config->crypto_key_id)
+ != NULL)
+ {
+ vty_out (vty, "OSPF: Key %d already exists%s",
+ vl_config->crypto_key_id, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ ck = ospf_crypt_key_new ();
+ ck->key_id = vl_config->crypto_key_id;
+ memset(ck->auth_key, 0, OSPF_AUTH_MD5_SIZE+1);
+ strncpy (ck->auth_key, vl_config->md5_key, OSPF_AUTH_MD5_SIZE);
+
+ ospf_crypt_key_add (IF_DEF_PARAMS (ifp)->auth_crypt, ck);
+ }
+ else if (vl_config->crypto_key_id != 0)
+ {
+ /* Delete a key */
+
+ if (ospf_crypt_key_lookup (IF_DEF_PARAMS (ifp)->auth_crypt,
+ vl_config->crypto_key_id) == NULL)
+ {
+ vty_out (vty, "OSPF: Key %d does not exist%s",
+ vl_config->crypto_key_id, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ospf_crypt_key_delete (IF_DEF_PARAMS (ifp)->auth_crypt, vl_config->crypto_key_id);
+
+ }
+
+ return CMD_SUCCESS;
+}
+
+
+
+int
+ospf_vl_set_timers (struct ospf_vl_data *vl_data,
+ struct ospf_vl_config_data *vl_config)
+{
+ struct interface *ifp = ifp = vl_data->vl_oi->ifp;
+ /* Virtual Link data initialised to defaults, so only set
+ if a value given */
+ if (vl_config->hello_interval)
+ {
+ SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_hello);
+ IF_DEF_PARAMS (ifp)->v_hello = vl_config->hello_interval;
+ }
+
+ if (vl_config->dead_interval)
+ {
+ SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_wait);
+ IF_DEF_PARAMS (ifp)->v_wait = vl_config->dead_interval;
+ }
+
+ if (vl_config->retransmit_interval)
+ {
+ SET_IF_PARAM (IF_DEF_PARAMS (ifp), retransmit_interval);
+ IF_DEF_PARAMS (ifp)->retransmit_interval = vl_config->retransmit_interval;
+ }
+
+ if (vl_config->transmit_delay)
+ {
+ SET_IF_PARAM (IF_DEF_PARAMS (ifp), transmit_delay);
+ IF_DEF_PARAMS (ifp)->transmit_delay = vl_config->transmit_delay;
+ }
+
+ return CMD_SUCCESS;
+}
+
+
+
+/* The business end of all of the above */
+int
+ospf_vl_set (struct ospf_vl_config_data *vl_config)
+{
+ struct ospf_vl_data *vl_data;
+ int ret;
+
+ vl_data = ospf_find_vl_data (vl_config);
+ if (!vl_data)
+ return CMD_WARNING;
+
+ /* Process this one first as it can have a fatal result, which can
+ only logically occur if the virtual link exists already
+ Thus a command error does not result in a change to the
+ running configuration such as unexpectedly altered timer
+ values etc.*/
+ ret = ospf_vl_set_security (vl_data, vl_config);
+ if (ret != CMD_SUCCESS)
+ return ret;
+
+ /* Set any time based parameters, these area already range checked */
+
+ ret = ospf_vl_set_timers (vl_data, vl_config);
+ if (ret != CMD_SUCCESS)
+ return ret;
+
+ return CMD_SUCCESS;
+
+}
+
+/* This stuff exists to make specifying all the alias commands A LOT simpler
+ */
+#define VLINK_HELPSTR_IPADDR \
+ "OSPF area parameters\n" \
+ "OSPF area ID in IP address format\n" \
+ "OSPF area ID as a decimal value\n" \
+ "Configure a virtual link\n" \
+ "Router ID of the remote ABR\n"
+
+#define VLINK_HELPSTR_AUTHTYPE_SIMPLE \
+ "Enable authentication on this virtual link\n" \
+ "dummy string \n"
+
+#define VLINK_HELPSTR_AUTHTYPE_ALL \
+ VLINK_HELPSTR_AUTHTYPE_SIMPLE \
+ "Use null authentication\n" \
+ "Use message-digest authentication\n"
+
+#define VLINK_HELPSTR_TIME_PARAM_NOSECS \
+ "Time between HELLO packets\n" \
+ "Time between retransmitting lost link state advertisements\n" \
+ "Link state transmit delay\n" \
+ "Interval after which a neighbor is declared dead\n"
+
+#define VLINK_HELPSTR_TIME_PARAM \
+ VLINK_HELPSTR_TIME_PARAM_NOSECS \
+ "Seconds\n"
+
+#define VLINK_HELPSTR_AUTH_SIMPLE \
+ "Authentication password (key)\n" \
+ "The OSPF password (key)"
+
+#define VLINK_HELPSTR_AUTH_MD5 \
+ "Message digest authentication password (key)\n" \
+ "dummy string \n" \
+ "Key ID\n" \
+ "Use MD5 algorithm\n" \
+ "The OSPF password (key)"
+
+DEFUN (area_vlink,
+ area_vlink_cmd,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D",
+ VLINK_HELPSTR_IPADDR)
+{
+ struct ospf_vl_config_data vl_config;
+ char auth_key[OSPF_AUTH_SIMPLE_SIZE+1];
+ char md5_key[OSPF_AUTH_MD5_SIZE+1];
+ int i;
+ int ret;
+
+ ospf_vl_config_data_init(&vl_config, vty);
+
+ /* Read off first 2 parameters and check them */
+ ret = ospf_str2area_id (argv[0], &vl_config.area_id, &vl_config.format);
+ if (ret < 0)
+ {
+ vty_out (vty, "OSPF area ID is invalid%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ret = inet_aton (argv[1], &vl_config.vl_peer);
+ if (! ret)
+ {
+ vty_out (vty, "Please specify valid Router ID as a.b.c.d%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (argc <=2)
+ {
+ /* Thats all folks! - BUGS B. strikes again!!!*/
+
+ return ospf_vl_set (&vl_config);
+ }
+
+ /* Deal with other parameters */
+ for (i=2; i < argc; i++)
+ {
+
+ /* vty_out (vty, "argv[%d] - %s%s", i, argv[i], VTY_NEWLINE); */
+
+ switch (argv[i][0])
+ {
+
+ case 'a':
+ if (i > 2 || strncmp (argv[i], "authentication-", 15) == 0)
+ {
+ /* authentication-key - this option can occur anywhere on
+ command line. At start of command line
+ must check for authentication option. */
+ memset (auth_key, 0, OSPF_AUTH_SIMPLE_SIZE + 1);
+ strncpy (auth_key, argv[i+1], OSPF_AUTH_SIMPLE_SIZE);
+ vl_config.auth_key = auth_key;
+ i++;
+ }
+ else if (strncmp (argv[i], "authentication", 14) == 0)
+ {
+ /* authentication - this option can only occur at start
+ of command line */
+ vl_config.auth_type = OSPF_AUTH_SIMPLE;
+ if ((i+1) < argc)
+ {
+ if (strncmp (argv[i+1], "n", 1) == 0)
+ {
+ /* "authentication null" */
+ vl_config.auth_type = OSPF_AUTH_NULL;
+ i++;
+ }
+ else if (strncmp (argv[i+1], "m", 1) == 0
+ && strcmp (argv[i+1], "message-digest-") != 0)
+ {
+ /* "authentication message-digest" */
+ vl_config.auth_type = OSPF_AUTH_CRYPTOGRAPHIC;
+ i++;
+ }
+ }
+ }
+ break;
+
+ case 'm':
+ /* message-digest-key */
+ i++;
+ vl_config.crypto_key_id = strtol (argv[i], NULL, 10);
+ if (vl_config.crypto_key_id < 0)
+ return CMD_WARNING;
+ i++;
+ memset(md5_key, 0, OSPF_AUTH_MD5_SIZE+1);
+ strncpy (md5_key, argv[i], OSPF_AUTH_MD5_SIZE);
+ vl_config.md5_key = md5_key;
+ break;
+
+ case 'h':
+ /* Hello interval */
+ i++;
+ vl_config.hello_interval = strtol (argv[i], NULL, 10);
+ if (vl_config.hello_interval < 0)
+ return CMD_WARNING;
+ break;
+
+ case 'r':
+ /* Retransmit Interval */
+ i++;
+ vl_config.retransmit_interval = strtol (argv[i], NULL, 10);
+ if (vl_config.retransmit_interval < 0)
+ return CMD_WARNING;
+ break;
+
+ case 't':
+ /* Transmit Delay */
+ i++;
+ vl_config.transmit_delay = strtol (argv[i], NULL, 10);
+ if (vl_config.transmit_delay < 0)
+ return CMD_WARNING;
+ break;
+
+ case 'd':
+ /* Dead Interval */
+ i++;
+ vl_config.dead_interval = strtol (argv[i], NULL, 10);
+ if (vl_config.dead_interval < 0)
+ return CMD_WARNING;
+ break;
+ }
+ }
+
+
+ /* Action configuration */
+
+ return ospf_vl_set (&vl_config);
+
+}
+
+DEFUN (no_area_vlink,
+ no_area_vlink_cmd,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D",
+ NO_STR
+ VLINK_HELPSTR_IPADDR)
+{
+ struct ospf_area *area;
+ struct ospf_vl_config_data vl_config;
+ struct ospf_vl_data *vl_data = NULL;
+ char auth_key[OSPF_AUTH_SIMPLE_SIZE+1];
+ int i;
+ int ret, format;
+
+ ospf_vl_config_data_init(&vl_config, vty);
+
+ ret = ospf_str2area_id (argv[0], &vl_config.area_id, &format);
+ if (ret < 0)
+ {
+ vty_out (vty, "OSPF area ID is invalid%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ area = ospf_area_lookup_by_area_id (vl_config.area_id);
+ if (!area)
+ {
+ vty_out (vty, "Area does not exist%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ret = inet_aton (argv[1], &vl_config.vl_peer);
+ if (! ret)
+ {
+ vty_out (vty, "Please specify valid Router ID as a.b.c.d%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (argc <=2)
+ {
+ /* Basic VLink no command */
+ /* Thats all folks! - BUGS B. strikes again!!!*/
+ if ((vl_data = ospf_vl_lookup (area, vl_config.vl_peer)))
+ ospf_vl_delete (vl_data);
+
+ ospf_area_check_free (vl_config.area_id);
+
+ return CMD_SUCCESS;
+ }
+
+ /* If we are down here, we are reseting parameters */
+
+ /* Deal with other parameters */
+ for (i=2; i < argc; i++)
+ {
+
+ /* vty_out (vty, "argv[%d] - %s%s", i, argv[i], VTY_NEWLINE); */
+
+ switch (argv[i][0])
+ {
+
+ case 'a':
+ if (i > 2 || strncmp (argv[i], "authentication-", 15) == 0)
+ {
+ /* authentication-key - this option can occur anywhere on
+ command line. At start of command line
+ must check for authentication option. */
+ memset (auth_key, 0, OSPF_AUTH_SIMPLE_SIZE + 1);
+ vl_config.auth_key = auth_key;
+ }
+ else if (strncmp (argv[i], "authentication", 14) == 0)
+ {
+ /* authentication - this option can only occur at start
+ of command line */
+ vl_config.auth_type = OSPF_AUTH_NOTSET;
+ }
+ break;
+
+ case 'm':
+ /* message-digest-key */
+ /* Delete one key */
+ i++;
+ vl_config.crypto_key_id = strtol (argv[i], NULL, 10);
+ if (vl_config.crypto_key_id < 0)
+ return CMD_WARNING;
+ vl_config.md5_key = NULL;
+ break;
+
+ case 'h':
+ /* Hello interval */
+ vl_config.hello_interval = OSPF_HELLO_INTERVAL_DEFAULT;
+ break;
+
+ case 'r':
+ /* Retransmit Interval */
+ vl_config.retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT;
+ break;
+
+ case 't':
+ /* Transmit Delay */
+ vl_config.transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT;
+ break;
+
+ case 'd':
+ /* Dead Interval */
+ i++;
+ vl_config.dead_interval = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT;
+ break;
+ }
+ }
+
+
+ /* Action configuration */
+
+ return ospf_vl_set (&vl_config);
+}
+
+ALIAS (area_vlink,
+ area_vlink_param1_cmd,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>",
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_TIME_PARAM)
+
+ALIAS (no_area_vlink,
+ no_area_vlink_param1_cmd,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval)",
+ NO_STR
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_TIME_PARAM)
+
+ALIAS (area_vlink,
+ area_vlink_param2_cmd,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>",
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_TIME_PARAM
+ VLINK_HELPSTR_TIME_PARAM)
+
+ALIAS (no_area_vlink,
+ no_area_vlink_param2_cmd,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval)",
+ NO_STR
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_TIME_PARAM
+ VLINK_HELPSTR_TIME_PARAM)
+
+ALIAS (area_vlink,
+ area_vlink_param3_cmd,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>",
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_TIME_PARAM
+ VLINK_HELPSTR_TIME_PARAM
+ VLINK_HELPSTR_TIME_PARAM)
+
+ALIAS (no_area_vlink,
+ no_area_vlink_param3_cmd,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval)",
+ NO_STR
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_TIME_PARAM
+ VLINK_HELPSTR_TIME_PARAM
+ VLINK_HELPSTR_TIME_PARAM)
+
+ALIAS (area_vlink,
+ area_vlink_param4_cmd,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>",
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_TIME_PARAM
+ VLINK_HELPSTR_TIME_PARAM
+ VLINK_HELPSTR_TIME_PARAM
+ VLINK_HELPSTR_TIME_PARAM)
+
+ALIAS (no_area_vlink,
+ no_area_vlink_param4_cmd,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval)",
+ NO_STR
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_TIME_PARAM
+ VLINK_HELPSTR_TIME_PARAM
+ VLINK_HELPSTR_TIME_PARAM
+ VLINK_HELPSTR_TIME_PARAM)
+
+ALIAS (area_vlink,
+ area_vlink_authtype_args_cmd,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication|) (message-digest|null)",
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_AUTHTYPE_ALL)
+
+ALIAS (area_vlink,
+ area_vlink_authtype_cmd,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication|)",
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_AUTHTYPE_SIMPLE)
+
+ALIAS (no_area_vlink,
+ no_area_vlink_authtype_cmd,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication|)",
+ NO_STR
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_AUTHTYPE_SIMPLE)
+
+ALIAS (area_vlink,
+ area_vlink_md5_cmd,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(message-digest-key|) <1-255> md5 KEY",
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_AUTH_MD5)
+
+ALIAS (no_area_vlink,
+ no_area_vlink_md5_cmd,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(message-digest-key|) <1-255>",
+ NO_STR
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_AUTH_MD5)
+
+ALIAS (area_vlink,
+ area_vlink_authkey_cmd,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication-key|) AUTH_KEY",
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_AUTH_SIMPLE)
+
+ALIAS (no_area_vlink,
+ no_area_vlink_authkey_cmd,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication-key|)",
+ NO_STR
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_AUTH_SIMPLE)
+
+ALIAS (area_vlink,
+ area_vlink_authtype_args_authkey_cmd,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication|) (message-digest|null) "
+ "(authentication-key|) AUTH_KEY",
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_AUTHTYPE_ALL
+ VLINK_HELPSTR_AUTH_SIMPLE)
+
+ALIAS (area_vlink,
+ area_vlink_authtype_authkey_cmd,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication|) "
+ "(authentication-key|) AUTH_KEY",
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_AUTHTYPE_SIMPLE
+ VLINK_HELPSTR_AUTH_SIMPLE)
+
+ALIAS (no_area_vlink,
+ no_area_vlink_authtype_authkey_cmd,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication|) "
+ "(authentication-key|)",
+ NO_STR
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_AUTHTYPE_SIMPLE
+ VLINK_HELPSTR_AUTH_SIMPLE)
+
+ALIAS (area_vlink,
+ area_vlink_authtype_args_md5_cmd,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication|) (message-digest|null) "
+ "(message-digest-key|) <1-255> md5 KEY",
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_AUTHTYPE_ALL
+ VLINK_HELPSTR_AUTH_MD5)
+
+ALIAS (area_vlink,
+ area_vlink_authtype_md5_cmd,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication|) "
+ "(message-digest-key|) <1-255> md5 KEY",
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_AUTHTYPE_SIMPLE
+ VLINK_HELPSTR_AUTH_MD5)
+
+ALIAS (no_area_vlink,
+ no_area_vlink_authtype_md5_cmd,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication|) "
+ "(message-digest-key|)",
+ NO_STR
+ VLINK_HELPSTR_IPADDR
+ VLINK_HELPSTR_AUTHTYPE_SIMPLE
+ VLINK_HELPSTR_AUTH_MD5)
+
+
+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 <zebra.h>
+
+#include "thread.h"
+#include "command.h"
+#include "network.h"
+#include "prefix.h"
+#include "routemap.h"
+#include "table.h"
+#include "stream.h"
+#include "memory.h"
+#include "zclient.h"
+#include "filter.h"
+#include "log.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_zebra.h"
+#ifdef HAVE_SNMP
+#include "ospfd/ospf_snmp.h"
+#endif /* HAVE_SNMP */
+
+/* Zebra structure to hold current status. */
+struct zclient *zclient = NULL;
+
+/* For registering threads. */
+extern struct thread_master *master;
+
+/* Inteface addition message from zebra. */
+int
+ospf_interface_add (int command, struct zclient *zclient, zebra_size_t length)
+{
+ struct interface *ifp;
+
+ ifp = zebra_interface_add_read (zclient->ibuf);
+
+ if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+ zlog_info ("Zebra: interface add %s index %d flags %ld metric %d mtu %d",
+ ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+ if (!OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), type))
+ {
+ SET_IF_PARAM (IF_DEF_PARAMS (ifp), type);
+ IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST;
+
+ if (if_is_broadcast (ifp))
+ IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST;
+ else if (if_is_pointopoint (ifp))
+ IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_POINTOPOINT;
+ else if (if_is_loopback (ifp))
+ IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_LOOPBACK;
+ }
+
+ ospf_if_update ();
+
+#ifdef HAVE_SNMP
+ ospf_snmp_if_update (ifp);
+#endif /* HAVE_SNMP */
+
+ return 0;
+}
+
+int
+ospf_interface_delete (int command, struct zclient *zclient,
+ zebra_size_t length)
+{
+ struct interface *ifp;
+ struct stream *s;
+ struct route_node *rn;
+
+ s = zclient->ibuf;
+ /* zebra_interface_state_read() updates interface structure in iflist */
+ ifp = zebra_interface_state_read (s);
+
+ if (ifp == NULL)
+ return 0;
+
+ if (if_is_up (ifp))
+ zlog_warn ("Zebra: got delete of %s, but interface is still up",
+ ifp->name);
+
+ if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+ zlog_info ("Zebra: interface delete %s index %d flags %ld metric %d mtu %d",
+ ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+#ifdef HAVE_SNMP
+ ospf_snmp_if_delete (ifp);
+#endif /* HAVE_SNMP */
+
+ for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+ if (rn->info)
+ ospf_if_free ((struct ospf_interface *) rn->info);
+
+ for (rn = route_top (IF_OIFS_PARAMS (ifp)); rn; rn = route_next (rn))
+ if (rn->info)
+ ospf_del_if_params (rn->info);
+
+ if_delete (ifp);
+
+ return 0;
+}
+
+struct interface *
+zebra_interface_if_lookup (struct stream *s)
+{
+ struct interface *ifp;
+ u_char ifname_tmp[INTERFACE_NAMSIZ];
+
+ /* Read interface name. */
+ stream_get (ifname_tmp, s, INTERFACE_NAMSIZ);
+
+ /* Lookup this by interface index. */
+ ifp = if_lookup_by_name (ifname_tmp);
+
+ /* If such interface does not exist, indicate an error */
+ if (!ifp)
+ return NULL;
+
+ return ifp;
+}
+
+void
+zebra_interface_if_set_value (struct stream *s, struct interface *ifp)
+{
+ /* Read interface's index. */
+ ifp->ifindex = stream_getl (s);
+
+ /* Read interface's value. */
+ ifp->flags = stream_getl (s);
+ ifp->metric = stream_getl (s);
+ ifp->mtu = stream_getl (s);
+ ifp->bandwidth = stream_getl (s);
+}
+
+int
+ospf_interface_state_up (int command, struct zclient *zclient,
+ zebra_size_t length)
+{
+ struct interface *ifp;
+ struct interface if_tmp;
+ struct ospf_interface *oi;
+ struct route_node *rn;
+
+ ifp = zebra_interface_if_lookup (zclient->ibuf);
+
+ if (ifp == NULL)
+ return 0;
+
+ /* Interface is already up. */
+ if (if_is_up (ifp))
+ {
+ /* Temporarily keep ifp values. */
+ memcpy (&if_tmp, ifp, sizeof (struct interface));
+
+ zebra_interface_if_set_value (zclient->ibuf, ifp);
+
+ if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+ zlog_info ("Zebra: Interface[%s] state update.", ifp->name);
+
+ if (if_tmp.bandwidth != ifp->bandwidth)
+ {
+ if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+ zlog_info ("Zebra: Interface[%s] bandwidth change %d -> %d.",
+ ifp->name, if_tmp.bandwidth, ifp->bandwidth);
+
+ ospf_if_recalculate_output_cost (ifp);
+ }
+ return 0;
+ }
+
+ zebra_interface_if_set_value (zclient->ibuf, ifp);
+
+ if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+ zlog_info ("Zebra: Interface[%s] state change to up.", ifp->name);
+
+ for (rn = route_top (IF_OIFS (ifp));rn; rn = route_next (rn))
+ {
+ if ( (oi = rn->info) == NULL)
+ continue;
+
+ ospf_if_up (oi);
+ }
+
+ return 0;
+}
+
+int
+ospf_interface_state_down (int command, struct zclient *zclient,
+ zebra_size_t length)
+{
+ struct interface *ifp;
+ struct ospf_interface *oi;
+ struct route_node *node;
+
+ ifp = zebra_interface_state_read (zclient->ibuf);
+
+ if (ifp == NULL)
+ return 0;
+
+ if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+ zlog_info ("Zebra: Interface[%s] state change to down.", ifp->name);
+
+ for (node = route_top (IF_OIFS (ifp));node; node = route_next (node))
+ {
+ if ( (oi = node->info) == NULL)
+ continue;
+ ospf_if_down (oi);
+ }
+
+ return 0;
+}
+
+int
+ospf_interface_address_add (int command, struct zclient *zclient,
+ zebra_size_t length)
+{
+ struct connected *c;
+
+ c = zebra_interface_address_add_read (zclient->ibuf);
+
+ if (c == NULL)
+ return 0;
+
+#if 0
+ if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+ {
+ struct prefix *p;
+
+ p = c->address;
+ if (p->family == AF_INET)
+ zlog_info (" connected address %s/%d",
+ inet_atop (p->u.prefix4), p->prefixlen);
+ }
+#endif
+
+ ospf_if_update ();
+
+#ifdef HAVE_SNMP
+ ospf_snmp_if_update (c->ifp);
+#endif /* HAVE_SNMP */
+
+ return 0;
+}
+
+int
+ospf_interface_address_delete (int command, struct zclient *zclient,
+ zebra_size_t length)
+{
+ struct connected *c;
+ struct interface *ifp;
+ struct ospf_interface *oi;
+ struct route_node *rn;
+ struct prefix p;
+
+ c = zebra_interface_address_delete_read (zclient->ibuf);
+
+ if (c == NULL)
+ return 0;
+
+ ifp = c->ifp;
+ p = *c->address;
+ p.prefixlen = IPV4_MAX_PREFIXLEN;
+
+ rn = route_node_lookup (IF_OIFS (ifp), &p);
+ if (! rn)
+ return 0;
+
+ assert (rn->info);
+ oi = rn->info;
+
+ /* Call interface hook functions to clean up */
+ ospf_if_free (oi);
+
+#ifdef HAVE_SNMP
+ ospf_snmp_if_update (c->ifp);
+#endif /* HAVE_SNMP */
+
+ connected_free (c);
+
+ ospf_if_update();
+
+ return 0;
+}
+
+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 <zebra.h>
+
+#include "thread.h"
+#include "vty.h"
+#include "command.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "table.h"
+#include "if.h"
+#include "memory.h"
+#include "stream.h"
+#include "log.h"
+#include "sockunion.h" /* for inet_aton () */
+#include "zclient.h"
+#include "plist.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_network.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ase.h"
+
+/* OSPF instance top. */
+struct ospf *ospf_top;
+
+extern struct zclient *zclient;
+
+
+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 <bsd.port.mk>
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 <kunihiro@ipinfusion.com>
+
+ * zebra-0.93 released.
+
+2002-06-30 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * ripd.c (rip_output_process): When outgoing interface is same as
+ next hop interface, announce RIPv2 next hop otherwise set next hop
+ to 0. Revert previous change then take 6WIND way.
+
+2001-09-14 Akihiro Mizutani <mizutani@dml.com>
+
+ * ripd.c: RIP enabled interface's route is advertised by default.
+
+2001-08-28 NOGUCHI Kay <kay@v6.access.co.jp>
+
+ * rip_snmp.c (rip_ifaddr_delete): Add route_node_lookup() return
+ value check.
+
+ * rip_interface.c (rip_multicast_leave): Fix bug of multiple IP
+ address on one interface multicast join/leave bug.
+
+2001-08-26 NOGUCHI Kay <kay@v6.access.co.jp>
+
+ * rip_interface.c (no_rip_passive_interface): Add NO_STR.
+
+2001-08-19 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92a released.
+
+2001-08-15 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92 released.
+
+2001-06-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_routemap.c (route_match_ip_address_prefix_list): Add match
+ ip next-hop prefix-list WORD.
+
+2001-02-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_interface.c (rip_passive_interface_clean): Call
+ rip_passive_interface_apply_all.
+
+2001-02-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_response_process): Multicast address nexthop check
+ is moved from rip_nexthop_check.
+
+2001-02-08 Matthew Grant <grantma@anathoth.gen.nz>
+
+ * rip_interface.c (ipv4_multicast_join): Use
+ setsockopt_multicast_ipv4.
+ (ipv4_multicast_leave): Likewise.
+ (rip_if_ipv4_address_check): Interface which has IPv4 address can
+ be enabled.
+
+2001-02-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_interface.c (rip_interface_delete): To support pseudo
+ interface do not free interface structure.
+ * ripd.c (rip_output_process): If output interface is in simple
+ password authentication mode, we need space for authentication
+ data.
+
+2001-02-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_nexthop_check): Fix multicast address nexthop check.
+
+ * zebra-0.91 is released.
+
+2001-01-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (show_ip_rip): Show metric infinity route's timeout.
+ (rip_rte_process): If current route is metric infinity, route is
+ replaced with received rte.
+ (rip_redistribute_delete): When redistribute route is deleted,
+ perform poisoned reverse.
+ (rip_redistribute_withdraw): Likewise.
+
+2001-01-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_response_process): RIPv2 routing table entry with
+ non directly reachable nexthop was dropped. The code is changed
+ to treat it as 0.0.0.0 nexthop.
+ (rip_destination_check): Check net 0 address destination.
+ (rip_nexthop_check): New function for checking nexthop address
+ validity.
+
+2001-01-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_request_process): Triggered update only send changed
+ route.
+
+ * rip_interface.c: Delete RIP_API part until new implementation
+ comes out.
+
+ * rip_snmp.: Likewise.
+
+ * rip_zebra.c: Likewise.
+
+ * ripd.c: Likewise.
+
+2001-01-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_interface.c (rip_if_init): Remove HAVE_IF_PSEUDO part.
+
+2001-01-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.90 is released.
+
+2001-01-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.h (RIP_VTYSH_PATH): Change "/tmp/ripd" to "/tmp/.ripd".
+
+2000-12-25 David Lipovkov <davidl@nbase.co.il>
+
+ * ripd.c (rip_rte_process): When a route is in garbage collection
+ process (invalid with metric 16) and a router receives the same
+ route with valid metric then route was not installed into zebra
+ rib, but only into ripd rib. Moreover , it will never get into
+ zebra rib, because ripd wrongly assumes it's already there.
+ (rip_redistribute_add): When doing redistribute into rip other
+ route (e.g. connected) and the same route exists in ripd rib we
+ changed it in place - bug. Now we don't forget to remove old route
+ from zebra.
+ (rip_timeout): When removing routes from zebra I made sure that we
+ remove route with the metric we have in zebra and not the new
+ one. It doesn't make a difference now,but could be significant
+ when multipath support is done.
+
+2000-12-25 David Lipovkov <davidl@nbase.co.il>
+
+ * rip_zebra.c (rip_metric_unset): Fix bug of metric value unset.
+
+2000-11-25 Frank van Maarseveen <F.vanMaarseveen@inter.NL.net>
+
+ * ripd.c (rip_request_process): Check passive flag of the
+ interface.
+
+2000-11-23 Frank van Maarseveen <F.vanMaarseveen@inter.NL.net>
+
+ * rip_interface.c (rip_multicast_join): When IP_ADD_MEMBERSHIP
+ failed do not set runnning flag to the interface.
+
+2000-11-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_output_process): Memory leak related classfull
+ network generation is fixed.
+
+2000-11-16 Frank van Maarseveen <F.vanMaarseveen@inter.NL.net>
+
+ * rip_interface.c (if_check_address): Obsolete pointopoint address
+ check is removed.
+
+2000-11-02 Frank van Maarseveen <F.vanMaarseveen@inter.NL.net>
+
+ * rip_interface.c (if_check_address): Add pointopoint address
+ check.
+ (rip_interface_up): Add check for passive interface when interface
+ goes up.
+
+2000-10-23 Jochen Friedrich <jochen@scram.de>
+
+ * rip_snmp.c: rip_oid and ripd_oid are used in smux_open after it
+ is registered. So those variables must be static.
+
+2000-10-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_interface.c: Change to "no ip rip (send|receive)" command
+ accept version number argument.
+
+2000-10-17 Akihiro Mizutani <mizutani@dml.com>
+
+ * rip_routemap.c (route_set_ip_nexthop_compile): Change "match ip
+ next-hop" from IP address to access-list name.
+
+2000-10-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_peer.c: Change ot use linklist.c instaed of newlist.c.
+
+2000-10-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_offset.c: Change to use linklist.c instead of newlist.c.
+
+2000-10-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.89 is released.
+
+2000-09-26 Akihiro Mizutani <mizutani@dml.com>
+
+ * rip_routemap.c (match_ip_nexthop): Add next-hop format check.
+
+2000-09-18 David Lipovkov <dlipovkov@OpticalAccess.com>
+
+ * rip_interface.c (ripd_api_get_if_rx_version): Corrects rip SNMP
+ and rip API functions dealing with rip version.
+
+ * rip_snmp.c (Status_Valid): SNMPv2-TC TEXTUAL-CONVENTION.
+
+2000-09-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_snmp.c (rip2IfLookup): Use rip_ifaddr_lookup_next() instead
+ of rip_if_lookup_next().
+
+ * rip_interface.c (rip_enable_network_lookup): Interface enable
+ check by interface's address with /32 prefix.
+
+ * ripd.c (rip_read): When RIP is configured with authentication
+ and no authentication in incoming packet, drop the packet.
+
+ * rip_interface.c (rip_interface_reset): RIP_AUTH_SIMPLE_PASSWORD
+ is default mode of authentication.
+ (rip_interface_new): Likewise.
+ (no_ip_rip_authentication_mode): Likewise.
+
+ * ripd.c (rip_read): Likewise.
+
+2000-09-10 David Lipovkov <davidl@nbase.co.il>
+
+ * rip_snmp.c: Set ASN_INTEGER v->type where it is needed.
+
+2000-09-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_auth_simple_password): Simple password
+ authentication using key-chain.
+ (rip_write_rte): Likewise.
+
+ * rip_interface.c (ip_rip_authentication_key_chain): Add check for
+ authentication string configuration.
+
+2000-09-08 Akihiro Mizutani <mizutani@dml.com>
+
+ * ripd.c (rip_write_rte): Add check for ri->auth_str.
+
+2000-09-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd_api.h: New file is added.
+
+2000-08-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_rte_process): rip_route_process() is renamed to
+ rip_rte_process() to clarify meanings of the function.
+ rip_route_process() is newly added to process RIP route selection.
+
+2000-08-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_incoming_filter): Extract incoming filter code to
+ function from rip_route_process(). Add check for all interface
+ filter.
+ (rip_outgoing_filter): Extract incoming filter code to function
+ from rip_output_process(). Add check for all interface filter.
+
+ * rip_zebra.c (rip_redistribute_clean): Reset redistribute status
+ when "no router rip" is performed.
+
+ * rip_interface.c (rip_interface_clean): Reset interface's RIP
+ enable status.
+
+2000-08-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_route_process): When metric infinity is received the
+ route is removed from service immediately.
+ (rip_timeout): Likewise.
+ (rip_garbage_collect): Do not delete route in garbage collection.
+ (rip_output_process): Check metric_out exceed metric infinity.
+
+ * zebra-0.88 is released.
+
+2000-08-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_distance_apply): Unlock node when there is matched
+ node.
+
+2000-08-13 Akihiro Mizutani <mizutani@dml.com>
+
+ * rip_routemap.c (match_ip_nexthop): Add check for IP address
+ validness.
+ (no_set_metric): Add new ALIAS.
+
+2000-08-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.h (struct rip ): Add distance.
+
+2000-08-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_zebra.c (rip_zebra_ipv4_add): Use new Zebra api to register
+ routes. Pass RIP metric value to zebra.
+
+2000-08-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_main.c (main): Make struct thread thread from global
+ variable to local variable in main.
+
+2000-08-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_packet_dump): Add MD5 authentication dump function.
+ (rip_auth_md5): RIP MD5 authentication packet receive works.
+
+2000-08-02 David Lipovkov <davidl@nbase.co.il>
+
+ * rip_interface.c (rip_if_init): Install interface "pseudo"
+ commands.
+ (rip_interface_delete): Do not call if_delete() when interface is
+ pseudo interface.
+
+2000-07-31 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_interface.c (ip_rip_authentication_mode): "ip rip
+ authentication mode (md5|text)" is added.
+ (ip_rip_authentication_key_chain): "ip rip authentication
+ key-chain KEY-CHAIN" is added.
+ (rip_interface_clean): Clean all interface configuration.
+ (rip_interface_reset): Reset all interface configuration.
+ (rip_clean_network): Clean rip_enable_network.
+
+ * ripd.h (struct rip_interface): Add key_chain member.
+
+ * ripd.c: Include md5-gnu.h.
+
+2000-07-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.h (RIP_NO_AUTH): Change RIP_NO_AUTH value from 1 to 0.
+
+ * ripd.c (rip_authentication): Use RIP_AUTH_SIMPLE_PASSWORD
+ instead of raw value 2.
+ (rip_write_rte): Likewise.
+ (rip_write_rte): Check ri->auth_type instead of ri->auth_str.
+
+2000-07-30 David Lipovkov <davidl@nbase.co.il>
+
+ * rip_interface.c (rip_if_down): Do not delete ZEBRA_ROUTE_KERNEL
+ route.
+
+2000-07-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_update_process): Add "passive-interface" command.
+
+ * ripd.h (struct rip_interface): Add passive member to struct
+ rip_interface.
+
+2000-07-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_interface.c (rip_if_init): Multiple RIP routes for one
+ prefix change. The codes are enclosed by #ifdef NEW_RIP_TABLE.
+
+2000-07-24 Akihiro Mizutani <mizutani@dml.com>
+
+ * rip_interface.c (rip_if_init): Use install_default() for
+ INTERFACE_NODE.
+
+2000-07-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c: First update timer will be invoked in two seconds.
+
+2000-07-09 Jochen Friedrich <jochen@scram.de>
+
+ * rip_snmp.c: Local function definitions to static. Add INTEGER
+ ASN_INTEGER and TIMETICKS ASN_TIMETICKS definition.
+ (rip2PeerLookup): Peer with domain lookup implemented.
+ (rip2PeerTable): Temporary disable RIP2PEERLASTUPDATE value
+ support due to unknown SNMP agent startup time.
+
+2000-07-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.h: Sweep obsolete definitions.
+
+ * rip_interface.c (rip_split_horizon): Add "ip split-horizon"
+ command.
+
+ * ripd.c (rip_output_process): Remove split_horizon argument.
+ (rip_update_process): Likewise.
+
+ * ripd.h (struct rip_interface): Add split_horizon flag to struct
+ rip_interface.
+
+2000-07-04 Akihiro Mizutani <mizutani@dml.com>
+
+ * ripd.c (rip_version): Change VERSION to <1-2>.
+ Add "no version" command.
+
+2000-07-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_zebra.c (rip_redistribute_type_metric): "redistribute TYPE
+ metric <0-16>" command is added.
+
+ * rip_routemap.c (route_set_metric): Set metric_set when metric is
+ modified.
+
+ * ripd.h (struct rip_info): To check route-map set metric or not,
+ new member metric_set is added to struct rip_info.
+
+ * ripd.c (rip_route_process): Move metric handling code from
+ rip_response_process() to rip_route_process().
+ (rip_output_process): Set output offset-list metric.
+
+2000-07-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_offset.c (rip_offset_list): New file for offset-list.
+
+2000-07-02 Akihiro Mizutani <mizutani@dml.com>
+
+ * ripd.h (struct rip ): Add default_metric.
+
+ * ripd.c (rip_default_metric): "default-metric <1-16>" command is
+ added.
+ (config_write_rip): Change configuration order.
+
+ * rip_zebra.c: Fix help strings.
+
+2000-07-02 David Lipovkov <davidl@nbase.co.il>
+
+ * rip_interface.c (rip_if_init): Add IF_DELETE_HOOK.
+
+2000-07-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_output_process): If specified route-map does not
+ exist, it treated as deny all.
+
+2000-06-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_routemap.c (rip_route_map_init): Call rip_route_map_update
+ when route-map is deleted.
+
+2000-06-28 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_routemap.c (set_metric): For consistency with bgpd's set
+ metric, value range is set to <0-4294967295>.
+
+2000-06-28 David Lipovkov <davidl@nbase.co.il>
+
+ * rip_routemap.c (rip_route_map_update): Add check for rip is
+ enabled or not for avoid core dump.
+
+ * rip_debug.c (debug_rip_packet_direct): Fix bug of setting
+ rip_debug_packet flag.
+
+2000-06-13 David Lipovkov <davidl@nbase.co.il>
+
+ * rip_interface.c (rip_interface_delete): All work is done in
+ rip_if_down().
+
+2000-06-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_redistribute_delete): Fix bug of missing
+ route_unlock_node() when redistribute route is not found.
+
+2000-06-05 Akihirof Mizutani <mizutani@dml.com>
+
+ * rip_debug.c (rip_debug_init): Disable show debugging in
+ VIEW_NODE like other protocol daemon.
+
+ * rip_routemap.c: Change command argument to more comprehensive.
+
+ METRIC -> <0-16>
+ IFNAME -> WORD
+ IP_ADDR -> A.B.C.D
+ ACCSESS_LIST -> WORD
+
+2000-06-05 David Lipovkov <davidl@nbase.co.il>
+
+ * rip_interface.c (rip_interface_delete): Delete all routes
+ include static and kernel through the interface , because even if
+ the interface is added again there is no guarantee that it will
+ get the same ifindex as before.
+
+2000-05-31 Akihirof Mizutani <mizutani@dml.com>
+
+ * rip_debug.c: Fix rip debug help string.
+
+2000-04-27 Mirko Karanovic <mkaranov@torsel.alcatel.com>
+
+ * rip_interface.c (rip_interface_down): Remove interface from
+ multicast group when interface goes down.
+
+2000-04-03 David Lipovkov <davidl@nbase.co.il>
+
+ * rip_interface.c (rip_interface_down): Implemented rip functions
+ for interface up/down events: rip_interface_up() and
+ rip_interface_down()
+
+2000-03-16 David Lipovkov <davidl@nbase.co.il>
+
+ * rip_zebra.c (rip_zclient_init): Added rip functions for
+ interface up/down events.
+
+2000-02-15 Hidetoshi Shimokawa <simokawa@sat.t.u-tokyo.ac.jp>
+
+ * ripd.c (rip_write_rte): "set metic" in route-map has no effect
+ for RIPv1 in ripd. It worked fine for RIPv2.
+
+2000-01-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (show_ip_protocols_rip): Fix bug of "show ip protocls"
+ mis-display RIP version.
+
+ * ripd.h (struct rip_peer): Add timeout thread to rip_peer
+ structure.
+
+2000-01-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_peer.c: Add new file for supporting RIP peer.
+
+1999-12-26 David Lipovkov <davidl@nbase.co.il>
+
+ * ripd.c (rip_authentication): RIP authantication string is 16
+ bytes long.
+
+1999-12-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_read): Add check for minimum packet length.
+ Authentication check is moved from rip_process_response() to
+ rip_read(). Patch from David Lipovkov <davidl@nbase.co.il> is
+ applied then add rte number check by Kunihiro Ishiguro
+ <kunihiro@zebra.org>.
+
+1999-12-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_response_process): In case of packet is RIPv2 and
+ network is non zero and netmask is zero, apply netmask rule as
+ same as RIPv1.
+
+1999-11-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_timers): Fix bug of timers basic argument format.
+
+1999-11-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_snmp.c (rip2IfConfAddress): Forgot to include
+ RIP2IFCONFDOMAIN.
+
+1999-10-28 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.h (struct rip_peer): New structure added.
+
+1999-10-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_zebra.c (rip_zebra_ipv4_add): Increment
+ rip_global_route_changes when route change occur.
+ (rip_zebra_ipv4_delete): Likewise.
+
+ * ripd.c (rip_request_process): Increment rip_global_queries when
+ reply to the query is sent.
+
+1999-10-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_debug.c (rip_debug_reset): Reset function added.
+
+ * ripd.c (rip_update_process): Logging bug is fixed.
+
+1999-10-10 Marc Boucher <marc@mbsi.ca>
+
+ * ripd.c (config_write_rip): Add config_write_distribute() call.
+
+1999-09-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_distribute_update): Fix bug of access-list
+ prefix-list updates.
+
+1999-09-10 VOP <vop@unity.net>
+
+ * rip_zebra.c: Add redistribute route-map feature.
+
+1999-09-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_response_process): Add check for given prefix is
+ given mask applied one.
+
+1999-09-03 VOP <vop@unity.net>
+
+ * rip_interface.c (rip_interface_multicast_set): Bug fix about
+ setting multicast interface.
+
+1999-09-02 VOP <vop@unity.net>
+
+ * rip_routemap.c: New file added.
+
+1999-09-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (show_ip_protocols_rip): Show next update time.
+ (show_ip_protocols_rip): Show redistribute information.
+
+1999-08-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * RIPv2-MIB.txt: New file added.
+
+ * rip_snmp.c: New file added.
+
+1999-08-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_interface.c (ip_rip_authentication_string): RIPv2
+ authentication command is added.
+
+1999-08-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_interface.c (rip_interface_multicast_set): Process of
+ setting IP_MULTICAST_IF on specific interface.
+
+ * ripd.c (rip_read): Add packet size check.
+
+1999-08-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_request_process): Fill in RIP_METRIC_INFINITY with
+ network byte order using htonl ().
+ (rip_response_process): Pass host byte order address to IN_CLASSC
+ and IN_CLASSB macro.
+
+1999-08-08 davidm@nbase.co.il (David Mozes)
+
+ * rip_zebra.c (rip_zebra_read_ipv4): Fix split horizon problem.
+
+1999-07-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_timer_set): Function added.
+
+1999-07-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_debug.c: New file added.
+ rip_debug.h: New file added.
+
+1999-07-01 Rick Payne <rickp@rossfell.co.uk>
+
+ * rip_zebra.c (zebra_init): Install standard commands to
+ ZEBRA_NODE.
+
+1999-06-01 David Luyer <luyer@ucs.uwa.edu.au>
+
+ * ripd.c (rip_process_route): Add support for RIP version 1.
+
+1999-05-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_zebra.c: Change to use lib/zclient.[ch].
+
+1999-05-20 Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+ * ripd.c (rip_add_route): Change the existance route's metric check
+ to the condition specified by RFC2453.
+
+1999-05-17 Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+ * ripd.c (rip_process_route): Add the if metric to the route metric.
+
+ * ripd.c (rip_add_route): Deleted add if metric to the route.
+
+1999-05-16 Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+ * rip_interface.c (if_valid_neighbor): New function.
+
+ * ripd.c (rip_process_route): Added check whether the datagram
+ is from a valid neighbor.
+
+1999-05-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_process_route): Set interface pointer to rinfo.
+
+1999-05-15 Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+ * ripd.c (rip_check_address): Unicast and not net 0 or 127 check
+ added.
+
+1999-05-14 Stephen R. van den Berg <srb@cuci.nl>
+
+ * rip_main.c (signal_init): SIGTERM call sigint.
+ (sigint): Loggging more better message.
+
+1999-05-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_add_route): Fix previous route_unlock_node() chenge.
+
+ * rip_main.c (main): Change default zlog output to ZLOG_STDOUT for
+ debugging.
+
+1999-05-09 Patrick Koppen <koppen@rhrk.uni-kl.de>
+
+ * rip_interface.c (rip_request): Fix old semantics for fetching
+ connected address.
+
+ * ripd.c (rip_add_route): Update timer when the route is updated.
+
+1999-05-09 Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+ * rip_zebra.c (struct zebra): Add ridist_static, ridist_connect,
+ redist_rip, redist_ripng.
+
+ * rip_zebra.c (zebra_create): Updated for current zebra method.
+
+ * ripd.c (rip_add_route): Add missing route_unlock_node().
+
+1999-05-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_add_route): Add metric check. Reported by Carlos
+ Alberto Barcenilla <barce@frlp.utn.edu.ar>.
+
+1999-02-18 Peter Galbavy <Peter.Galbavy@knowledge.com>
+
+ * syslog support added
+
+1998-12-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_announce_func): Apply new lib functions.
+
+1998-12-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (config_write_rip): Delete vector v argument.
+ * rip_zebra.c (config_write_zebra): Likewise.
+ * rip_interface.c (interface_config_write): Likewise.
+
+1998-09-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_announce.c (rip_rib_close): When ripd terminates delete all
+ added route.
+
+1998-09-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_interface.c: return read packet size.
+
+1998-05-18 Yamshita TAKAO <jargon@lares.dti.ne.jp>
+
+ * ripd.h: Modify for compile on Solaris.
+
+1998-05-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c: DEFUN function return CMD_SUCCESS.
+ change xmalloc to XMALLOC macro.
+
+1998-05-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_main.c: change CONFDIR to SYSCONFDIR.
+
+1998-05-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * .cvsignore: added.
+
+1998-02-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_interface.c (config_write_interface): correct ADVERTISE spell.
+
+ * rip_main.c (main): add usage() and make cleanup.
+
+1998-01-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripd.c (rip_version): add rip version command.
+
+1998-01-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rip_interface.c (zebra_get_interface): added to get
+ interface's information.
+
+ * ChangeLog: create.
diff --git a/ripd/Makefile.am b/ripd/Makefile.am
new file mode 100644
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 <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+#include "command.h"
+#include "ripd/rip_debug.h"
+
+/* For debug statement. */
+unsigned long rip_debug_event = 0;
+unsigned long rip_debug_packet = 0;
+unsigned long rip_debug_zebra = 0;
+
+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 <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_RIP_DEBUG_H
+#define _ZEBRA_RIP_DEBUG_H
+
+/* RIP debug event flags. */
+#define RIP_DEBUG_EVENT 0x01
+
+/* RIP debug packet flags. */
+#define RIP_DEBUG_PACKET 0x01
+#define RIP_DEBUG_SEND 0x20
+#define RIP_DEBUG_RECV 0x40
+#define RIP_DEBUG_DETAIL 0x80
+
+/* RIP debug zebra flags. */
+#define RIP_DEBUG_ZEBRA 0x01
+
+/* Debug related macro. */
+#define IS_RIP_DEBUG_EVENT (rip_debug_event & RIP_DEBUG_EVENT)
+
+#define IS_RIP_DEBUG_PACKET (rip_debug_packet & RIP_DEBUG_PACKET)
+#define IS_RIP_DEBUG_SEND (rip_debug_packet & RIP_DEBUG_SEND)
+#define IS_RIP_DEBUG_RECV (rip_debug_packet & RIP_DEBUG_RECV)
+#define IS_RIP_DEBUG_DETAIL (rip_debug_packet & RIP_DEBUG_DETAIL)
+
+#define IS_RIP_DEBUG_ZEBRA (rip_debug_zebra & RIP_DEBUG_ZEBRA)
+
+extern unsigned long rip_debug_event;
+extern unsigned long rip_debug_packet;
+extern unsigned long rip_debug_zebra;
+
+void rip_debug_init ();
+void rip_debug_reset ();
+
+#endif /* _ZEBRA_RIP_DEBUG_H */
diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c
new file mode 100644
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 <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "if.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "memory.h"
+#include "network.h"
+#include "table.h"
+#include "log.h"
+#include "stream.h"
+#include "thread.h"
+#include "zclient.h"
+#include "filter.h"
+#include "sockopt.h"
+
+#include "zebra/connected.h"
+
+#include "ripd/ripd.h"
+#include "ripd/rip_debug.h"
+
+void rip_enable_apply (struct interface *);
+void rip_passive_interface_apply (struct interface *);
+int rip_if_down(struct interface *ifp);
+
+struct message ri_version_msg[] =
+{
+ {RI_RIP_VERSION_1, "1"},
+ {RI_RIP_VERSION_2, "2"},
+ {RI_RIP_VERSION_1_AND_2, "1 2"},
+ {0, NULL}
+};
+
+/* RIP enabled network vector. */
+vector rip_enable_interface;
+
+/* RIP enabled interface table. */
+struct route_table *rip_enable_network;
+
+/* Vector to store passive-interface name. */
+vector Vrip_passive_interface;
+
+/* 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 <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Interface name\n")
+{
+ int ret;
+ struct prefix_ipv4 p;
+
+ ret = str2prefix_ipv4 (argv[0], &p);
+
+ if (ret)
+ ret = rip_enable_network_add ((struct prefix *) &p);
+ else
+ ret = rip_enable_if_add (argv[0]);
+
+ if (ret < 0)
+ {
+ vty_out (vty, "There is a same network configuration %s%s", argv[0],
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ rip_enable_apply_all ();
+
+ return CMD_SUCCESS;
+}
+
+/* RIP enable network or interface configuration. */
+DEFUN (no_rip_network,
+ no_rip_network_cmd,
+ "no network (A.B.C.D/M|WORD)",
+ NO_STR
+ "Enable routing on an IP network\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Interface name\n")
+{
+ int ret;
+ struct prefix_ipv4 p;
+
+ ret = str2prefix_ipv4 (argv[0], &p);
+
+ if (ret)
+ ret = rip_enable_network_delete ((struct prefix *) &p);
+ else
+ ret = rip_enable_if_delete (argv[0]);
+
+ if (ret < 0)
+ {
+ vty_out (vty, "Can't find network configuration %s%s", argv[0],
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ rip_enable_apply_all ();
+
+ return CMD_SUCCESS;
+}
+
+/* RIP neighbor configuration set. */
+DEFUN (rip_neighbor,
+ rip_neighbor_cmd,
+ "neighbor A.B.C.D",
+ "Specify a neighbor router\n"
+ "Neighbor address\n")
+{
+ int ret;
+ struct prefix_ipv4 p;
+
+ ret = str2prefix_ipv4 (argv[0], &p);
+
+ if (ret <= 0)
+ {
+ vty_out (vty, "Please specify address by A.B.C.D%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ rip_neighbor_add (&p);
+
+ return CMD_SUCCESS;
+}
+
+/* RIP neighbor configuration unset. */
+DEFUN (no_rip_neighbor,
+ no_rip_neighbor_cmd,
+ "no neighbor A.B.C.D",
+ NO_STR
+ "Specify a neighbor router\n"
+ "Neighbor address\n")
+{
+ int ret;
+ struct prefix_ipv4 p;
+
+ ret = str2prefix_ipv4 (argv[0], &p);
+
+ if (ret <= 0)
+ {
+ vty_out (vty, "Please specify address by A.B.C.D%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ rip_neighbor_delete (&p);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (ip_rip_receive_version,
+ ip_rip_receive_version_cmd,
+ "ip rip receive version (1|2)",
+ IP_STR
+ "Routing Information Protocol\n"
+ "Advertisement reception\n"
+ "Version control\n"
+ "RIP version 1\n"
+ "RIP version 2\n")
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ ifp = (struct interface *)vty->index;
+ ri = ifp->info;
+
+ /* Version 1. */
+ if (atoi (argv[0]) == 1)
+ {
+ ri->ri_receive = RI_RIP_VERSION_1;
+ return CMD_SUCCESS;
+ }
+ if (atoi (argv[0]) == 2)
+ {
+ ri->ri_receive = RI_RIP_VERSION_2;
+ return CMD_SUCCESS;
+ }
+ return CMD_WARNING;
+}
+
+DEFUN (ip_rip_receive_version_1,
+ ip_rip_receive_version_1_cmd,
+ "ip rip receive version 1 2",
+ IP_STR
+ "Routing Information Protocol\n"
+ "Advertisement reception\n"
+ "Version control\n"
+ "RIP version 1\n"
+ "RIP version 2\n")
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ ifp = (struct interface *)vty->index;
+ ri = ifp->info;
+
+ /* Version 1 and 2. */
+ ri->ri_receive = RI_RIP_VERSION_1_AND_2;
+ return CMD_SUCCESS;
+}
+
+DEFUN (ip_rip_receive_version_2,
+ ip_rip_receive_version_2_cmd,
+ "ip rip receive version 2 1",
+ IP_STR
+ "Routing Information Protocol\n"
+ "Advertisement reception\n"
+ "Version control\n"
+ "RIP version 2\n"
+ "RIP version 1\n")
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ ifp = (struct interface *)vty->index;
+ ri = ifp->info;
+
+ /* Version 1 and 2. */
+ ri->ri_receive = RI_RIP_VERSION_1_AND_2;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_rip_receive_version,
+ no_ip_rip_receive_version_cmd,
+ "no ip rip receive version",
+ NO_STR
+ IP_STR
+ "Routing Information Protocol\n"
+ "Advertisement reception\n"
+ "Version control\n")
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ ifp = (struct interface *)vty->index;
+ ri = ifp->info;
+
+ ri->ri_receive = RI_RIP_UNSPEC;
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_rip_receive_version,
+ no_ip_rip_receive_version_num_cmd,
+ "no ip rip receive version (1|2)",
+ NO_STR
+ IP_STR
+ "Routing Information Protocol\n"
+ "Advertisement reception\n"
+ "Version control\n"
+ "Version 1\n"
+ "Version 2\n")
+
+DEFUN (ip_rip_send_version,
+ ip_rip_send_version_cmd,
+ "ip rip send version (1|2)",
+ IP_STR
+ "Routing Information Protocol\n"
+ "Advertisement transmission\n"
+ "Version control\n"
+ "RIP version 1\n"
+ "RIP version 2\n")
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ ifp = (struct interface *)vty->index;
+ ri = ifp->info;
+
+ /* Version 1. */
+ if (atoi (argv[0]) == 1)
+ {
+ ri->ri_send = RI_RIP_VERSION_1;
+ return CMD_SUCCESS;
+ }
+ if (atoi (argv[0]) == 2)
+ {
+ ri->ri_send = RI_RIP_VERSION_2;
+ return CMD_SUCCESS;
+ }
+ return CMD_WARNING;
+}
+
+DEFUN (ip_rip_send_version_1,
+ ip_rip_send_version_1_cmd,
+ "ip rip send version 1 2",
+ IP_STR
+ "Routing Information Protocol\n"
+ "Advertisement transmission\n"
+ "Version control\n"
+ "RIP version 1\n"
+ "RIP version 2\n")
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ ifp = (struct interface *)vty->index;
+ ri = ifp->info;
+
+ /* Version 1 and 2. */
+ ri->ri_send = RI_RIP_VERSION_1_AND_2;
+ return CMD_SUCCESS;
+}
+
+DEFUN (ip_rip_send_version_2,
+ ip_rip_send_version_2_cmd,
+ "ip rip send version 2 1",
+ IP_STR
+ "Routing Information Protocol\n"
+ "Advertisement transmission\n"
+ "Version control\n"
+ "RIP version 2\n"
+ "RIP version 1\n")
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ ifp = (struct interface *)vty->index;
+ ri = ifp->info;
+
+ /* Version 1 and 2. */
+ ri->ri_send = RI_RIP_VERSION_1_AND_2;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_rip_send_version,
+ no_ip_rip_send_version_cmd,
+ "no ip rip send version",
+ NO_STR
+ IP_STR
+ "Routing Information Protocol\n"
+ "Advertisement transmission\n"
+ "Version control\n")
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ ifp = (struct interface *)vty->index;
+ ri = ifp->info;
+
+ ri->ri_send = RI_RIP_UNSPEC;
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_rip_send_version,
+ no_ip_rip_send_version_num_cmd,
+ "no ip rip send version (1|2)",
+ NO_STR
+ IP_STR
+ "Routing Information Protocol\n"
+ "Advertisement transmission\n"
+ "Version control\n"
+ "Version 1\n"
+ "Version 2\n")
+
+DEFUN (ip_rip_authentication_mode,
+ ip_rip_authentication_mode_cmd,
+ "ip rip authentication mode (md5|text)",
+ IP_STR
+ "Routing Information Protocol\n"
+ "Authentication control\n"
+ "Authentication mode\n"
+ "Keyed message digest\n"
+ "Clear text authentication\n")
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ ifp = (struct interface *)vty->index;
+ ri = ifp->info;
+
+ if (strncmp ("md5", argv[0], strlen (argv[0])) == 0)
+ ri->auth_type = RIP_AUTH_MD5;
+ else if (strncmp ("text", argv[0], strlen (argv[0])) == 0)
+ ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD;
+ else
+ {
+ vty_out (vty, "mode should be md5 or text%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_rip_authentication_mode,
+ no_ip_rip_authentication_mode_cmd,
+ "no ip rip authentication mode",
+ NO_STR
+ IP_STR
+ "Routing Information Protocol\n"
+ "Authentication control\n"
+ "Authentication mode\n")
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ ifp = (struct interface *)vty->index;
+ ri = ifp->info;
+
+ /* ri->auth_type = RIP_NO_AUTH; */
+ ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_rip_authentication_mode,
+ no_ip_rip_authentication_mode_type_cmd,
+ "no ip rip authentication mode (md5|text)",
+ NO_STR
+ IP_STR
+ "Routing Information Protocol\n"
+ "Authentication control\n"
+ "Authentication mode\n"
+ "Keyed message digest\n"
+ "Clear text authentication\n")
+
+DEFUN (ip_rip_authentication_string,
+ ip_rip_authentication_string_cmd,
+ "ip rip authentication string LINE",
+ IP_STR
+ "Routing Information Protocol\n"
+ "Authentication control\n"
+ "Authentication string\n"
+ "Authentication string\n")
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ ifp = (struct interface *)vty->index;
+ ri = ifp->info;
+
+ if (strlen (argv[0]) > 16)
+ {
+ vty_out (vty, "%% RIPv2 authentication string must be shorter than 16%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (ri->key_chain)
+ {
+ vty_out (vty, "%% key-chain configuration exists%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (ri->auth_str)
+ free (ri->auth_str);
+
+ ri->auth_str = strdup (argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_rip_authentication_string,
+ no_ip_rip_authentication_string_cmd,
+ "no ip rip authentication string",
+ NO_STR
+ IP_STR
+ "Routing Information Protocol\n"
+ "Authentication control\n"
+ "Authentication string\n")
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ ifp = (struct interface *)vty->index;
+ ri = ifp->info;
+
+ if (ri->auth_str)
+ free (ri->auth_str);
+
+ ri->auth_str = NULL;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_rip_authentication_string,
+ no_ip_rip_authentication_string2_cmd,
+ "no ip rip authentication string LINE",
+ NO_STR
+ IP_STR
+ "Routing Information Protocol\n"
+ "Authentication control\n"
+ "Authentication string\n"
+ "Authentication string\n")
+
+DEFUN (ip_rip_authentication_key_chain,
+ ip_rip_authentication_key_chain_cmd,
+ "ip rip authentication key-chain LINE",
+ IP_STR
+ "Routing Information Protocol\n"
+ "Authentication control\n"
+ "Authentication key-chain\n"
+ "name of key-chain\n")
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ ifp = (struct interface *) vty->index;
+ ri = ifp->info;
+
+ if (ri->auth_str)
+ {
+ vty_out (vty, "%% authentication string configuration exists%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (ri->key_chain)
+ free (ri->key_chain);
+
+ ri->key_chain = strdup (argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_rip_authentication_key_chain,
+ no_ip_rip_authentication_key_chain_cmd,
+ "no ip rip authentication key-chain",
+ NO_STR
+ IP_STR
+ "Routing Information Protocol\n"
+ "Authentication control\n"
+ "Authentication key-chain\n")
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ ifp = (struct interface *) vty->index;
+ ri = ifp->info;
+
+ if (ri->key_chain)
+ free (ri->key_chain);
+
+ ri->key_chain = NULL;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_rip_authentication_key_chain,
+ no_ip_rip_authentication_key_chain2_cmd,
+ "no ip rip authentication key-chain LINE",
+ NO_STR
+ IP_STR
+ "Routing Information Protocol\n"
+ "Authentication control\n"
+ "Authentication key-chain\n"
+ "name of key-chain\n")
+
+DEFUN (rip_split_horizon,
+ rip_split_horizon_cmd,
+ "ip split-horizon",
+ IP_STR
+ "Perform split horizon\n")
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ ifp = vty->index;
+ ri = ifp->info;
+
+ ri->split_horizon = 1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_split_horizon,
+ no_rip_split_horizon_cmd,
+ "no ip split-horizon",
+ NO_STR
+ IP_STR
+ "Perform split horizon\n")
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ ifp = vty->index;
+ ri = ifp->info;
+
+ ri->split_horizon = 0;
+ return CMD_SUCCESS;
+}
+
+DEFUN (rip_passive_interface,
+ rip_passive_interface_cmd,
+ "passive-interface IFNAME",
+ "Suppress routing updates on an interface\n"
+ "Interface name\n")
+{
+ return rip_passive_interface_set (vty, argv[0]);
+}
+
+DEFUN (no_rip_passive_interface,
+ no_rip_passive_interface_cmd,
+ "no passive-interface IFNAME",
+ NO_STR
+ "Suppress routing updates on an interface\n"
+ "Interface name\n")
+{
+ return rip_passive_interface_unset (vty, argv[0]);
+}
+
+/* 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 <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "version.h"
+#include "getopt.h"
+#include "thread.h"
+#include "command.h"
+#include "memory.h"
+#include "prefix.h"
+#include "filter.h"
+#include "keychain.h"
+#include "log.h"
+
+#include "ripd/ripd.h"
+
+/* ripd options. */
+static struct option longopts[] =
+{
+ { "daemon", no_argument, NULL, 'd'},
+ { "config_file", required_argument, NULL, 'f'},
+ { "pid_file", required_argument, NULL, 'i'},
+ { "help", no_argument, NULL, 'h'},
+ { "vty_addr", required_argument, NULL, 'A'},
+ { "vty_port", required_argument, NULL, 'P'},
+ { "retain", no_argument, NULL, 'r'},
+ { "version", no_argument, NULL, 'v'},
+ { 0 }
+};
+
+/* Configuration file and directory. */
+char config_current[] = RIPD_DEFAULT_CONFIG;
+char config_default[] = SYSCONFDIR RIPD_DEFAULT_CONFIG;
+char *config_file = NULL;
+
+/* ripd program name */
+
+/* Route retain mode flag. */
+int retain_mode = 0;
+
+/* RIP VTY bind address. */
+char *vty_addr = NULL;
+
+/* RIP VTY connection port. */
+int vty_port = RIP_VTY_PORT;
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* Process ID saved for use by init system */
+char *pid_file = PATH_RIPD_PID;
+
+/* Help information display. */
+static void
+usage (char *progname, int status)
+{
+ if (status != 0)
+ fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+ else
+ {
+ printf ("Usage : %s [OPTION...]\n\
+Daemon which manages RIP version 1 and 2.\n\n\
+-d, --daemon Runs in daemon mode\n\
+-f, --config_file Set configuration file name\n\
+-i, --pid_file Set process identifier file name\n\
+-A, --vty_addr Set vty's bind address\n\
+-P, --vty_port Set vty's port number\n\
+-r, --retain When program terminates, retain added route by ripd.\n\
+-v, --version Print program version\n\
+-h, --help Display this help and exit\n\
+\n\
+Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
+ }
+
+ exit (status);
+}
+
+/* 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 <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "filter.h"
+#include "command.h"
+#include "linklist.h"
+#include "memory.h"
+
+#define RIP_OFFSET_LIST_IN 0
+#define RIP_OFFSET_LIST_OUT 1
+#define RIP_OFFSET_LIST_MAX 2
+
+struct rip_offset_list
+{
+ char *ifname;
+
+ struct
+ {
+ char *alist_name;
+ /* struct access_list *alist; */
+ int metric;
+ } direct[RIP_OFFSET_LIST_MAX];
+};
+
+static struct list *rip_offset_list_master;
+
+int
+strcmp_safe (char *s1, char *s2)
+{
+ if (s1 == NULL && s2 == NULL)
+ return 0;
+ if (s1 == NULL)
+ return -1;
+ if (s2 == NULL)
+ return 1;
+ return strcmp (s1, s2);
+}
+
+struct rip_offset_list *
+rip_offset_list_new ()
+{
+ struct rip_offset_list *new;
+
+ new = XMALLOC (MTYPE_RIP_OFFSET_LIST, sizeof (struct rip_offset_list));
+ memset (new, 0, sizeof (struct rip_offset_list));
+ return new;
+}
+
+void
+rip_offset_list_free (struct rip_offset_list *offset)
+{
+ XFREE (MTYPE_RIP_OFFSET_LIST, offset);
+}
+
+struct rip_offset_list *
+rip_offset_list_lookup (char *ifname)
+{
+ struct rip_offset_list *offset;
+ struct listnode *nn;
+
+ LIST_LOOP (rip_offset_list_master, offset, nn)
+ {
+ if (strcmp_safe (offset->ifname, ifname) == 0)
+ return offset;
+ }
+ return NULL;
+}
+
+struct rip_offset_list *
+rip_offset_list_get (char *ifname)
+{
+ struct rip_offset_list *offset;
+
+ offset = rip_offset_list_lookup (ifname);
+ if (offset)
+ return offset;
+
+ offset = rip_offset_list_new ();
+ if (ifname)
+ offset->ifname = strdup (ifname);
+ listnode_add_sort (rip_offset_list_master, offset);
+
+ return offset;
+}
+
+int
+rip_offset_list_set (struct vty *vty, char *alist, char *direct_str,
+ char *metric_str, char *ifname)
+{
+ int direct;
+ int metric;
+ struct rip_offset_list *offset;
+
+ /* Check direction. */
+ if (strncmp (direct_str, "i", 1) == 0)
+ direct = RIP_OFFSET_LIST_IN;
+ else if (strncmp (direct_str, "o", 1) == 0)
+ direct = RIP_OFFSET_LIST_OUT;
+ else
+ {
+ vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Check metric. */
+ metric = atoi (metric_str);
+ if (metric < 0 || metric > 16)
+ {
+ vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Get offset-list structure with interface name. */
+ offset = rip_offset_list_get (ifname);
+
+ if (offset->direct[direct].alist_name)
+ free (offset->direct[direct].alist_name);
+ offset->direct[direct].alist_name = strdup (alist);
+ offset->direct[direct].metric = metric;
+
+ return CMD_SUCCESS;
+}
+
+int
+rip_offset_list_unset (struct vty *vty, char *alist, char *direct_str,
+ char *metric_str, char *ifname)
+{
+ int direct;
+ int metric;
+ struct rip_offset_list *offset;
+
+ /* Check direction. */
+ if (strncmp (direct_str, "i", 1) == 0)
+ direct = RIP_OFFSET_LIST_IN;
+ else if (strncmp (direct_str, "o", 1) == 0)
+ direct = RIP_OFFSET_LIST_OUT;
+ else
+ {
+ vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Check metric. */
+ metric = atoi (metric_str);
+ if (metric < 0 || metric > 16)
+ {
+ vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Get offset-list structure with interface name. */
+ offset = rip_offset_list_lookup (ifname);
+
+ if (offset)
+ {
+ if (offset->direct[direct].alist_name)
+ free (offset->direct[direct].alist_name);
+ offset->direct[direct].alist_name = NULL;
+
+ if (offset->direct[RIP_OFFSET_LIST_IN].alist_name == NULL &&
+ offset->direct[RIP_OFFSET_LIST_OUT].alist_name == NULL)
+ {
+ listnode_delete (rip_offset_list_master, offset);
+ if (offset->ifname)
+ free (offset->ifname);
+ rip_offset_list_free (offset);
+ }
+ }
+ else
+ {
+ vty_out (vty, "Can't find offset-list%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
+#define OFFSET_LIST_IN_NAME(O) ((O)->direct[RIP_OFFSET_LIST_IN].alist_name)
+#define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIP_OFFSET_LIST_IN].metric)
+
+#define OFFSET_LIST_OUT_NAME(O) ((O)->direct[RIP_OFFSET_LIST_OUT].alist_name)
+#define OFFSET_LIST_OUT_METRIC(O) ((O)->direct[RIP_OFFSET_LIST_OUT].metric)
+
+/* If metric is modifed return 1. */
+int
+rip_offset_list_apply_in (struct prefix_ipv4 *p, struct interface *ifp,
+ u_int32_t *metric)
+{
+ struct rip_offset_list *offset;
+ struct access_list *alist;
+
+ /* Look up offset-list with interface name. */
+ offset = rip_offset_list_lookup (ifp->name);
+ if (offset && OFFSET_LIST_IN_NAME (offset))
+ {
+ alist = access_list_lookup (AFI_IP, OFFSET_LIST_IN_NAME (offset));
+
+ if (alist
+ && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
+ {
+ *metric += OFFSET_LIST_IN_METRIC (offset);
+ return 1;
+ }
+ return 0;
+ }
+ /* Look up offset-list without interface name. */
+ offset = rip_offset_list_lookup (NULL);
+ if (offset && OFFSET_LIST_IN_NAME (offset))
+ {
+ alist = access_list_lookup (AFI_IP, OFFSET_LIST_IN_NAME (offset));
+
+ if (alist
+ && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
+ {
+ *metric += OFFSET_LIST_IN_METRIC (offset);
+ return 1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+/* If metric is modifed return 1. */
+int
+rip_offset_list_apply_out (struct prefix_ipv4 *p, struct interface *ifp,
+ u_int32_t *metric)
+{
+ struct rip_offset_list *offset;
+ struct access_list *alist;
+
+ /* Look up offset-list with interface name. */
+ offset = rip_offset_list_lookup (ifp->name);
+ if (offset && OFFSET_LIST_OUT_NAME (offset))
+ {
+ alist = access_list_lookup (AFI_IP, OFFSET_LIST_OUT_NAME (offset));
+
+ if (alist
+ && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
+ {
+ *metric += OFFSET_LIST_OUT_METRIC (offset);
+ return 1;
+ }
+ return 0;
+ }
+
+ /* Look up offset-list without interface name. */
+ offset = rip_offset_list_lookup (NULL);
+ if (offset && OFFSET_LIST_OUT_NAME (offset))
+ {
+ alist = access_list_lookup (AFI_IP, OFFSET_LIST_OUT_NAME (offset));
+
+ if (alist
+ && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
+ {
+ *metric += OFFSET_LIST_OUT_METRIC (offset);
+ return 1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+DEFUN (rip_offset_list,
+ rip_offset_list_cmd,
+ "offset-list WORD (in|out) <0-16>",
+ "Modify RIP metric\n"
+ "Access-list name\n"
+ "For incoming updates\n"
+ "For outgoing updates\n"
+ "Metric value\n")
+{
+ return rip_offset_list_set (vty, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN (rip_offset_list_ifname,
+ rip_offset_list_ifname_cmd,
+ "offset-list WORD (in|out) <0-16> IFNAME",
+ "Modify RIP metric\n"
+ "Access-list name\n"
+ "For incoming updates\n"
+ "For outgoing updates\n"
+ "Metric value\n"
+ "Interface to match\n")
+{
+ return rip_offset_list_set (vty, argv[0], argv[1], argv[2], argv[3]);
+}
+
+DEFUN (no_rip_offset_list,
+ no_rip_offset_list_cmd,
+ "no offset-list WORD (in|out) <0-16>",
+ NO_STR
+ "Modify RIP metric\n"
+ "Access-list name\n"
+ "For incoming updates\n"
+ "For outgoing updates\n"
+ "Metric value\n")
+{
+ return rip_offset_list_unset (vty, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN (no_rip_offset_list_ifname,
+ no_rip_offset_list_ifname_cmd,
+ "no offset-list WORD (in|out) <0-16> IFNAME",
+ NO_STR
+ "Modify RIP metric\n"
+ "Access-list name\n"
+ "For incoming updates\n"
+ "For outgoing updates\n"
+ "Metric value\n"
+ "Interface to match\n")
+{
+ return rip_offset_list_unset (vty, argv[0], argv[1], argv[2], argv[3]);
+}
+
+int
+offset_list_cmp (struct rip_offset_list *o1, struct rip_offset_list *o2)
+{
+ return strcmp_safe (o1->ifname, o2->ifname);
+}
+
+void
+offset_list_del (struct rip_offset_list *offset)
+{
+ if (OFFSET_LIST_IN_NAME (offset))
+ free (OFFSET_LIST_IN_NAME (offset));
+ if (OFFSET_LIST_OUT_NAME (offset))
+ free (OFFSET_LIST_OUT_NAME (offset));
+ if (offset->ifname)
+ free (offset->ifname);
+ rip_offset_list_free (offset);
+}
+
+void
+rip_offset_init ()
+{
+ rip_offset_list_master = list_new ();
+ rip_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp;
+ rip_offset_list_master->del = (void (*)(void *)) offset_list_del;
+
+ install_element (RIP_NODE, &rip_offset_list_cmd);
+ install_element (RIP_NODE, &rip_offset_list_ifname_cmd);
+ install_element (RIP_NODE, &no_rip_offset_list_cmd);
+ install_element (RIP_NODE, &no_rip_offset_list_ifname_cmd);
+}
+
+void
+rip_offset_clean ()
+{
+ list_delete (rip_offset_list_master);
+
+ rip_offset_list_master = list_new ();
+ rip_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp;
+ rip_offset_list_master->del = (void (*)(void *)) offset_list_del;
+}
+
+int
+config_write_rip_offset_list (struct vty *vty)
+{
+ struct listnode *nn;
+ struct rip_offset_list *offset;
+
+ LIST_LOOP (rip_offset_list_master, offset, nn)
+ {
+ if (! offset->ifname)
+ {
+ if (offset->direct[RIP_OFFSET_LIST_IN].alist_name)
+ vty_out (vty, " offset-list %s in %d%s",
+ offset->direct[RIP_OFFSET_LIST_IN].alist_name,
+ offset->direct[RIP_OFFSET_LIST_IN].metric,
+ VTY_NEWLINE);
+ if (offset->direct[RIP_OFFSET_LIST_OUT].alist_name)
+ vty_out (vty, " offset-list %s out %d%s",
+ offset->direct[RIP_OFFSET_LIST_OUT].alist_name,
+ offset->direct[RIP_OFFSET_LIST_OUT].metric,
+ VTY_NEWLINE);
+ }
+ else
+ {
+ if (offset->direct[RIP_OFFSET_LIST_IN].alist_name)
+ vty_out (vty, " offset-list %s in %d %s%s",
+ offset->direct[RIP_OFFSET_LIST_IN].alist_name,
+ offset->direct[RIP_OFFSET_LIST_IN].metric,
+ offset->ifname, VTY_NEWLINE);
+ if (offset->direct[RIP_OFFSET_LIST_OUT].alist_name)
+ vty_out (vty, " offset-list %s out %d %s%s",
+ offset->direct[RIP_OFFSET_LIST_OUT].alist_name,
+ offset->direct[RIP_OFFSET_LIST_OUT].metric,
+ offset->ifname, VTY_NEWLINE);
+ }
+ }
+
+ return 0;
+}
diff --git a/ripd/rip_peer.c b/ripd/rip_peer.c
new file mode 100644
index 00000000..20c2da73
--- /dev/null
+++ b/ripd/rip_peer.c
@@ -0,0 +1,211 @@
+/* RIP peer support
+ * Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "command.h"
+#include "linklist.h"
+#include "thread.h"
+#include "memory.h"
+
+#include "ripd/ripd.h"
+
+/* Linked list of RIP peer. */
+struct list *peer_list;
+
+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 <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "memory.h"
+#include "prefix.h"
+#include "routemap.h"
+#include "command.h"
+#include "filter.h"
+#include "log.h"
+#include "sockunion.h" /* for inet_aton () */
+#include "plist.h"
+
+#include "ripd/ripd.h"
+
+/* Add rip route map rule. */
+int
+rip_route_match_add (struct vty *vty, struct route_map_index *index,
+ char *command, char *arg)
+{
+ int ret;
+
+ ret = route_map_add_match (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+/* Delete rip route map rule. */
+int
+rip_route_match_delete (struct vty *vty, struct route_map_index *index,
+ char *command, char *arg)
+{
+ int ret;
+
+ ret = route_map_delete_match (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+/* Add rip route map rule. */
+int
+rip_route_set_add (struct vty *vty, struct route_map_index *index,
+ char *command, char *arg)
+{
+ int ret;
+
+ ret = route_map_add_set (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+/* Delete rip route map rule. */
+int
+rip_route_set_delete (struct vty *vty, struct route_map_index *index,
+ char *command, char *arg)
+{
+ int ret;
+
+ ret = route_map_delete_set (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+/* Hook function for updating route_map assignment. */
+void
+rip_route_map_update ()
+{
+ int i;
+
+ if (rip)
+ {
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ {
+ if (rip->route_map[i].name)
+ rip->route_map[i].map =
+ route_map_lookup_by_name (rip->route_map[i].name);
+ }
+ }
+}
+
+/* `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 <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#ifdef HAVE_SNMP
+#include <asn1.h>
+#include <snmp.h>
+#include <snmp_impl.h>
+
+#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "command.h"
+#include "table.h"
+#include "smux.h"
+
+#include "ripd/ripd.h"
+
+/* 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 <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "prefix.h"
+#include "stream.h"
+#include "routemap.h"
+#include "zclient.h"
+#include "log.h"
+#include "ripd/ripd.h"
+#include "ripd/rip_debug.h"
+
+/* All information about zebra. */
+struct zclient *zclient = NULL;
+
+/* Callback prototypes for zebra client service. */
+int rip_interface_add (int, struct zclient *, zebra_size_t);
+int rip_interface_delete (int, struct zclient *, zebra_size_t);
+int rip_interface_address_add (int, struct zclient *, zebra_size_t);
+int rip_interface_address_delete (int, struct zclient *, zebra_size_t);
+int rip_interface_up (int, struct zclient *, zebra_size_t);
+int rip_interface_down (int, struct zclient *, zebra_size_t);
+
+/* 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 <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "command.h"
+#include "prefix.h"
+#include "table.h"
+#include "thread.h"
+#include "memory.h"
+#include "log.h"
+#include "stream.h"
+#include "filter.h"
+#include "sockunion.h"
+#include "routemap.h"
+#include "plist.h"
+#include "distribute.h"
+#include "md5-gnu.h"
+#include "keychain.h"
+
+#include "ripd/ripd.h"
+#include "ripd/rip_debug.h"
+
+/* RIP Structure. */
+struct rip *rip = NULL;
+
+/* RIP neighbor address table. */
+struct route_table *rip_neighbor_table;
+
+/* RIP route changes. */
+long rip_global_route_changes = 0;
+
+/* RIP queries. */
+long rip_global_queries = 0;
+
+/* 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 <network>/<length>\n")
+{
+ int ret;
+ struct prefix_ipv4 p;
+ struct route_node *node;
+
+ ret = str2prefix_ipv4 (argv[0], &p);
+ if (ret < 0)
+ {
+ vty_out (vty, "Malformed address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ apply_mask_ipv4 (&p);
+
+ /* For router rip configuration. */
+ node = route_node_get (rip->route, (struct prefix *) &p);
+
+ if (node->info)
+ {
+ vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
+ route_unlock_node (node);
+ return CMD_WARNING;
+ }
+
+ node->info = "static";
+
+ rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_route,
+ no_rip_route_cmd,
+ "no route A.B.C.D/M",
+ NO_STR
+ "RIP static route configuration\n"
+ "IP prefix <network>/<length>\n")
+{
+ int ret;
+ struct prefix_ipv4 p;
+ struct route_node *node;
+
+ ret = str2prefix_ipv4 (argv[0], &p);
+ if (ret < 0)
+ {
+ vty_out (vty, "Malformed address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ apply_mask_ipv4 (&p);
+
+ /* For router rip configuration. */
+ node = route_node_lookup (rip->route, (struct prefix *) &p);
+ if (! node)
+ {
+ vty_out (vty, "Can't find route %s.%s", argv[0],
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
+ route_unlock_node (node);
+
+ node->info = NULL;
+ route_unlock_node (node);
+
+ return CMD_SUCCESS;
+}
+
+void
+rip_update_default_metric ()
+{
+ struct route_node *np;
+ struct rip_info *rinfo;
+
+ for (np = route_top (rip->table); np; np = route_next (np))
+ if ((rinfo = np->info) != NULL)
+ if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
+ rinfo->metric = rip->default_metric;
+}
+
+DEFUN (rip_default_metric,
+ rip_default_metric_cmd,
+ "default-metric <1-16>",
+ "Set a metric of redistribute routes\n"
+ "Default metric\n")
+{
+ if (rip)
+ {
+ rip->default_metric = atoi (argv[0]);
+ /* rip_update_default_metric (); */
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_default_metric,
+ no_rip_default_metric_cmd,
+ "no default-metric",
+ NO_STR
+ "Set a metric of redistribute routes\n"
+ "Default metric\n")
+{
+ if (rip)
+ {
+ rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
+ /* rip_update_default_metric (); */
+ }
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_rip_default_metric,
+ no_rip_default_metric_val_cmd,
+ "no default-metric <1-16>",
+ NO_STR
+ "Set a metric of redistribute routes\n"
+ "Default metric\n")
+
+DEFUN (rip_timers,
+ rip_timers_cmd,
+ "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
+ "Adjust routing timers\n"
+ "Basic routing protocol update timers\n"
+ "Routing table update timer value in second. Default is 30.\n"
+ "Routing information timeout timer. Default is 180.\n"
+ "Garbage collection timer. Default is 120.\n")
+{
+ unsigned long update;
+ unsigned long timeout;
+ unsigned long garbage;
+ char *endptr = NULL;
+ unsigned long RIP_TIMER_MAX = 2147483647;
+ unsigned long RIP_TIMER_MIN = 5;
+
+ update = strtoul (argv[0], &endptr, 10);
+ if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')
+ {
+ vty_out (vty, "update timer value error%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ timeout = strtoul (argv[1], &endptr, 10);
+ if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0')
+ {
+ vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ garbage = strtoul (argv[2], &endptr, 10);
+ if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0')
+ {
+ vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Set each timer value. */
+ rip->update_time = update;
+ rip->timeout_time = timeout;
+ rip->garbage_time = garbage;
+
+ /* Reset update timer thread. */
+ rip_event (RIP_UPDATE_EVENT, 0);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_timers,
+ no_rip_timers_cmd,
+ "no timers basic",
+ NO_STR
+ "Adjust routing timers\n"
+ "Basic routing protocol update timers\n")
+{
+ /* Set each timer value to the default. */
+ rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
+ rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
+ rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
+
+ /* Reset update timer thread. */
+ rip_event (RIP_UPDATE_EVENT, 0);
+
+ return CMD_SUCCESS;
+}
+
+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 <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_RIP_H
+#define _ZEBRA_RIP_H
+
+/* RIP version number. */
+#define RIPv1 1
+#define RIPv2 2
+
+/* RIP command list. */
+#define RIP_REQUEST 1
+#define RIP_RESPONSE 2
+#define RIP_TRACEON 3 /* Obsolete */
+#define RIP_TRACEOFF 4 /* Obsolete */
+#define RIP_POLL 5
+#define RIP_POLL_ENTRY 6
+#define RIP_COMMAND_MAX 7
+
+/* RIP metric infinity value.*/
+#define RIP_METRIC_INFINITY 16
+
+/* Normal RIP packet min and max size. */
+#define RIP_PACKET_MINSIZ 4
+#define RIP_PACKET_MAXSIZ 512
+
+#define RIP_HEADER_SIZE 4
+#define RIP_RTE_SIZE 20
+
+/* Max count of routing table entry in one rip packet. */
+#define RIP_MAX_RTE 25
+
+/* RIP version 2 multicast address. */
+#ifndef INADDR_RIP_GROUP
+#define INADDR_RIP_GROUP 0xe0000009 /* 224.0.0.9 */
+#endif
+
+/* RIP timers */
+#define RIP_UPDATE_TIMER_DEFAULT 30
+#define RIP_TIMEOUT_TIMER_DEFAULT 180
+#define RIP_GARBAGE_TIMER_DEFAULT 120
+
+/* RIP peer timeout value. */
+#define RIP_PEER_TIMER_DEFAULT 180
+
+/* RIP port number. */
+#define RIP_PORT_DEFAULT 520
+#define RIP_VTY_PORT 2602
+#define RIP_VTYSH_PATH "/tmp/.ripd"
+
+/* Default configuration file name. */
+#define RIPD_DEFAULT_CONFIG "ripd.conf"
+
+/* RIP route types. */
+#define RIP_ROUTE_RTE 0
+#define RIP_ROUTE_STATIC 1
+#define RIP_ROUTE_DEFAULT 2
+#define RIP_ROUTE_REDISTRIBUTE 3
+#define RIP_ROUTE_INTERFACE 4
+
+/* RIP MD5 authentication. */
+#define RIP_AUTH_MD5_SIZE 16
+
+/* RIP structure. */
+struct rip
+{
+ /* RIP socket. */
+ int sock;
+
+ /* Default version of rip instance. */
+ u_char version;
+
+ /* Output buffer of RIP. */
+ struct stream *obuf;
+
+ /* RIP routing information base. */
+ struct route_table *table;
+
+ /* RIP only static routing information. */
+ struct route_table *route;
+
+ /* RIP neighbor. */
+ struct route_table *neighbor;
+
+ /* RIP threads. */
+ struct thread *t_read;
+
+ /* Update and garbage timer. */
+ struct thread *t_update;
+
+ /* Triggered update hack. */
+ int trigger;
+ struct thread *t_triggered_update;
+ struct thread *t_triggered_interval;
+
+ /* RIP timer values. */
+ unsigned long update_time;
+ unsigned long timeout_time;
+ unsigned long garbage_time;
+
+ /* RIP default metric. */
+ int default_metric;
+
+ /* RIP default-information originate. */
+ u_char default_information;
+ char *default_information_route_map;
+
+ /* RIP default distance. */
+ u_char distance;
+ struct route_table *distance_table;
+
+ /* For redistribute route map. */
+ struct
+ {
+ char *name;
+ struct route_map *map;
+ int metric_config;
+ u_int32_t metric;
+ } route_map[ZEBRA_ROUTE_MAX];
+};
+
+/* RIP routing table entry which belong to rip_packet. */
+struct rte
+{
+ u_int16_t family; /* Address family of this route. */
+ u_int16_t tag; /* Route Tag which included in RIP2 packet. */
+ struct in_addr prefix; /* Prefix of rip route. */
+ struct in_addr mask; /* Netmask of rip route. */
+ struct in_addr nexthop; /* Next hop of rip route. */
+ u_int32_t metric; /* Metric value of rip route. */
+};
+
+/* RIP packet structure. */
+struct rip_packet
+{
+ unsigned char command; /* Command type of RIP packet. */
+ unsigned char version; /* RIP version which coming from peer. */
+ unsigned char pad1; /* Padding of RIP packet header. */
+ unsigned char pad2; /* Same as above. */
+ struct rte rte[1]; /* Address structure. */
+};
+
+/* Buffer to read RIP packet. */
+union rip_buf
+{
+ struct rip_packet rip_packet;
+ char buf[RIP_PACKET_MAXSIZ];
+};
+
+/* RIP route information. */
+struct rip_info
+{
+ /* This route's type. */
+ int type;
+
+ /* Sub type. */
+ int sub_type;
+
+ /* RIP nexthop. */
+ struct in_addr nexthop;
+ struct in_addr from;
+
+ /* Which interface does this route come from. */
+ unsigned int ifindex;
+
+ /* Metric of this route. */
+ u_int32_t metric;
+
+ /* Tag information of this route. */
+ u_int16_t tag;
+
+ /* Flags of RIP route. */
+#define RIP_RTF_FIB 1
+#define RIP_RTF_CHANGED 2
+ u_char flags;
+
+ /* Garbage collect timer. */
+ struct thread *t_timeout;
+ struct thread *t_garbage_collect;
+
+ /* Route-map futures - this variables can be changed. */
+ struct in_addr nexthop_out;
+ u_char metric_set;
+ u_int32_t metric_out;
+ unsigned int ifindex_out;
+
+ struct route_node *rp;
+
+ u_char distance;
+
+#ifdef NEW_RIP_TABLE
+ struct rip_info *next;
+ struct rip_info *prev;
+#endif /* NEW_RIP_TABLE */
+};
+
+/* RIP specific interface configuration. */
+struct rip_interface
+{
+ /* RIP is enabled on this interface. */
+ int enable_network;
+ int enable_interface;
+
+ /* RIP is running on this interface. */
+ int running;
+
+ /* RIP version control. */
+ int ri_send;
+ int ri_receive;
+
+ /* RIPv2 authentication type. */
+#define RIP_NO_AUTH 0
+#define RIP_AUTH_DATA 1
+#define RIP_AUTH_SIMPLE_PASSWORD 2
+#define RIP_AUTH_MD5 3
+ int auth_type;
+
+ /* RIPv2 authentication string. */
+ char *auth_str;
+
+ /* RIPv2 authentication key chain. */
+ char *key_chain;
+
+ /* Split horizon flag. */
+ int split_horizon;
+ int split_horizon_default;
+
+ /* For filter type slot. */
+#define RIP_FILTER_IN 0
+#define RIP_FILTER_OUT 1
+#define RIP_FILTER_MAX 2
+
+ /* Access-list. */
+ struct access_list *list[RIP_FILTER_MAX];
+
+ /* Prefix-list. */
+ struct prefix_list *prefix[RIP_FILTER_MAX];
+
+ /* Wake up thread. */
+ struct thread *t_wakeup;
+
+ /* Interface statistics. */
+ int recv_badpackets;
+ int recv_badroutes;
+ int sent_updates;
+
+ /* Passive interface. */
+ int passive;
+};
+
+/* RIP peer information. */
+struct rip_peer
+{
+ /* Peer address. */
+ struct in_addr addr;
+
+ /* Peer RIP tag value. */
+ int domain;
+
+ /* Last update time. */
+ time_t uptime;
+
+ /* Peer RIP version. */
+ u_char version;
+
+ /* Statistics. */
+ int recv_badpackets;
+ int recv_badroutes;
+
+ /* Timeout thread. */
+ struct thread *t_timeout;
+};
+
+struct rip_md5_info
+{
+ u_int16_t family;
+ u_int16_t type;
+ u_int16_t packet_len;
+ u_char keyid;
+ u_char auth_len;
+ u_int32_t sequence;
+ u_int32_t reserv1;
+ u_int32_t reserv2;
+};
+
+struct rip_md5_data
+{
+ u_int16_t family;
+ u_int16_t type;
+ u_char digest[16];
+};
+
+/* RIP accepet/announce methods. */
+#define RI_RIP_UNSPEC 0
+#define RI_RIP_VERSION_1 1
+#define RI_RIP_VERSION_2 2
+#define RI_RIP_VERSION_1_AND_2 3
+
+/* Default value for "default-metric" command. */
+#define RIP_DEFAULT_METRIC_DEFAULT 1
+
+/* RIP event. */
+enum rip_event
+{
+ RIP_READ,
+ RIP_UPDATE_EVENT,
+ RIP_TRIGGERED_UPDATE,
+};
+
+/* Macro for timer turn on. */
+#define RIP_TIMER_ON(T,F,V) \
+ do { \
+ if (!(T)) \
+ (T) = thread_add_timer (master, (F), rinfo, (V)); \
+ } while (0)
+
+/* Macro for timer turn off. */
+#define RIP_TIMER_OFF(X) \
+ do { \
+ if (X) \
+ { \
+ thread_cancel (X); \
+ (X) = NULL; \
+ } \
+ } while (0)
+
+/* Prototypes. */
+void rip_init ();
+void rip_reset ();
+void rip_clean ();
+void rip_clean_network ();
+void rip_interface_clean ();
+void rip_interface_reset ();
+void rip_passive_interface_clean ();
+void rip_if_init ();
+void rip_if_down_all ();
+void rip_route_map_init ();
+void rip_route_map_reset ();
+void rip_snmp_init ();
+void rip_zclient_init ();
+void rip_zclient_start ();
+void rip_zclient_reset ();
+void rip_offset_init ();
+int if_check_address (struct in_addr addr);
+int if_valid_neighbor (struct in_addr addr);
+
+int rip_request_send (struct sockaddr_in *, struct interface *, u_char);
+int rip_neighbor_lookup (struct sockaddr_in *);
+void rip_redistribute_add (int, int, struct prefix_ipv4 *, unsigned int,
+ struct in_addr *);
+void rip_redistribute_delete (int, int, struct prefix_ipv4 *, unsigned int);
+void rip_redistribute_withdraw (int);
+void rip_zebra_ipv4_add (struct prefix_ipv4 *, struct in_addr *, u_int32_t, u_char);
+void rip_zebra_ipv4_delete (struct prefix_ipv4 *, struct in_addr *, u_int32_t);
+void rip_interface_multicast_set (int, struct interface *);
+void rip_distribute_update_interface (struct interface *);
+
+int config_write_rip_network (struct vty *, int);
+int config_write_rip_offset_list (struct vty *);
+int config_write_rip_redistribute (struct vty *, int);
+
+void rip_peer_init ();
+void rip_peer_update (struct sockaddr_in *, u_char);
+void rip_peer_bad_route (struct sockaddr_in *);
+void rip_peer_bad_packet (struct sockaddr_in *);
+void rip_peer_display (struct vty *);
+struct rip_peer *rip_peer_lookup (struct in_addr *);
+struct rip_peer *rip_peer_lookup_next (struct in_addr *);
+
+int rip_offset_list_apply_in (struct prefix_ipv4 *, struct interface *, u_int32_t *);
+int rip_offset_list_apply_out (struct prefix_ipv4 *, struct interface *, u_int32_t *);
+void rip_offset_clean ();
+
+void rip_info_free (struct rip_info *);
+u_char rip_distance_apply (struct rip_info *);
+void rip_redistribute_clean ();
+void rip_ifaddr_add (struct interface *, struct connected *);
+void rip_ifaddr_delete (struct interface *, struct connected *);
+
+/* There is only one rip strucutre. */
+extern struct rip *rip;
+
+/* Master thread strucutre. */
+extern struct thread_master *master;
+
+/* RIP statistics for SNMP. */
+extern long rip_global_route_changes;
+extern long rip_global_queries;
+
+#endif /* _ZEBRA_RIP_H */
diff --git a/ripngd/.cvsignore b/ripngd/.cvsignore
new file mode 100644
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 <kunihiro@ipinfusion.com>
+
+ * zebra-0.93 released.
+
+2001-08-28 NOGUCHI Kay <kay@v6.access.co.jp>
+
+ * ripngd.c (no_ripng_route): route_unlock_node () is not needed.
+
+2001-08-26 NOGUCHI Kay <kay@v6.access.co.jp>
+
+ * ripngd.h (struct ripng_interface): Add passive interface option.
+
+2001-08-19 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92a released.
+
+2001-08-15 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92 released.
+
+2001-08-07 Akira Kato <kato@wide.ad.jp>
+
+ * ripngd.c (ripng_timers): "timers basic" argument is fixed.
+
+2001-02-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.91 is released.
+
+2001-01-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.90 is released.
+
+2001-01-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripngd.h (RIPNG_VTYSH_PATH): Change "/tmp/ripngd" to
+ "/tmp/.ripngd".
+
+2000-10-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.89 is released.
+
+2000-09-20 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripngd.c (ripng_send_packet): Use CMSG_SPACE instead of sizeof
+ hack. Revert privious alignment patch.
+
+2000-09-20 URA Hiroshi <ura@hiru.aoba.yokohama.jp>
+
+ * ripngd.c (ripng_send_packet): Fix an alignment bug. Thus ripngd
+ can't send packets.
+
+2000-09-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripng_interface.c (ripng_interface_address_delete): Connected
+ address delete treatment added.
+
+2000-08-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripng_routemap.c (route_set_metric_compile): When checking '-'
+ character, argv[1] should be argv[0]. Reported by SHIRASAKI
+ Yasuhiro <yasuhiro@ocn.v6.ntt.net>.
+
+2000-08-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.88 is released.
+
+2000-06-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripngd.c (ripng_route_process): Clear prefix_ipv6 before using
+ it.
+ (ripng_redistribute_delete): Fix bug of missing
+ route_unlock_node() when redistribute route is not found.
+ (ripng_redistribute_delete): Make it sure that timers are off.
+ (ripng_redistribute_delete): Likewise.
+
+2000-01-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripngd.c (ripng_route_process): Fix bug of mis-checking of same
+ route.
+ (show_ipv6_ripng): Include ifindex to "show ipv6 ripng" output.
+
+1999-11-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripngd.c (ripng_output_process): Use MINMTU when mtu value is
+ not available.
+
+1999-11-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripngd.c (ripng_output_process): Calculate max RTE count from
+ interface MTU value.
+
+1999-09-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripngd.c (ripng_distribute_update): Fix bug of updating
+ access-list and prefix-list.
+
+1999-09-07 URA Hiroshi <ura@hiru.aoba.yokohama.jp>
+
+ * ripngd.c (ripng_recv_packet): Change CMSG_DATA cast from (u_char
+ *) to (int *). (u_char *) does not work for NetBSD-currnet on
+ SparcStation 10.
+
+1999-08-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripngd.c (ripng_request_process): When request packet comes,
+ check RIPng process is enabled on the interface.
+ (ripng_redistribute_withdraw): Delete routes when `no
+ redistribute' is executed.
+
+1999-08-13 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ripng_zebra.c (ripng_redistribute_ospf6_cmd): Add OSPF6
+ redistribute command.
+
+1999-07-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripngd.c (default_information_originate): Add
+ default-information command.
+
+1999-07-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripngd.c (ripng_route_process): rip_add_route() and
+ rip_delete_route() are deleted. Both functions are integrated
+ into ripng_route_process().
+ (ripng_request_process): Proper reply for request message.
+
+ * ripng_routemap.c: New file added.
+
+1999-07-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripngd.c (ripng_nexthop_rte): RIPng next hop routine is
+ rewritten.
+ (show_ipv6_ripng): Change `show ip ripng' to `show ipv6 ripng'.
+ (ripng_response_process): RIPng incoming packet's hop count check
+ added.
+ (ripng_response_process): Add strict RTE checking.
+
+1999-07-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripngd.c (ripng_add_route): Fix metric compare bug.
+
+1999-06-25 itojun@iijlab.net
+
+ * ripngd.c (ripng_distribute_in): "distribute in" filter in ripngd
+ actually work.
+
+1999-05-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripngd.c (ripng_zebra): Send each ripng information by separate
+ zebra packet.
+
+1999-05-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripng_interface.c (if_add_multicast): Change log to zlog.
+
+1999-05-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripng_interface.c (ripng_zebra_get_interface): Add function.
+
+ * ripng_zebra.c (redistribute_ripng): Delete function because
+ redistirbute the routes to the zebra daemon is now default
+ behavior.
+
+1999-05-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripngd.conf.sample: Change network to route statement.
+
+1999-03-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripngd.c: Old non Advanced API version ripng_send_packet and
+ ripng_recv_packet is removed.
+ * ripng_radix.c: File removed.
+
+1998-12-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Now I assume KAME support Advanced API and use sendmsg/recvmsg.
+
+1998-12-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripng_interface.c: Delete old ifa (interface address) related
+ functions.
+
+1998-12-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripng_debug.[ch]: New file.
+
+ * ripngd.c (ripng_supply): Do not send header only RIPng packet.
+ Change `network' statement to `route' statement.
+ (ripng_request_process): Reply to RIPng REQUEST packet.
+
+1998-12-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripngd.c (ripng_config_write): Delete vector v argument.
+ * ripng_zebra.c (zebra_config_write): Likewise.
+ * ripng_interface.c (interface_config_write): Likewise.
+
+1998-12-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ripng_route.h: New file.
+
+ * ripng_interface.c: Delete #include <linux/in6.h>.
+ ripng_main.c: likewise.
+ ripng_radix.c: likewise.
+ ripng_route.c: likewise.
+ ripng_zebra.c: likewise.
+ ripngd.c: likewise.
+
+1998-12-06 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ripngd.h (IPV6_ADD_MEMBERSHIP): If IPV6_ADD_MEMBERSHIP is not
+ defined. Define IPV6_ADD_MEMBERSHIP as IPV6_JOIN_GROUP.
+
+1998-09-15 HEO SeonMeyong <seirios@matrix.iri.co.jp>
+
+ * all Hydrangea define is changed to KAME.
+
diff --git a/ripngd/Makefile.am b/ripngd/Makefile.am
new file mode 100644
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 <zebra.h>
+#include "command.h"
+#include "ripngd/ripng_debug.h"
+
+/* For debug statement. */
+unsigned long ripng_debug_event = 0;
+unsigned long ripng_debug_packet = 0;
+unsigned long ripng_debug_zebra = 0;
+
+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 <zebra.h>
+
+#include "linklist.h"
+#include "if.h"
+#include "prefix.h"
+#include "memory.h"
+#include "network.h"
+#include "filter.h"
+#include "log.h"
+#include "stream.h"
+#include "zclient.h"
+#include "command.h"
+#include "table.h"
+#include "thread.h"
+
+#include "ripngd/ripngd.h"
+#include "ripngd/ripng_debug.h"
+
+/* 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 <zebra.h>
+
+#include "version.h"
+#include "getopt.h"
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+#include "thread.h"
+#include "log.h"
+#include "prefix.h"
+#include "if.h"
+
+#include "ripngd/ripngd.h"
+
+/* Configuration filename and directory. */
+char config_current[] = RIPNG_DEFAULT_CONFIG;
+char config_default[] = SYSCONFDIR RIPNG_DEFAULT_CONFIG;
+
+/* RIPngd options. */
+struct option longopts[] =
+{
+ { "daemon", no_argument, NULL, 'd'},
+ { "config_file", required_argument, NULL, 'f'},
+ { "pid_file", required_argument, NULL, 'i'},
+ { "log_mode", no_argument, NULL, 'l'},
+ { "help", no_argument, NULL, 'h'},
+ { "vty_addr", required_argument, NULL, 'A'},
+ { "vty_port", required_argument, NULL, 'P'},
+ { "retain", no_argument, NULL, 'r'},
+ { "version", no_argument, NULL, 'v'},
+ { 0 }
+};
+
+/* RIPngd program name */
+
+/* Route retain mode flag. */
+int retain_mode = 0;
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* Process ID saved for use by init system */
+char *pid_file = PATH_RIPNGD_PID;
+
+/* Help information display. */
+static void
+usage (char *progname, int status)
+{
+ if (status != 0)
+ fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+ else
+ {
+ printf ("Usage : %s [OPTION...]\n\
+Daemon which manages RIPng.\n\n\
+-d, --daemon Runs in daemon mode\n\
+-f, --config_file Set configuration file name\n\
+-i, --pid_file Set process identifier file name\n\
+-l. --log_mode Set verbose log mode flag\n\
+-A, --vty_addr Set vty's bind address\n\
+-P, --vty_port Set vty's port number\n\
+-r, --retain When program terminates, retain added route by ripngd.\n\
+-v, --version Print program version\n\
+-h, --help Display this help and exit\n\
+\n\
+Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
+ }
+ exit (status);
+}
+
+/* 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 <zebra.h>
+
+#include "prefix.h"
+#include "table.h"
+#include "memory.h"
+#include "if.h"
+
+#include "ripngd/ripngd.h"
+#include "ripngd/ripng_route.h"
+
+struct ripng_aggregate *
+ripng_aggregate_new ()
+{
+ struct ripng_aggregate *new;
+
+ new = XCALLOC (MTYPE_RIPNG_AGGREGATE, sizeof (struct ripng_aggregate));
+ return new;
+}
+
+void
+ripng_aggregate_free (struct ripng_aggregate *aggregate)
+{
+ XFREE (MTYPE_RIPNG_AGGREGATE, aggregate);
+}
+
+/* Aggregate count increment check. */
+void
+ripng_aggregate_increment (struct route_node *child, struct ripng_info *rinfo)
+{
+ struct route_node *np;
+ struct ripng_aggregate *aggregate;
+
+ for (np = child; np; np = np->parent)
+ if ((aggregate = np->aggregate) != NULL)
+ {
+ aggregate->count++;
+ rinfo->suppress++;
+ }
+}
+
+/* Aggregate count decrement check. */
+void
+ripng_aggregate_decrement (struct route_node *child, struct ripng_info *rinfo)
+{
+ struct route_node *np;
+ struct ripng_aggregate *aggregate;
+
+ for (np = child; np; np = np->parent)
+ if ((aggregate = np->aggregate) != NULL)
+ {
+ aggregate->count--;
+ rinfo->suppress--;
+ }
+}
+
+/* RIPng routes treatment. */
+int
+ripng_aggregate_add (struct prefix *p)
+{
+ struct route_node *top;
+ struct route_node *rp;
+ struct ripng_info *rinfo;
+ struct ripng_aggregate *aggregate;
+ struct ripng_aggregate *sub;
+
+ /* Get top node for aggregation. */
+ top = route_node_get (ripng->table, p);
+
+ /* Allocate new aggregate. */
+ aggregate = ripng_aggregate_new ();
+ aggregate->metric = 1;
+
+ top->aggregate = aggregate;
+
+ /* Suppress routes match to the aggregate. */
+ for (rp = route_lock_node (top); rp; rp = route_next_until (rp, top))
+ {
+ /* Suppress normal route. */
+ if ((rinfo = rp->info) != NULL)
+ {
+ aggregate->count++;
+ rinfo->suppress++;
+ }
+ /* Suppress aggregate route. This may not need. */
+ if (rp != top && (sub = rp->aggregate) != NULL)
+ {
+ aggregate->count++;
+ sub->suppress++;
+ }
+ }
+
+ return 0;
+}
+
+/* Delete RIPng static route. */
+int
+ripng_aggregate_delete (struct prefix *p)
+{
+ struct route_node *top;
+ struct route_node *rp;
+ struct ripng_info *rinfo;
+ struct ripng_aggregate *aggregate;
+ struct ripng_aggregate *sub;
+
+ /* Get top node for aggregation. */
+ top = route_node_get (ripng->table, p);
+
+ /* Allocate new aggregate. */
+ aggregate = top->aggregate;
+
+ /* Suppress routes match to the aggregate. */
+ for (rp = route_lock_node (top); rp; rp = route_next_until (rp, top))
+ {
+ /* Suppress normal route. */
+ if ((rinfo = rp->info) != NULL)
+ {
+ aggregate->count--;
+ rinfo->suppress--;
+ }
+
+ if (rp != top && (sub = rp->aggregate) != NULL)
+ {
+ aggregate->count--;
+ sub->suppress--;
+ }
+ }
+
+ top->aggregate = NULL;
+ ripng_aggregate_free (aggregate);
+
+ route_unlock_node (top);
+ route_unlock_node (top);
+
+ return 0;
+}
diff --git a/ripngd/ripng_route.h b/ripngd/ripng_route.h
new file mode 100644
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 <zebra.h>
+
+#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 <zebra.h>
+
+#include "command.h"
+#include "prefix.h"
+#include "stream.h"
+#include "routemap.h"
+#include "zclient.h"
+#include "log.h"
+
+#include "ripngd/ripngd.h"
+
+/* All information about zebra. */
+struct zclient *zclient = NULL;
+
+/* Callback prototypes for zebra client service. */
+int ripng_interface_up (int, struct zclient *, zebra_size_t);
+int ripng_interface_down (int, struct zclient *, zebra_size_t);
+int ripng_interface_add (int, struct zclient *, zebra_size_t);
+int ripng_interface_delete (int, struct zclient *, zebra_size_t);
+int ripng_interface_address_add (int, struct zclient *, zebra_size_t);
+int ripng_interface_address_delete (int, struct zclient *, zebra_size_t);
+
+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 <zebra.h>
+
+/* For struct udphdr. */
+#include <netinet/udp.h>
+
+#include "prefix.h"
+#include "filter.h"
+#include "log.h"
+#include "thread.h"
+#include "memory.h"
+#include "if.h"
+#include "stream.h"
+#include "table.h"
+#include "command.h"
+#include "sockopt.h"
+#include "distribute.h"
+#include "plist.h"
+#include "routemap.h"
+#include "if_rmap.h"
+
+#include "ripngd/ripngd.h"
+#include "ripngd/ripng_route.h"
+#include "ripngd/ripng_debug.h"
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+/* RIPng structure which includes many parameters related to RIPng
+ protocol. If ripng couldn't active or ripng doesn't configured,
+ ripng->fd must be negative value. */
+struct ripng *ripng = NULL;
+
+enum
+{
+ ripng_all_route,
+ ripng_changed_route,
+ ripng_split_horizon,
+ ripng_no_split_horizon
+};
+
+/* Prototypes. */
+void
+ripng_output_process (struct interface *, struct sockaddr_in6 *, int, int);
+
+int
+ripng_triggered_update (struct thread *);
+
+/* RIPng next hop specification. */
+struct ripng_nexthop
+{
+ enum ripng_nexthop_type
+ {
+ RIPNG_NEXTHOP_UNSPEC,
+ RIPNG_NEXTHOP_ADDRESS
+ } flag;
+ struct in6_addr address;
+};
+
+/* 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 <john.fraizer@enterzone.net>
+## *All* copyright notices must remain in place to use this code.
+##
+## The latest version of this code is available at:
+## ftp://ftp.enterzone.net/looking-glass/
+##
+##
+## This file is part of GNU Zebra.
+##
+## GNU Zebra is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by the
+## Free Software Foundation; either version 2, or (at your option) any
+## later version.
+##
+## GNU Zebra is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with GNU Zebra; see the file COPYING. If not, write to the
+## Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+## Boston, MA 02111-1307, USA.
+
+require 5.002;
+use POSIX;
+use Net::Telnet ();
+
+
+
+## Set the URL for your site.
+$url="http://www.sample.com/mrlg.cgi";
+
+## Set your router variables in sub set_router and modify the selections in Main to match.
+
+
+############################################################
+#Main
+############################################################
+{
+
+## Set the router default
+@Form{'router'} = "router1";
+
+## Get the form results now so we can override the default router
+get_form();
+
+print "Content-type: text/html\n\n";
+
+print '
+<html>
+<head>
+<title>Multi-Router Looking Glass for Zebra</title>
+</head>
+<body bgcolor=white>
+
+<font face=arial size=3 color=blue>
+<h1>Multi-Router Looking Glass for Zebra</h1>
+Copyright 2000 - John Fraizer, EnterZone Inc.
+<br>
+';
+
+print '
+<font color=black>
+';
+print "<form METHOD=\"POST\" action=\"$url\">\n";
+print "<B>Router:</B> <SELECT Name=\"router\" Size=1>\n";
+print "<OPTION Value=\"$Form{'router'}\">$Form{'router'}\n";
+print '
+<OPTION Value="router1">router1
+<OPTION Value="router2">router2
+<OPTION Value="router3">router3
+<OPTION Value="router4">router4
+</select>
+<br><br>
+<B>Query</B>:
+<br>
+<input type=radio name=query value=1>show ip bgp<br>
+<input type=radio name=query value=2>show ip bgp summary<br>
+<input type=radio name=query value=3>show ip route<br>
+<input type=radio name=query value=4>show interface<br>
+<input type=radio name=query value=5>show ipv6 bgp<br>
+<input type=radio name=query value=6>show ipv6 bgp summary<br>
+<input type=radio name=query value=7>show ipv6 route<br>
+<br>
+<B>Argument:</B> <input type=text name=arg length=20 maxlength=60>
+<input type="submit" value="Execute"></form>
+';
+
+## Set up the address, pw and ports, etc for the selected router.
+set_router();
+
+## Set up which command is to be executed (and then execute it!)
+set_command();
+
+
+print '
+<br><br>
+</font>
+<font color=blue face=arial size=2>
+Multi-Router Looking Glass for Zebra version 1.0<br>
+Written by: John Fraizer -
+<a href="http://www.ez-hosting.net/">EnterZone, Inc</a><br>
+Source code: <a href="ftp://ftp.enterzone.net/looking-glass/">ftp://ftp.enterzone.net/looking-glass/</a>
+</body>
+</html>
+';
+
+## All done!
+
+exit (0);
+}
+
+
+############################################################
+sub get_form
+############################################################
+{
+
+ #read STDIN
+ read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
+
+ # Split the name-value pairs
+ @pairs = split(/&/, $buffer);
+
+ # For each name-value pair:
+ foreach $pair (@pairs)
+ {
+
+ # Split the pair up into individual variables.
+ local($name, $value) = split(/=/, $pair);
+
+ # Decode the form encoding on the name and value variables.
+ $name =~ tr/+/ /;
+ $name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
+
+ $value =~ tr/+/ /;
+ $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
+
+ # If they try to include server side includes, erase them, so they
+ # aren't a security risk if the html gets returned. Another
+ # security hole plugged up.
+ $value =~ s/<!--(.|\n)*-->//g;
+
+ @Form{$name} = $value ;
+
+ }
+
+}
+
+############################################################
+sub set_router
+############################################################
+
+## $server is the IP address of the router running zebra
+## $login_pass is the password of the router
+## $bgpd is the port that bgpd will answer on
+## $zebra is the port that zebra will answer on
+## if $zebra is "", it will disable sh ip route and sh int for that router.
+## if $full_tables is set to "1" for a router, full BGP and IP ROUTE table dumps will be allowed via the looking glass.
+## This is a BAD thing to do if you have multiple full views on a router. That's why the option is there.
+
+{
+if ($Form{'router'} eq 'router1')
+ {
+$server = '10.1.1.1';
+$login_pass = 'zebra';
+$bgpd = "2605";
+$zebra = "";
+$full_tables=1;
+
+ }
+
+elsif ($Form{'router'} eq 'router2')
+ {
+$server = '10.1.1.2';
+$login_pass = 'zebra';
+$bgpd = "2605";
+$zebra = "2601";
+ }
+
+elsif ($Form{'router'} eq 'router3')
+ {
+$server = '10.1.1.3';
+$login_pass = 'zebra';
+$bgpd = "2605";
+$zebra = "2601";
+$full_tables=1;
+ }
+
+elsif ($Form{'router'} eq 'router4')
+ {
+$server = '10.1.1.4';
+$login_pass = 'zebra';
+$bgpd = "2605";
+$zebra = "2601";
+ }
+
+
+}
+
+
+############################################################
+sub set_command
+############################################################
+{
+if ($Form{'query'} eq '1')
+ {
+ sh_ip_bgp('ip');
+ }
+
+elsif ($Form{'query'} eq '2')
+ {
+ sh_ip_bgp_sum('ip');
+ }
+
+if ($Form{'query'} eq '3')
+ {
+ sh_ip_route('ip');
+ }
+
+if ($Form{'query'} eq '4')
+ {
+ sh_int();
+ }
+if ($Form{'query'} eq '5')
+ {
+ sh_ip_bgp('ipv6');
+ }
+if ($Form{'query'} eq '6')
+ {
+ sh_ip_bgp_sum('ipv6');
+ }
+if ($Form{'query'} eq '7')
+ {
+ sh_ip_route('ipv6');
+ }
+}
+############################################################
+sub sh_ip_bgp
+############################################################
+{
+my $protocol = shift(@_);
+$port = $bgpd;
+if ($protocol ne 'ip' && $protocol ne 'ipv6')
+ {
+ print "Invalid protocol: $protocol\n";
+ print "protocol must be 'ip' or 'ipv6'\n\n";
+ return;
+ }
+$command = "show $protocol bgp $Form{'arg'}";
+if ($Form{'arg'} eq '')
+ {
+ if ($full_tables eq '1')
+ {
+ execute_command();
+ }
+ else
+ {
+ print "Sorry. Displaying the FULL routing table would put too much load on the router!\n\n";
+ }
+ }
+else
+ {
+ execute_command();
+ }
+}
+
+############################################################
+sub sh_ip_bgp_sum
+############################################################
+{
+ my $protocol = shift(@_);
+ $port = $bgpd;
+ if ($protocol ne 'ip' && $protocol ne 'ipv6')
+ {
+ print "Invalid protocol: $protocol\n";
+ print "protocol must be 'ip' or 'ipv6'\n\n";
+ return;
+ }
+ $command = "show $protocol bgp summary";
+ execute_command();
+}
+
+############################################################
+sub sh_ip_route
+############################################################
+{
+
+if ($zebra eq '')
+ {
+ print "Sorry. The <b>show ip route</b> command is disabled for this router."
+ }
+else
+ {
+
+ $port = $zebra;
+ my $protocol = shift(@_);
+ if ($protocol ne 'ip' && $protocol ne 'ipv6')
+ {
+ print "Invalid protocol: $protocol\n";
+ print "protocol must be 'ip' or 'ipv6'\n\n";
+ return;
+ }
+ $command = "show $protocol route $Form{'arg'}";
+ if ($Form{'arg'} eq '')
+ {
+ if ($full_tables eq '1')
+ {
+ execute_command();
+ }
+ else
+ {
+ print "Sorry. Displaying the FULL routing table would put too much load on the router!\n\n";
+ }
+ }
+ else
+ {
+ execute_command();
+ }
+ }
+}
+
+############################################################
+sub sh_int
+############################################################
+{
+if ($zebra eq '')
+ {
+ print "Sorry. The <b>show interface</b> command is disabled for this router."
+ }
+else
+ {
+ $port = $zebra;
+ $command = "show interface $Form{'arg'}";
+ execute_command();
+ }
+}
+
+
+
+############################################################
+sub execute_command
+############################################################
+## This code is based on:
+##
+## Zebra interactive console
+## Copyright (C) 2000 Vladimir B. Grebenschikov <vova@express.ru>
+##
+
+
+{
+
+print "Executing command = $command";
+
+# my $port = ($opt_z ? 'zebra' : 0) ||
+# ($opt_b ? 'bgpd' : 0) ||
+# ($opt_o ? 'ospfd' : 0) ||
+# ($opt_r ? 'ripd' : 0) || 'bgpd';
+
+my $cmd = $command;
+
+
+ my $t = new Net::Telnet (Timeout => 10,
+ Prompt => '/[\>\#] $/',
+ Port => $port);
+
+ $t->open ($server);
+
+ $t->cmd ($login_pass);
+
+ if ($cmd)
+ {
+ docmd ($t, $cmd);
+ }
+
+}
+
+############################################################
+sub docmd
+############################################################
+{
+ my ($t, $cmd) = @_;
+ my @lines = $t->cmd ($cmd);
+ print "<pre>\n";
+ print join ('', grep (!/[\>\#] $/, @lines)), "\n";
+ print "</pre>";
+}
+
+
+
diff --git a/tools/rrcheck.pl b/tools/rrcheck.pl
new file mode 100644
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 = <LOG>;
+ if ($index =~ /[bgpd]/) {
+ break;
+ }
+ }
+
+ while (<LOG>) {
+ if (/([\d\.\/]+)\s+([\d\.]+)\s+(\d+)\s+(\d+)\s+([\d ]+)\s+[ie\?]/) {
+ $prefix = $1;
+ $nexthop = $2;
+ $med = $3;
+ $dummy = $4;
+ $aspath = $5;
+ ($origin) = ($aspath =~ /([\d]+)$/);
+
+ print "$nexthop [$origin] $prefix $aspath ";
+
+ $ret = &whois_check ($prefix, $origin);
+ if ($ret == 0) {
+ print "Check OK\n";
+ } elsif ($ret == 1){
+ print "AS orgin mismatch\n";
+ } else {
+ print "prefix doesn't exist \n";
+ }
+ }
+ }
+}
+
+sub whois_check
+{
+ local ($prefix, $origin) = @_;
+ local ($rr_prefix, $rr_origin) = ();
+ local (@result);
+
+ $origin = "AS" . $origin;
+
+ @result = &whois ($prefix);
+
+ $prefix_match = 0;
+ foreach (@result) {
+ if (/^route:.*\s([\d\.\/]+)$/) {
+ $rr_prefix = $1;
+ }
+ if (/^origin:.*\s(AS[\d]+)$/) {
+ $rr_origin = $1;
+
+ if ($prefix eq $rr_prefix and $origin eq $rr_origin) {
+ return 0;
+ } elsif ($prefix eq $rr_prefix) {
+ $prefix_match = 1;
+ }
+ }
+ }
+# alarm_mail ($prefix, $origin, @result);
+ if ($prefix_match) {
+ return 1;
+ } else {
+ return 2;
+ }
+}
+
+## get port of whois
+sub get_whois_port
+{
+ local ($name, $aliases, $port, $proto) = getservbyname ("whois", "tcp");
+ return ($port, $proto);
+}
+
+## whois lookup
+sub whois
+{
+ local ($query) = @_;
+ local ($port, $proto) = &get_whois_port;
+ local (@result);
+
+ if ($whois_host=~ /^\s*\d+\.\d+\.\d+\.\d+\s*$/) {
+ $address = pack ("C4",split(/\./,$host));
+ } else {
+ $address = (gethostbyname ($whois_host))[4];
+ }
+
+ socket (SOCKET, PF_INET, SOCK_STREAM, $proto);
+
+ if (connect (SOCKET, sockaddr_in ($port, $address))) {
+ local ($oldhandle) = select (SOCKET);
+ $| = 1;
+ select($oldhandle);
+
+ print SOCKET "$query\r\n";
+
+ @result = <SOCKET>;
+ return @result;
+ }
+}
+
+##
+sub alarm_mail
+{
+ local ($prefix, $origin, @result) = @_;
+
+ open (MAIL, "|$mailer -t $mail_address") || die "can't open $mailer";
+
+ print MAIL "From: root\@rr1.jpix.ad.jp\n";
+ print MAIL "Subject: RR $origin $prefix\n";
+ print MAIL "MIME-Version: 1.0\n";
+ print MAIL "Content-Type: text/plain; charset=us-ascii \n\n";
+ print MAIL "RR Lookup Error Report\n";
+ print MAIL "======================\n";
+ print MAIL "Announced route : $prefix from $origin\n\n";
+ print MAIL "@result";
+ close MAIL;
+}
diff --git a/tools/rrlookup.pl b/tools/rrlookup.pl
new file mode 100644
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 (<LOG>) {
+ if (/Update\S+ ([\d\.\/]+) .* (\d+) [ie\?]/) {
+ $prefix = $1;
+ $origin = $2;
+ $ret = &whois_check ($prefix, $origin);
+ if ($ret) {
+ print LOOKUP "$prefix AS$origin : Check OK\n";
+ } else {
+ print LOOKUP "$prefix AS$origin : Error\n";
+ }
+# fflush (LOOKUP);
+ }
+ }
+ sleep (3);
+ }
+}
+
+sub whois_check
+{
+ local ($prefix, $origin) = @_;
+ local ($rr_prefix, $rr_origin) = ();
+ local (@result);
+
+ $origin = "AS" . $origin;
+
+# print "$prefix $origin\n";
+
+ @result = &whois ($prefix);
+
+ foreach (@result) {
+ if (/^route:.*\s([\d\.\/]+)$/) {
+ $rr_prefix = $1;
+ }
+ if (/^origin:.*\s(AS[\d]+)$/) {
+ $rr_origin = $1;
+
+ if ($prefix eq $rr_prefix and $origin eq $rr_origin) {
+ return 1;
+ }
+ }
+ }
+ alarm_mail ($prefix, $origin, @result);
+ return 0;
+}
+
+## get port of whois
+sub get_whois_port
+{
+ local ($name, $aliases, $port, $proto) = getservbyname ("whois", "tcp");
+ return ($port, $proto);
+}
+
+## whois lookup
+sub whois
+{
+ local ($query) = @_;
+ local ($port, $proto) = &get_whois_port;
+ local (@result);
+
+ if ($whois_host=~ /^\s*\d+\.\d+\.\d+\.\d+\s*$/) {
+ $address = pack ("C4",split(/\./,$host));
+ } else {
+ $address = (gethostbyname ($whois_host))[4];
+ }
+
+ socket (SOCKET, PF_INET, SOCK_STREAM, $proto);
+
+ if (connect (SOCKET, sockaddr_in ($port, $address))) {
+ local ($oldhandle) = select (SOCKET);
+ $| = 1;
+ select($oldhandle);
+
+ print SOCKET "$query\r\n";
+
+ @result = <SOCKET>;
+ return @result;
+ }
+}
+
+##
+sub alarm_mail
+{
+ local ($prefix, $origin, @result) = @_;
+
+ open (MAIL, "|$mailer -t $mail_address") || die "can't open $mailer";
+
+ print MAIL "From: root\@rr1.jpix.ad.jp\n";
+ print MAIL "Subject: RR $origin $prefix\n";
+ print MAIL "MIME-Version: 1.0\n";
+ print MAIL "Content-Type: text/plain; charset=us-ascii \n\n";
+ print MAIL "RR Lookup Error Report\n";
+ print MAIL "======================\n";
+ print MAIL "Announced route : $prefix from $origin\n\n";
+ print MAIL "@result";
+ close MAIL;
+}
diff --git a/tools/zc.pl b/tools/zc.pl
new file mode 100755
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 <vova@express.ru>
+##
+## This file is part of GNU Zebra.
+##
+## GNU Zebra is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by the
+## Free Software Foundation; either version 2, or (at your option) any
+## later version.
+##
+## GNU Zebra is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with GNU Zebra; see the file COPYING. If not, write to the
+## Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+## Boston, MA 02111-1307, USA.
+
+use Net::Telnet ();
+use Getopt::Std;
+
+#use strict;
+
+my $host = `hostname -s`; $host =~ s/\s//g;
+my $port = 'zebra';
+my $server = 'localhost';
+
+# Check arguments
+&getopts ('l:e:czborh');
+
+&usage () if $opt_h;
+
+# main
+{
+ my $login_pass = $opt_l || $ENV{ZEBRA_PASSWORD} || 'zebra';
+ my $enable_pass = $opt_e || $ENV{ZEBRA_ENABLE} || '';
+
+ my $port = ($opt_z ? 'zebra' : 0) ||
+ ($opt_b ? 'bgpd' : 0) ||
+ ($opt_o ? 'ospfd' : 0) ||
+ ($opt_r ? 'ripd' : 0) || 'zebra';
+
+ my $cmd = join (' ', @ARGV);
+
+ my $t = new Net::Telnet (Timeout => 10,
+ Prompt => '/[\>\#] $/',
+ Port => $port);
+
+ $t->open ($server);
+
+ $t->cmd ($login_pass);
+ if ($enable_pass) {
+ $t->cmd (String => 'en',
+ Prompt => '/Password: /');
+ $t->cmd ($enable_pass);
+ }
+ $t->cmd ('conf t') if "$opt_c";
+
+ if ($cmd)
+ {
+ docmd ($t, $cmd);
+ exit (0);
+ }
+
+ my $prompt = sprintf ("%s%s# ", $host,
+ ($port eq 'zebra') ? '' : "/$port");
+
+ print "\nZEBRA interactive console ($port)\n\n" if -t STDIN;
+
+ while (1)
+ {
+ $| = 1;
+ print $prompt if -t STDIN;
+ chomp ($cmd = <>);
+ if (!defined ($cmd))
+ {
+ print "\n" if -t STDIN;
+ exit(0);
+ }
+ exit (0) if ($cmd eq 'q' || $cmd eq 'quit');
+
+ docmd ($t, $cmd) if $cmd !~ /^\s*$/;
+ }
+
+ exit(0);
+}
+
+sub docmd
+{
+ my ($t, $cmd) = @_;
+ my @lines = $t->cmd ($cmd);
+ print join ('', grep (!/[\>\#] $/, @lines)), "\n";
+}
+
+sub usage
+{
+ print "USAGE: $0 [-l LOGIN_PASSWORD] [-e ENABLE_PASSWORD] [-z|-b|-o|-r|-h] [<cmd>]\n",
+ "\t-l - specify login password\n",
+ "\t-e - specify enable password\n",
+ "\t-c - execute command in configure mode\n",
+ "\t-z - connect to zebra daemon\n",
+ "\t-b - connect to bgpd daemon\n",
+ "\t-o - connect to ospfd daemon\n",
+ "\t-r - connect to ripd daemon\n",
+ "\t-h - help\n";
+ exit (1);
+}
diff --git a/tools/zebra.el b/tools/zebra.el
new file mode 100644
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 <kunihiro@zebra.org>
+#
+rm -f config.cache
+rm -f Makefile.in
+rm -f aclocal.m4
+rm -f config.h.in
+rm -f configure
+aclocal
+autoheader
+autoconf
+automake --foreign
diff --git a/vtysh/.cvsignore b/vtysh/.cvsignore
new file mode 100644
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 <kunihiro@ipinfusion.com>
+
+ * zebra-0.93 released.
+
+2001-08-19 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92a released.
+
+2001-08-15 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92 released.
+
+2001-02-20 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh.c (vtysh_client_config): Do not set bufsz to 120.
+ Suggested by: Matthew Grant <grantma@anathoth.gen.nz>.
+
+2001-02-15 Hideto Yamakawa <yamakawa@dml.com>
+
+ * vtysh.c (vtysh_client_execute): Call fflush after fprintf.
+
+ * vtysh_config.c (vtysh_config_dump): Use VTYSH_PAGER if defined.
+
+2001-02-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh.c (vtysh_execute_func): Add fflush before pclose.
+
+2001-02-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh.c: VTY shell pager name. When environment variable
+ VTYSH_PAGER is defined, use it as VTY shell pager.
+
+2001-02-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh.c (vtysh_execute_func): Add pager argument for test of
+ pager invocation.
+
+2001-02-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * extract.pl: Add -DHAVE_CONFIG_H option to cpp.
+
+2001-02-08 Matthew Grant <grantma@anathoth.gen.nz>
+
+ * vtysh.c (vtysh_client_config): Use sysconf to determine output
+ buffer size.
+ (vtysh_write_memory): Set umask 0077.
+ (vtysh_connect): Check permission to the socket.
+
+2001-02-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.91 is released.
+
+2001-01-31 Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+ * vtysh.c (new_completion): Fix problem of appending space when
+ completion is executed.
+
+2001-01-23 Akihiro Mizutani <mizutani@dml.com>
+
+ * vtysh.c (vtysh_write_terminal): "write terminal" to all node.
+
+2001-01-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh.c (vtysh_execute): Fix unconditional lock by other VTY.
+ Suggested by Hideto Yamakawa <yamakawa@dml.com>.
+
+2001-01-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.90 is released.
+
+2001-01-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh.h (ZEBRA_PATH): Fix new vtysh path. Reported by "Matt
+ Ranney" <mjr@ranney.com>
+
+2000-11-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh.c (DEFUNSH): Add "address-family vpnv4" DEFUNSH.
+
+2000-10-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh.c (execute_command): Add two arguemnt support for
+ executing child process.
+ (vtysh_telnet_port): New command "telnet WORD PORT" is added.
+
+2000-10-23 Akihiro Mizutani <mizutani@dml.com>
+
+ * vtysh.c (vtysh_write_memory): Display [OK] when configuration is
+ saved without problem.
+
+2000-10-20 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh.c (vtysh_config_from_file): "key chain" command with -b
+ flag problem is fixed.
+
+2000-10-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh_user.c: Change to use linklist.c.
+
+2000-10-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am (noinst_HEADERS): Add vtysh_user.h.
+
+ * zebra-0.89 is released.
+
+2000-09-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh_main.c: Declare thread master.
+
+2000-08-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh_main.c (main): Add missing --help procudure. Reported by
+ Patrick Rother <krd@roka.net>.
+
+2000-08-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh.c (DEFUNSH): "interface IFNAME" works.
+
+2000-08-20 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh_user.c: Change name from vtysh_pam.c.
+
+ * vtysh.conf.sample: New file for vtysh configuration.
+
+2000-08-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh_pam.c (vtysh_pam): New file for PAM.
+
+2000-08-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.88 is released.
+
+2000-08-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am (vtysh_LDADD): Remove -lreadline and -lncurses.
+
+ * vtysh.c (vtysh_connect): Use AF_UNIX instead of AF_LOCAL for
+ backward compatibility.
+
+2000-07-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * extract.pl: Change regexp to match DEFUN and ALIAS at the same
+ time.
+
+2000-07-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh.c (signal_init): Ignore SIGPIPE signal.
+
+2000-07-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * extract.pl: ALIAS command can be extracted by extract.pl.
+
+2000-07-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * extract.pl: Fix scalar and array semantics.
+
+ * vtysh.c (vtysh_telnet): Add "telnet" client command.
+
+2000-07-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh.c (main): Add -e flag for passing command from arugment.
+ (vtysh_ping): Add "ping" command for test of command execution.
+ (init_node): Add "traceroute" command.
+ (vtysh_start_shell): Add "start-shell", "start-shell bash",
+ "start-shell zsh".
+ (sigint): Add check for execute_flag for avoid duplicate prompt.
+
+2000-06-28 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vtysh.c: New file for vty shell.
+ * vtysh.h: Likewise.
+ * extract.pl: Likewise.
+ * vtysh_cmd.c: Generate by extract.pl.
diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am
new file mode 100644
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 <<EOF;
+#include <zebra.h>
+#include "command.h"
+#include "vtysh.h"
+
+EOF
+
+$ignore{'"interface IFNAME"'} = "ignore";
+$ignore{'"ip vrf NAME"'} = "ignore";
+$ignore{'"router rip"'} = "ignore";
+$ignore{'"router ripng"'} = "ignore";
+$ignore{'"router ospf"'} = "ignore";
+$ignore{'"router ospf <0-65535>"'} = "ignore";
+$ignore{'"router ospf6"'} = "ignore";
+$ignore{'"router bgp <1-65535>"'} = "ignore";
+$ignore{'"router bgp <1-65535> view WORD"'} = "ignore";
+$ignore{'"address-family ipv4"'} = "ignore";
+$ignore{'"address-family ipv4 (unicast|multicast)"'} = "ignore";
+$ignore{'"address-family ipv6"'} = "ignore";
+$ignore{'"address-family ipv6 unicast"'} = "ignore";
+$ignore{'"address-family vpnv4"'} = "ignore";
+$ignore{'"address-family vpnv4 unicast"'} = "ignore";
+$ignore{'"address-family ipv4 vrf NAME"'} = "ignore";
+$ignore{'"exit-address-family"'} = "ignore";
+$ignore{'"key chain WORD"'} = "ignore";
+$ignore{'"key <0-2147483647>"'} = "ignore";
+$ignore{'"route-map WORD (deny|permit) <1-65535>"'} = "ignore";
+$ignore{'"show route-map"'} = "ignore";
+
+foreach (@ARGV) {
+ $file = $_;
+
+ open (FH, "cpp -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -I. -I.. -I../lib $file |");
+ local $/; undef $/;
+ $line = <FH>;
+ close (FH);
+
+ @defun = ($line =~ /(?:DEFUN|ALIAS)\s*\((.+?)\);?\s?\s?\n/sg);
+ @install = ($line =~ /install_element \(\s*[0-9A-Z_]+,\s*&[^;]*;\s*\n/sg);
+
+ # $protocol is VTYSH_PROTO format for redirection of user input
+ if ($file =~ /lib/) {
+ if ($file =~ /keychain.c/) {
+ $protocol = "VTYSH_RIPD";
+ }
+ if ($file =~ /routemap.c/) {
+ $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD";
+ }
+ if ($file =~ /filter.c/) {
+ $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD";
+ }
+ if ($file =~ /plist.c/) {
+ $protocol = "VTYSH_RIPD|VTYSH_BGPD";
+ }
+ } else {
+ ($protocol) = ($file =~ /\/([a-z0-9]+)/);
+ $protocol = "VTYSH_" . uc $protocol;
+ }
+
+ # DEFUN process
+ foreach (@defun) {
+ my (@defun_array);
+ @defun_array = split (/,/);
+ $defun_array[0] = '';
+
+
+ # Actual input command string.
+ $str = "$defun_array[2]";
+ $str =~ s/^\s+//g;
+ $str =~ s/\s+$//g;
+
+ # Get VTY command structure. This is needed for searching
+ # install_element() command.
+ $cmd = "$defun_array[1]";
+ $cmd =~ s/^\s+//g;
+ $cmd =~ s/\s+$//g;
+
+ # Append _vtysh to structure then build DEFUN again
+ $defun_array[1] = $cmd . "_vtysh";
+ $defun_body = join (", ", @defun_array);
+
+ # $cmd -> $str hash for lookup
+ $cmd2str{$cmd} = $str;
+ $cmd2defun{$cmd} = $defun_body;
+ $cmd2proto{$cmd} = $protocol;
+ }
+
+ # install_element() process
+ foreach (@install) {
+ my (@element_array);
+ @element_array = split (/,/);
+
+ # Install node
+ $enode = $element_array[0];
+ $enode =~ s/^\s+//g;
+ $enode =~ s/\s+$//g;
+ ($enode) = ($enode =~ /([0-9A-Z_]+)$/);
+
+ # VTY command structure.
+ ($ecmd) = ($element_array[1] =~ /&([^\)]+)/);
+ $ecmd =~ s/^\s+//g;
+ $ecmd =~ s/\s+$//g;
+
+ # Register $ecmd
+ if (defined ($cmd2str{$ecmd})
+ && ! defined ($ignore{$cmd2str{$ecmd}})) {
+ my ($key);
+ $key = $enode . "," . $cmd2str{$ecmd};
+ $ocmd{$key} = $ecmd;
+ $odefun{$key} = $cmd2defun{$ecmd};
+ push (@{$oproto{$key}}, $cmd2proto{$ecmd});
+ }
+ }
+}
+
+# Check finaly alive $cmd;
+foreach (keys %odefun) {
+ my ($node, $str) = (split (/,/));
+ my ($cmd) = $ocmd{$_};
+ $live{$cmd} = $_;
+}
+
+# Output DEFSH
+foreach (keys %live) {
+ my ($proto);
+ my ($key);
+ $key = $live{$_};
+ $proto = join ("|", @{$oproto{$key}});
+ printf "DEFSH ($proto$odefun{$key})\n\n";
+}
+
+# Output install_element
+print <<EOF;
+void
+vtysh_init_cmd ()
+{
+EOF
+
+foreach (keys %odefun) {
+ my ($node, $str) = (split (/,/));
+ $cmd = $ocmd{$_};
+ $cmd =~ s/_cmd/_cmd_vtysh/;
+ printf " install_element ($node, &$cmd);\n";
+}
+
+print <<EOF
+}
+EOF
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
new file mode 100644
index 00000000..965eb392
--- /dev/null
+++ b/vtysh/vtysh.c
@@ -0,0 +1,1803 @@
+/* Virtual terminal interface shell.
+ * Copyright (C) 2000 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include <sys/un.h>
+#include <setjmp.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "command.h"
+#include "memory.h"
+#include "vtysh/vtysh.h"
+
+/* Struct VTY. */
+struct vty *vty;
+
+/* VTY shell pager name. */
+char *vtysh_pager_name = NULL;
+
+/* VTY shell client structure. */
+struct vtysh_client
+{
+ int fd;
+} vtysh_client[VTYSH_INDEX_MAX];
+
+/* 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 <zebra.h>
+#include "command.h"
+#include "vtysh.h"
+
+DEFSH (VTYSH_BGPD, neighbor_version_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X) " "version (4|4-)",
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Neighbor's BGP version\n"
+ "Border Gateway Protocol 4\n"
+ "Multiprotocol Extensions for BGP-4(Old Draft)\n")
+
+DEFSH (VTYSH_BGPD, no_set_aspath_prepend_cmd_vtysh,
+ "no set as-path prepend",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "Prepend string for a BGP AS-path attribute\n"
+ "Prepend to the as-path\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, clear_ipv6_prefix_list_cmd_vtysh,
+ "clear ipv6 prefix-list",
+ "Reset functions\n"
+ "IPv6 information\n"
+ "Build a prefix list\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_vpnv4_soft_out_cmd_vtysh,
+ "clear ip bgp A.B.C.D vpnv4 unicast soft out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "Address family\n"
+ "Address Family Modifier\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_host_any_cmd_vtysh,
+ "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D any",
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "A single source host\n"
+ "Source address\n"
+ "Any destination host\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_description_cmd_vtysh,
+ "ip prefix-list WORD description .LINE",
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Prefix-list specific description\n"
+ "Up to 80 characters describing this prefix-list\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_route_cmd_vtysh,
+ "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE)",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_intra_inter_external_cmd_vtysh,
+ "distance ospf intra-area <1-255> inter-area <1-255> external <1-255>",
+ "Define an administrative distance\n"
+ "OSPF Administrative distance\n"
+ "Intra-area routes\n"
+ "Distance for intra-area routes\n"
+ "Inter-area routes\n"
+ "Distance for inter-area routes\n"
+ "External routes\n"
+ "Distance for external routes\n")
+
+DEFSH (VTYSH_OSPFD, area_default_cost_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) default-cost <0-16777215>",
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Set the summary-default cost of a NSSA or stub area\n"
+ "Stub's advertised default summary cost\n")
+
+DEFSH (VTYSH_RIPNGD, default_information_originate_cmd_vtysh,
+ "default-information originate",
+ "Default route information\n"
+ "Distribute default route\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_update_source_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "update-source",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Source of routing updates\n"
+ "Interface name\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_route_cmd_vtysh,
+ "show bgp ipv6 X:X::X:X",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Network in the BGP routing table to display\n")
+
+DEFSH (VTYSH_ZEBRA, no_bandwidth_if_cmd_vtysh,
+ "no bandwidth",
+ "Negate a command or set its defaults\n"
+ "Set bandwidth informational parameter\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_standard_any_cmd_vtysh,
+ "access-list (<1-99>|<1300-1999>) (deny|permit) any",
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP standard access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any source host\n")
+
+DEFSH (VTYSH_BGPD, no_match_ipv6_next_hop_cmd_vtysh,
+ "no match ipv6 next-hop X:X::X:X",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "IPv6 information\n"
+ "Match IPv6 next-hop address of route\n"
+ "IPv6 address of next hop\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_external_out_cmd_vtysh,
+ "clear bgp external out",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all external peers\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_seq_le_cmd_vtysh,
+ "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32>",
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_instance_summary_cmd_vtysh,
+ "show ip bgp view WORD summary",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP view\n"
+ "View name\n"
+ "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_kernel_metric_routemap_cmd_vtysh,
+ "redistribute kernel metric <0-16> route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Metric\n"
+ "Metric value\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_distance_source_cmd_vtysh,
+ "no distance <1-255> A.B.C.D/M",
+ "Negate a command or set its defaults\n"
+ "Define an administrative distance\n"
+ "Administrative distance\n"
+ "IP source prefix\n")
+
+DEFSH (VTYSH_OSPF6D, no_ospf6_redistribute_cmd_vtysh,
+ "no redistribute (static|kernel|connected|ripng|bgp)",
+ "Negate a command or set its defaults\n"
+ "Redistribute\n"
+ "Static route\n"
+ "Kernel route\n"
+ "Connected route\n"
+ "RIPng route\n"
+ "BGP route\n"
+ )
+
+DEFSH (VTYSH_RIPNGD, ripng_aggregate_address_cmd_vtysh,
+ "aggregate-address X:X::X:X/M",
+ "Set aggregate RIPng route announcement\n"
+ "Aggregate network\n")
+
+DEFSH (VTYSH_RIPD, send_lifetime_duration_month_day_cmd_vtysh,
+ "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> duration <1-2147483646>",
+ "Set send lifetime of the key\n"
+ "Time to start\n"
+ "Month of the year to start\n"
+ "Day of th month to start\n"
+ "Year to start\n"
+ "Duration of the key\n"
+ "Duration seconds\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_ge_cmd_vtysh,
+ "ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32>",
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_dampening_cmd_vtysh,
+ "clear ip bgp dampening",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear route flap dampening information\n")
+
+DEFSH (VTYSH_RIPNGD, debug_ripng_zebra_cmd_vtysh,
+ "debug ripng zebra",
+ "Debugging functions (see also 'undebug')\n"
+ "RIPng configuration\n"
+ "Debug option set for ripng and zebra communication\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community_cmd_vtysh,
+ "show ip bgp community (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_static_cmd_vtysh,
+ "no redistribute static",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Static routes\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community3_cmd_vtysh,
+ "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community_all_cmd_vtysh,
+ "show ipv6 bgp community",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_next_hop_prefix_list_val_cmd_vtysh,
+ "no match ip next-hop prefix-list WORD",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "IP information\n"
+ "Match next-hop address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv6_cmd_vtysh,
+ "redistribute (connected|kernel|ospf6|ripng|static)",
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPFv3)\n"
+ "Routing Information Protocol (RIPng)\n"
+ "Static routes\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_local_as_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Specify a local-as number\n")
+
+DEFSH (VTYSH_OSPFD, ospf_network_cmd_vtysh,
+ "ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)",
+ "OSPF interface commands\n"
+ "Network type\n"
+ "Specify OSPF broadcast multi-access network\n"
+ "Specify OSPF NBMA network\n"
+ "Specify OSPF point-to-multipoint network\n"
+ "Specify OSPF point-to-point network\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_set_metric_cmd_vtysh,
+ "no set metric",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "Metric value for destination routing protocol\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_filter_list_cmd_vtysh,
+ "show ip bgp filter-list WORD",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display routes conforming to the filter-list\n"
+ "Regular expression access list name\n")
+
+DEFSH (VTYSH_OSPFD, no_area_range_advertise_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "OSPF area range for route advertise (default)\n"
+ "area range prefix\n"
+ "advertise this range\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_seq_ge_cmd_vtysh,
+ "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128>",
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_timers_cmd_vtysh,
+ "no timers bgp",
+ "Negate a command or set its defaults\n"
+ "Adjust routing timers\n"
+ "BGP timers\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_enforce_first_as_cmd_vtysh,
+ "no bgp enforce-first-as",
+ "Negate a command or set its defaults\n"
+ "BGP information\n"
+ "Enforce the first AS for EBGP routes\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_authentication_mode_cmd_vtysh,
+ "no ip rip authentication mode",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Authentication control\n"
+ "Authentication mode\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_intra_cmd_vtysh,
+ "distance ospf intra-area <1-255>",
+ "Define an administrative distance\n"
+ "OSPF Administrative distance\n"
+ "Intra-area routes\n"
+ "Distance for intra-area routes\n")
+
+DEFSH (VTYSH_BGPD, match_ipv6_address_cmd_vtysh,
+ "match ipv6 address WORD",
+ "Match values from routing table\n"
+ "IPv6 information\n"
+ "Match IPv6 address of route\n"
+ "IPv6 access-list name\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_static_cmd_vtysh,
+ "redistribute static",
+ "Redistribute information from another routing protocol\n"
+ "Static routes\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_soft_in_cmd_vtysh,
+ "clear ip bgp * soft in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_ospf6_metric_routemap_cmd_vtysh,
+ "no redistribute ospf6 metric <0-16> route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "IPv6 Open Shortest Path First (OSPFv3)\n"
+ "Metric\n"
+ "Metric value\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_RIPD, no_router_rip_cmd_vtysh,
+ "no router rip",
+ "Negate a command or set its defaults\n"
+ "Enable a routing process\n"
+ "Routing Information Protocol (RIP)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_summary_name_cmd_vtysh,
+ "show ip prefix-list summary WORD",
+ "Show running system information\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Summary of prefix lists\n"
+ "Name of a prefix list\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_all_cmd_vtysh,
+ "clear bgp *",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all peers\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_strict_capability_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X) " "strict-capability-match",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Strict capability negotiation match\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community2_cmd_vtysh,
+ "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD, no_set_metric_val_cmd_vtysh,
+ "no set metric <0-4294967295>",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "Metric value for destination routing protocol\n"
+ "Metric value\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_in_cmd_vtysh,
+ "clear ip bgp * in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_out_cmd_vtysh,
+ "clear ip bgp peer-group WORD out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, no_network_area_cmd_vtysh,
+ "no network A.B.C.D/M area (A.B.C.D|<0-4294967295>)",
+ "Negate a command or set its defaults\n"
+ "Enable routing on an IP network\n"
+ "OSPF network prefix\n"
+ "Set the OSPF area ID\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n")
+
+DEFSH (VTYSH_OSPFD, neighbor_pollinterval_cmd_vtysh,
+ "neighbor A.B.C.D poll-interval <1-65535>",
+ "Specify neighbor router\n"
+ "Neighbor IP address\n"
+ "Dead Neighbor Polling interval\n"
+ "Seconds\n")
+
+DEFSH (VTYSH_BGPD, neighbor_activate_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "activate",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Enable the Address Family for this Neighbor\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_flap_route_map_cmd_vtysh,
+ "show ip bgp flap-statistics route-map WORD",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display flap statistics of routes\n"
+ "Display routes matching the route-map\n"
+ "A route-map to match on\n")
+
+DEFSH (VTYSH_OSPF6D|VTYSH_BGPD, no_match_ipv6_address_prefix_list_cmd_vtysh,
+ "no match ipv6 address prefix-list WORD",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "IPv6 information\n"
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ipv6_access_list_any_cmd_vtysh,
+ "no ipv6 access-list WORD (deny|permit) any",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any prefixi to match\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_nd_reachable_time_cmd_vtysh,
+ "ipv6 nd reachable-time MILLISECONDS",
+ "IP information\n"
+ "Neighbor discovery\n"
+ "Reachable time\n"
+ "Reachable time in milliseconds\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_ge_le_cmd_vtysh,
+ "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128> le <0-128>",
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_mask_cmd_vtysh,
+ "aggregate-address A.B.C.D A.B.C.D",
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_static_metric_cmd_vtysh,
+ "redistribute static metric <0-16>",
+ "Redistribute information from another routing protocol\n"
+ "Static routes\n"
+ "Metric\n"
+ "Metric value\n")
+
+DEFSH (VTYSH_OSPFD, interface_ip_ospf_authentication_cmd_vtysh,
+ "ip ospf authentication",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Enable authentication on this interface\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_authtype_authkey_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication|) "
+ "(authentication-key|) AUTH_KEY",
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Enable authentication on this virtual link\n" "dummy string \n"
+ "Authentication password (key)\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_OSPFD, no_ospf_compatible_rfc1583_cmd_vtysh,
+ "no compatible rfc1583",
+ "Negate a command or set its defaults\n"
+ "OSPF compatibility list\n"
+ "compatible with RFC 1583\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_ism_cmd_vtysh,
+ "debug ospf ism",
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n"
+ "OSPF Interface State Machine\n")
+
+DEFSH (VTYSH_RIPD, rip_split_horizon_cmd_vtysh,
+ "ip split-horizon",
+ "IP information\n"
+ "Perform split horizon\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community_list_exact_cmd_vtysh,
+ "show ipv6 mbgp community-list WORD exact-match",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "MBGP information\n"
+ "Display routes matching the community-list\n"
+ "community-list name\n"
+ "Exact match of the communities\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_routemap_cmd_vtysh,
+ "default-information originate always route-map WORD",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "Always advertise default route\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_soft_cmd_vtysh,
+ "clear bgp ipv6 external soft",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all external peers\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_sequence_number_cmd_vtysh,
+ "ip prefix-list sequence-number",
+ "IP information\n"
+ "Build a prefix list\n"
+ "Include/exclude sequence numbers in NVGEN\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_hello_interval_cmd_vtysh,
+ "no ip ospf hello-interval",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Time between HELLO packets\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_neighbor_received_routes_cmd_vtysh,
+ "show bgp neighbors (A.B.C.D|X:X::X:X) received-routes",
+ "Show running system information\n"
+ "BGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display the received routes from neighbor\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_cost_cmd_vtysh,
+ "no ip ospf cost",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Interface cost\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community4_cmd_vtysh,
+ "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_seq_ge_le_cmd_vtysh,
+ "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128> le <0-128>",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_group_soft_in_cmd_vtysh,
+ "clear bgp peer-group WORD soft in",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_as_set_cmd_vtysh,
+ "no aggregate-address A.B.C.D/M as-set",
+ "Negate a command or set its defaults\n"
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Generate AS set path information\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_soft_out_cmd_vtysh,
+ "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, no_set_local_pref_cmd_vtysh,
+ "no set local-preference",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "BGP local preference path attribute\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd_vtysh,
+ "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in prefix-filter",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig inbound update\n"
+ "Push out the existing ORF prefix-list\n")
+
+DEFSH (VTYSH_BGPD, old_no_ipv6_bgp_network_cmd_vtysh,
+ "no ipv6 bgp network X:X::X:X/M",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Specify a network to announce via BGP\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_nd_send_ra_cmd_vtysh,
+ "ipv6 nd send-ra",
+ "IP information\n"
+ "Neighbor discovery\n"
+ "Send Router Advertisement\n")
+
+DEFSH (VTYSH_BGPD, debug_bgp_normal_cmd_vtysh,
+ "debug bgp",
+ "Debugging functions (see also 'undebug')\n"
+ "BGP information\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_static_metric_routemap_cmd_vtysh,
+ "no redistribute static metric <0-16> route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Static routes\n"
+ "Metric\n"
+ "Metric value\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_ZEBRA, no_bandwidth_if_val_cmd_vtysh,
+ "no bandwidth <1-10000000>",
+ "Negate a command or set its defaults\n"
+ "Set bandwidth informational parameter\n"
+ "Bandwidth in kilobits\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_database_type_id_adv_router_dump_cmd_vtysh,
+ "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*) (A.B.C.D|*) (A.B.C.D|*) (dump|summary|)",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "LSA Database\n"
+ "Router-LSA\n"
+ "Network-LSA\n"
+ "AS-External-LSA\n"
+ "Intra-Area-Prefix-LSA\n"
+ "Inter-Area-Router-LSA\n"
+ "Inter-Area-Prefix-LSA\n"
+ "Link-LSA\n"
+ "All LS Type\n"
+ "Link State ID\n"
+ "All Link State ID\n"
+ "Advertising Router\n"
+ "All Advertising Router\n"
+ "Dump raw LSA data in Hex\n"
+ "show summary of LSA\n"
+ )
+
+DEFSH (VTYSH_BGPD, no_bgp_router_id_val_cmd_vtysh,
+ "no bgp router-id A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "BGP information\n"
+ "Override configured router identifier\n"
+ "Manually configured router identifier\n")
+
+DEFSH (VTYSH_RIPD, no_rip_offset_list_cmd_vtysh,
+ "no offset-list WORD (in|out) <0-16>",
+ "Negate a command or set its defaults\n"
+ "Modify RIP metric\n"
+ "Access-list name\n"
+ "For incoming updates\n"
+ "For outgoing updates\n"
+ "Metric value\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_neighbor_detail_all_cmd_vtysh,
+ "show ip ospf neighbor detail all",
+ "Show running system information\n"
+ "IP information\n"
+ "OSPF information\n"
+ "Neighbor list\n"
+ "detail of all neighbors\n"
+ "include down status neighbor\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_prefix_cmd_vtysh,
+ "show bgp ipv6 X:X::X:X/M",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "IPv6 prefix <network>/<length>\n")
+
+DEFSH (VTYSH_BGPD, no_dump_bgp_routes_cmd_vtysh,
+ "no dump bgp routes-mrt [PATH] [INTERVAL]",
+ "Negate a command or set its defaults\n"
+ "Dump packet\n"
+ "BGP packet dump\n"
+ "Dump whole BGP routing table\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_inter_external_cmd_vtysh,
+ "distance ospf inter-area <1-255> external <1-255>",
+ "Define an administrative distance\n"
+ "OSPF Administrative distance\n"
+ "Inter-area routes\n"
+ "Distance for inter-area routes\n"
+ "External routes\n"
+ "Distance for external routes\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_event_cmd_vtysh,
+ "debug ospf event",
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n"
+ "OSPF event information\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_retransmit_interval_cmd_vtysh,
+ "no ospf retransmit-interval",
+ "Negate a command or set its defaults\n"
+ "OSPF interface commands\n"
+ "Time between retransmitting lost link state advertisements\n")
+
+DEFSH (VTYSH_BGPD, set_community_none_cmd_vtysh,
+ "set community none",
+ "Set values in destination routing protocol\n"
+ "BGP community attribute\n"
+ "No community attribute\n")
+
+DEFSH (VTYSH_BGPD, debug_bgp_filter_cmd_vtysh,
+ "debug bgp filters",
+ "Debugging functions (see also 'undebug')\n"
+ "BGP information\n"
+ "BGP filters\n")
+
+DEFSH (VTYSH_OSPF6D, ospf6_routemap_set_forwarding_cmd_vtysh,
+ "set forwarding-address X:X::X:X",
+ "Set value\n"
+ "Forwarding Address\n"
+ "IPv6 Address\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_bestpath_compare_router_id_cmd_vtysh,
+ "no bgp bestpath compare-routerid",
+ "Negate a command or set its defaults\n"
+ "BGP specific commands\n"
+ "Change the default bestpath selection\n"
+ "Compare router-id for identical EBGP paths\n")
+
+DEFSH (VTYSH_RIPD, no_match_ip_address_val_cmd_vtysh,
+ "no match ip address WORD",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "IP information\n"
+ "Match address of route\n"
+ "IP access-list name\n")
+
+DEFSH (VTYSH_ZEBRA, bandwidth_if_cmd_vtysh,
+ "bandwidth <1-10000000>",
+ "Set bandwidth informational parameter\n"
+ "Bandwidth in kilobits\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_metric_cmd_vtysh,
+ "default-metric <0-16777214>",
+ "Set metric of redistributed routes\n"
+ "Default metric\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_allowas_in_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "allowas-in",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "allow local ASN appears in aspath attribute\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_default_metric_cmd_vtysh,
+ "no default-metric",
+ "Negate a command or set its defaults\n"
+ "Set a metric of redistribute routes\n"
+ "Default metric\n")
+
+DEFSH (VTYSH_OSPF6D, reload_cmd_vtysh,
+ "reload",
+ "Reloads\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_area_spf_tree_cmd_vtysh,
+ "show ipv6 ospf6 area A.B.C.D spf tree",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Area information\n"
+ "Area ID (as an IPv4 notation)\n"
+ "Shortest Path First caculation\n"
+ "Displays spf tree\n")
+
+DEFSH (VTYSH_BGPD, bgp_damp_unset2_cmd_vtysh,
+ "no bgp dampening <1-45> <1-20000> <1-20000> <1-255>",
+ "Negate a command or set its defaults\n"
+ "BGP Specific commands\n"
+ "Enable route-flap dampening\n"
+ "Half-life time for the penalty\n"
+ "Value to start reusing a route\n"
+ "Value to start suppressing a route\n"
+ "Maximum duration to suppress a stable route\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_authentication_key_addr_cmd_vtysh,
+ "ip ospf authentication-key AUTH_KEY A.B.C.D",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Authentication password (key)\n"
+ "The OSPF password (key)\n"
+ "Address of interface")
+
+DEFSH (VTYSH_RIPD, ip_rip_send_version_2_cmd_vtysh,
+ "ip rip send version 2 1",
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Advertisement transmission\n"
+ "Version control\n"
+ "RIP version 2\n"
+ "RIP version 1\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_route_ifname_cmd_vtysh,
+ "ipv6 route X:X::X:X/M X:X::X:X INTERFACE",
+ "IP information\n"
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community_all_cmd_vtysh,
+ "show bgp community",
+ "Show running system information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n")
+
+DEFSH (VTYSH_BGPD, neighbor_port_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X) " "port <0-65535>",
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Neighbor's BGP port\n"
+ "TCP port number\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_dampening_prefix_cmd_vtysh,
+ "clear ip bgp dampening A.B.C.D/M",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear route flap dampening information\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_soft_out_cmd_vtysh,
+ "clear bgp ipv6 * soft out",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all peers\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, show_ip_community_list_cmd_vtysh,
+ "show ip community-list",
+ "Show running system information\n"
+ "IP information\n"
+ "List community-list\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_mask_host_cmd_vtysh,
+ "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D host A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Source address\n"
+ "Source wildcard bits\n"
+ "A single destination host\n"
+ "Destination address\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_nd_ra_lifetime_cmd_vtysh,
+ "ipv6 nd ra-lifetime SECONDS",
+ "IP information\n"
+ "Neighbor discovery\n"
+ "Router lifetime\n"
+ "Router lifetime in seconds\n")
+
+DEFSH (VTYSH_BGPD, set_ecommunity_soo_cmd_vtysh,
+ "set extcommunity soo .ASN:nn_or_IP-address:nn",
+ "Set values in destination routing protocol\n"
+ "BGP extended community attribute\n"
+ "Site-of-Origin extended community\n"
+ "VPN extended community\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community4_exact_cmd_vtysh,
+ "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, no_set_originator_id_cmd_vtysh,
+ "no set originator-id",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "BGP originator ID attribute\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_prefix_cmd_vtysh,
+ "show ip prefix-list WORD A.B.C.D/M",
+ "Show running system information\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+
+DEFSH (VTYSH_RIPD, send_lifetime_infinite_day_month_cmd_vtysh,
+ "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> infinite",
+ "Set send lifetime of the key\n"
+ "Time to start\n"
+ "Day of th month to start\n"
+ "Month of the year to start\n"
+ "Year to start\n"
+ "Never expires")
+
+DEFSH (VTYSH_BGPD, no_neighbor_description_val_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "description .LINE",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Neighbor specific description\n"
+ "Up to 80 characters describing this neighbor\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_nd_suppress_ra_cmd_vtysh,
+ "ipv6 nd suppress-ra",
+ "IP information\n"
+ "Neighbor discovery\n"
+ "Suppress Router Advertisement\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_default_originate_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X) " "default-originate",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Originate default route to this neighbor\n")
+
+DEFSH (VTYSH_RIPD, no_rip_passive_interface_cmd_vtysh,
+ "no passive-interface IFNAME",
+ "Negate a command or set its defaults\n"
+ "Suppress routing updates on an interface\n"
+ "Interface name\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_remark_arg_cmd_vtysh,
+ "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP extended access list\n"
+ "IP standard access list (expanded range)\n"
+ "IP extended access list (expanded range)\n"
+ "IP zebra access-list\n"
+ "Access list entry comment\n"
+ "Comment up to 100 characters\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_as_set_cmd_vtysh,
+ "aggregate-address A.B.C.D/M as-set",
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Generate AS set path information\n")
+
+DEFSH (VTYSH_OSPF6D, interface_area_cmd_vtysh,
+ "interface IFNAME area A.B.C.D",
+ "Enable routing on an IPv6 interface\n"
+ "Interface name(e.g. ep0)\n"
+ "Set the OSPF6 area ID\n"
+ "OSPF6 area ID in IPv4 address notation\n"
+ )
+
+DEFSH (VTYSH_BGPD, no_neighbor_send_community_type_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community (both|extended|standard)",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Send Community attribute to this neighbor\n"
+ "Send Standard and Extended Community attributes\n"
+ "Send Extended Community attributes\n"
+ "Send Standard Community attributes\n")
+
+DEFSH (VTYSH_OSPFD, ospf_hello_interval_cmd_vtysh,
+ "ospf hello-interval <1-65535>",
+ "OSPF interface commands\n"
+ "Time between HELLO packets\n"
+ "Seconds\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_neighbor_all_cmd_vtysh,
+ "show ip ospf neighbor all",
+ "Show running system information\n"
+ "IP information\n"
+ "OSPF information\n"
+ "Neighbor list\n"
+ "include down status neighbor\n")
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_cost_cmd_vtysh,
+ "ipv6 ospf6 cost COST",
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Interface cost\n"
+ "<1-65535> Cost\n"
+ )
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_out_cmd_vtysh,
+ "clear ip bgp external out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all external peers\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD, match_interface_cmd_vtysh,
+ "match interface WORD",
+ "Match values from routing table\n"
+ "Match first hop interface of route\n"
+ "Interface name\n")
+
+DEFSH (VTYSH_ZEBRA, debug_zebra_kernel_cmd_vtysh,
+ "debug zebra kernel",
+ "Debugging functions (see also 'undebug')\n"
+ "Zebra configuration\n"
+ "Debug option set for zebra between kernel interface\n")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_cmd_vtysh,
+ "no aggregate-address A.B.C.D/M",
+ "Negate a command or set its defaults\n"
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n")
+
+DEFSH (VTYSH_ZEBRA, show_ipv6_forwarding_cmd_vtysh,
+ "show ipv6 forwarding",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "Forwarding status\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_nd_prefix_advertisement_cmd_vtysh,
+ "no ipv6 nd prefix-advertisement IPV6PREFIX",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Neighbor discovery\n"
+ "Prefix information\n"
+ "IPv6 prefix\n")
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_instance_cmd_vtysh,
+ "ipv6 ospf6 instance-id INSTANCE",
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Instance ID\n"
+ "<0-255> Instance ID\n"
+ )
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv4_rmap_metric_cmd_vtysh,
+ "redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>",
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPF)\n"
+ "Routing Information Protocol (RIP)\n"
+ "Static routes\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n"
+ "Metric for redistributed routes\n"
+ "Default metric\n")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_as_set_summary_cmd_vtysh,
+ "no aggregate-address A.B.C.D/M as-set summary-only",
+ "Negate a command or set its defaults\n"
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Generate AS set path information\n"
+ "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_capability_dynamic_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "capability dynamic",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Advertise capability to the peer\n"
+ "Advertise dynamic capability to this neighbor\n")
+
+DEFSH (VTYSH_OSPFD, ospf_retransmit_interval_cmd_vtysh,
+ "ospf retransmit-interval <3-65535>",
+ "OSPF interface commands\n"
+ "Time between retransmitting lost link state advertisements\n"
+ "Seconds\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_soft_in_cmd_vtysh,
+ "clear bgp ipv6 peer-group WORD soft in",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, bgp_confederation_identifier_cmd_vtysh,
+ "bgp confederation identifier <1-65535>",
+ "BGP specific commands\n"
+ "AS confederation parameters\n"
+ "AS number\n"
+ "Set routing domain confederation AS\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_vpnv4_soft_cmd_vtysh,
+ "clear ip bgp <1-65535> vpnv4 unicast soft",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Address family\n"
+ "Address Family Modifier\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_in_prefix_filter_cmd_vtysh,
+ "clear bgp ipv6 peer-group WORD in prefix-filter",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Soft reconfig inbound update\n"
+ "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged4_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med (as-path|next-hop)",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "Med attribute\n"
+ "As-path attribute\n"
+ "Nexthop attribute\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_nsm_cmd_vtysh,
+ "no debug ospf nsm",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n"
+ "OSPF Neighbor State Machine")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_ipv4_soft_out_cmd_vtysh,
+ "clear ip bgp view WORD * ipv4 (unicast|multicast) soft out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP view\n"
+ "view name\n"
+ "Clear all peers\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_ZEBRA, ip_route_mask_cmd_vtysh,
+ "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE)",
+ "IP information\n"
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n")
+
+DEFSH (VTYSH_BGPD, no_match_ipv6_address_cmd_vtysh,
+ "no match ipv6 address WORD",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "IPv6 information\n"
+ "Match IPv6 address of route\n"
+ "IPv6 access-list name\n")
+
+DEFSH (VTYSH_BGPD, bgp_damp_set_cmd_vtysh,
+ "bgp dampening <1-45> <1-20000> <1-20000> <1-255>",
+ "BGP Specific commands\n"
+ "Enable route-flap dampening\n"
+ "Half-life time for the penalty\n"
+ "Value to start reusing a route\n"
+ "Value to start suppressing a route\n"
+ "Maximum duration to suppress a stable route\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_timers_arg_cmd_vtysh,
+ "no timers bgp <0-65535> <0-65535>",
+ "Negate a command or set its defaults\n"
+ "Adjust routing timers\n"
+ "BGP timers\n"
+ "Keepalive interval\n"
+ "Holdtime\n")
+
+DEFSH (VTYSH_RIPD, send_lifetime_month_day_month_day_cmd_vtysh,
+ "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>",
+ "Set send lifetime of the key\n"
+ "Time to start\n"
+ "Month of the year to start\n"
+ "Day of th month to start\n"
+ "Year to start\n"
+ "Time to expire\n"
+ "Month of the year to expire\n"
+ "Day of th month to expire\n"
+ "Year to expire\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community4_exact_cmd_vtysh,
+ "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_neighborlist_cmd_vtysh,
+ "show ipv6 ospf6 (summary-list|request-list|retrans-list|dbdesc-list)",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Link State summary list\n"
+ "Link State request list\n"
+ "Link State retransmission list\n"
+ "Link State Description list (Used to retrans DbDesc)\n"
+ )
+
+DEFSH (VTYSH_BGPD, no_neighbor_maximum_prefix_val_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X) " "maximum-prefix <1-4294967295>",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Maximum number of prefix accept from this peer\n"
+ "maximum no. of prefix limit\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_intra_external_inter_cmd_vtysh,
+ "distance ospf intra-area <1-255> external <1-255> inter-area <1-255>",
+ "Define an administrative distance\n"
+ "OSPF Administrative distance\n"
+ "Intra-area routes\n"
+ "Distance for intra-area routes\n"
+ "External routes\n"
+ "Distance for external routes\n"
+ "Inter-area routes\n"
+ "Distance for inter-area routes\n")
+
+DEFSH (VTYSH_BGPD, no_set_atomic_aggregate_cmd_vtysh,
+ "no set atomic-aggregate",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "BGP atomic aggregate attribute\n" )
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_cmd_vtysh,
+ "clear bgp ipv6 external",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all external peers\n")
+
+DEFSH (VTYSH_OSPFD, network_area_cmd_vtysh,
+ "network A.B.C.D/M area (A.B.C.D|<0-4294967295>)",
+ "Enable routing on an IP network\n"
+ "OSPF network prefix\n"
+ "Set the OSPF area ID\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_authtype_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication|)",
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Enable authentication on this virtual link\n" "dummy string \n")
+
+DEFSH (VTYSH_BGPD, bgp_bestpath_aspath_ignore_cmd_vtysh,
+ "bgp bestpath as-path ignore",
+ "BGP specific commands\n"
+ "Change the default bestpath selection\n"
+ "AS-path attribute\n"
+ "Ignore as-path length in selecting a route\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_dampening_address_cmd_vtysh,
+ "clear ip bgp dampening A.B.C.D",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear route flap dampening information\n"
+ "Network to clear damping information\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_kernel_metric_cmd_vtysh,
+ "redistribute kernel metric <0-16>",
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Metric\n"
+ "Metric value\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_any_any_cmd_vtysh,
+ "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any any",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Any source host\n"
+ "Any destination host\n")
+
+DEFSH (VTYSH_BGPD, bgp_bestpath_med_cmd_vtysh,
+ "bgp bestpath med (confed|missing-as-worst)",
+ "BGP specific commands\n"
+ "Change the default bestpath selection\n"
+ "MED attribute\n"
+ "Compare MED among confederation paths\n"
+ "Treat missing MED as the least preferred one\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community_all_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) community",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the communities\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_in_prefix_filter_cmd_vtysh,
+ "clear ip bgp peer-group WORD in prefix-filter",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Soft reconfig inbound update\n"
+ "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_cmd_vtysh,
+ "show ipv6 mbgp",
+ "Show running system information\n"
+ "IP information\n"
+ "MBGP information\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_unsuppress_map_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "unsuppress-map WORD",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Route-map to selectively unsuppress suppressed routes\n"
+ "Name of route map\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_ospf6_routemap_cmd_vtysh,
+ "no redistribute ospf6 route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "IPv6 Open Shortest Path First (OSPFv3)\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_OSPFD, no_area_default_cost_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) default-cost <0-16777215>",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Set the summary-default cost of a NSSA or stub area\n"
+ "Stub's advertised default summary cost\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_summary_cmd_vtysh,
+ "show ip prefix-list summary",
+ "Show running system information\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Summary of prefix lists\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_database_type_id_cmd_vtysh,
+ "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*) (A.B.C.D|*|dump|summary)",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "LSA Database\n"
+ "Router-LSA\n"
+ "Network-LSA\n"
+ "AS-External-LSA\n"
+ "Intra-Area-Prefix-LSA\n"
+ "Inter-Area-Router-LSA\n"
+ "Inter-Area-Prefix-LSA\n"
+ "Link-LSA\n"
+ "All LS Type\n"
+ "Link State ID\n"
+ "All Link State ID\n"
+ "Dump raw LSA data in Hex\n"
+ "show summary of LSA\n"
+ )
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_summary_name_cmd_vtysh,
+ "show ipv6 prefix-list summary WORD",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Summary of prefix lists\n"
+ "Name of a prefix list\n")
+
+DEFSH (VTYSH_BGPD, set_aggregator_as_cmd_vtysh,
+ "set aggregator as <1-65535> A.B.C.D",
+ "Set values in destination routing protocol\n"
+ "BGP aggregator attribute\n"
+ "AS number of aggregator\n"
+ "AS number\n"
+ "IP address of aggregator\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, match_ip_address_prefix_list_cmd_vtysh,
+ "match ip address prefix-list WORD",
+ "Match values from routing table\n"
+ "IP information\n"
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_network_mask_backdoor_cmd_vtysh,
+ "no network A.B.C.D mask A.B.C.D backdoor",
+ "Negate a command or set its defaults\n"
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Network mask\n"
+ "Network mask\n"
+ "Specify a BGP backdoor route\n")
+
+DEFSH (VTYSH_BGPD, no_match_origin_val_cmd_vtysh,
+ "no match origin (egp|igp|incomplete)",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "BGP origin code\n"
+ "remote EGP\n"
+ "local IGP\n"
+ "unknown heritage\n")
+
+DEFSH (VTYSH_RIPD, rip_network_cmd_vtysh,
+ "network (A.B.C.D/M|WORD)",
+ "Enable routing on an IP network\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Interface name\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_cost_cmd_vtysh,
+ "ip ospf cost <1-65535>",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Interface cost\n"
+ "Cost")
+
+DEFSH (VTYSH_BGPD, ipv6_aggregate_address_cmd_vtysh,
+ "aggregate-address X:X::X:X/M",
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_as_cmd_vtysh,
+ "clear bgp <1-65535>",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_external_intra_inter_cmd_vtysh,
+ "distance ospf external <1-255> intra-area <1-255> inter-area <1-255>",
+ "Define an administrative distance\n"
+ "OSPF Administrative distance\n"
+ "External routes\n"
+ "Distance for external routes\n"
+ "Intra-area routes\n"
+ "Distance for intra-area routes\n"
+ "Inter-area routes\n"
+ "Distance for inter-area routes\n")
+
+DEFSH (VTYSH_OSPFD, ospf_cost_cmd_vtysh,
+ "ospf cost <1-65535>",
+ "OSPF interface commands\n"
+ "Interface cost\n"
+ "Cost")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_seq_cmd_vtysh,
+ "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) (X:X::X:X/M|any)",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Any prefix match. Same as \"::0/0 le 128\"\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_type_metric_routemap_cmd_vtysh,
+ "default-information originate metric-type (1|2) metric <0-16777214> route-map WORD",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "OSPF metric type for default routes\n"
+ "Set OSPF External Type 1 metrics\n"
+ "Set OSPF External Type 2 metrics\n"
+ "OSPF default metric\n"
+ "OSPF metric\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_OSPFD, area_range_subst_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M substitute A.B.C.D/M",
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "configure OSPF area range for route summarization\n"
+ "area range prefix\n"
+ "announce area range as another prefix\n"
+ "network prefix to be announced instead of range\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_prefix_cmd_vtysh,
+ "show ipv6 mbgp X:X::X:X/M",
+ "Show running system information\n"
+ "IP information\n"
+ "MBGP information\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_nd_other_config_flag_cmd_vtysh,
+ "no ipv6 nd other-config-flag",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Neighbor discovery\n"
+ "Other statefull configuration flag\n")
+
+DEFSH (VTYSH_RIPD, no_key_cmd_vtysh,
+ "no key <0-2147483647>",
+ "Negate a command or set its defaults\n"
+ "Delete a key\n"
+ "Key identifier number\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_ge_cmd_vtysh,
+ "no ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32>",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged4_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med (as-path|next-hop)",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "Med attribute\n"
+ "As-path attribute\n"
+ "Nexthop attribute\n")
+
+DEFSH (VTYSH_RIPNGD, no_debug_ripng_zebra_cmd_vtysh,
+ "no debug ripng zebra",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "RIPng configuration\n"
+ "Debug option set for ripng and zebra communication\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_weight_val_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "weight <0-65535>",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Set default weight for routes from this neighbor\n"
+ "default weight\n")
+
+DEFSH (VTYSH_RIPD, no_rip_default_information_originate_cmd_vtysh,
+ "no default-information originate",
+ "Negate a command or set its defaults\n"
+ "Control distribution of default route\n"
+ "Distribute a default route\n")
+
+DEFSH (VTYSH_BGPD, match_community_exact_cmd_vtysh,
+ "match community (<1-99>|<100-199>|WORD) exact-match",
+ "Match values from routing table\n"
+ "Match BGP community list\n"
+ "Community-list number (standard)\n"
+ "Community-list number (expanded)\n"
+ "Community-list name\n"
+ "Do exact matching of communities\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_as_in_cmd_vtysh,
+ "clear bgp <1-65535> in",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_any_host_cmd_vtysh,
+ "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any host A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Any source host\n"
+ "A single destination host\n"
+ "Destination address\n")
+
+DEFSH (VTYSH_BGPD, ipv6_bgp_network_cmd_vtysh,
+ "network X:X::X:X/M",
+ "Specify a network to announce via BGP\n"
+ "IPv6 prefix <network>/<length>\n")
+
+DEFSH (VTYSH_ZEBRA, ip_irdp_preference_cmd_vtysh,
+
+ "ip irdp preference <0-2147483647>",
+ "IP information\n"
+ "ICMP Router discovery on this interface\n"
+ "Set default preference level for this interface\n"
+ "Preference level\n")
+
+DEFSH (VTYSH_BGPD, bgp_fast_external_failover_cmd_vtysh,
+ "bgp fast-external-failover",
+ "BGP information\n"
+ "Immediately reset session if a link to a directly connected external peer goes down\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_prefix_list_cmd_vtysh,
+ "show ipv6 mbgp prefix-list WORD",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "MBGP information\n"
+ "Display routes matching the prefix-list\n"
+ "IPv6 prefix-list name\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_mask_cmd_vtysh,
+ "network A.B.C.D mask A.B.C.D",
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Network mask\n"
+ "Network mask\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_authtype_md5_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication|) "
+ "(message-digest-key|) <1-255> md5 KEY",
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Enable authentication on this virtual link\n" "dummy string \n"
+ "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_BGPD, show_bgp_cmd_vtysh,
+ "show bgp",
+ "Show running system information\n"
+ "BGP information\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_mask_backdoor_cmd_vtysh,
+ "network A.B.C.D mask A.B.C.D backdoor",
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Network mask\n"
+ "Network mask\n"
+ "Specify a BGP backdoor route\n")
+
+DEFSH (VTYSH_RIPD, ip_rip_authentication_string_cmd_vtysh,
+ "ip rip authentication string LINE",
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Authentication control\n"
+ "Authentication string\n"
+ "Authentication string\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_interface_cmd_vtysh,
+ "show ipv6 ospf6 interface",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Interface infomation\n"
+ )
+
+DEFSH (VTYSH_ZEBRA, no_ip_route_pref_cmd_vtysh,
+ "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) <1-255>",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Distance value for this route\n")
+
+DEFSH (VTYSH_BGPD, no_set_community_none_cmd_vtysh,
+ "no set community none",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "BGP community attribute\n"
+ "No community attribute\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_instance_summary_cmd_vtysh,
+ "show bgp view WORD summary",
+ "Show running system information\n"
+ "BGP information\n"
+ "BGP view\n"
+ "View name\n"
+ "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_all_cmd_vtysh,
+ "no ip extcommunity-list (<1-99>|<100-199>)",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Add a extended community list entry\n"
+ "Extended Community list number (standard)\n"
+ "Extended Community list number (expanded)\n")
+
+DEFSH (VTYSH_BGPD, ipv6_bgp_network_route_map_cmd_vtysh,
+ "network X:X::X:X/M route-map WORD",
+ "Specify a network to announce via BGP\n"
+ "IPv6 prefix <network>/<length>\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_connected_metric_cmd_vtysh,
+ "redistribute connected metric <0-16>",
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Metric\n"
+ "Metric value\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_ge_le_cmd_vtysh,
+ "no ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32> le <0-32>",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_authentication_key_cmd_vtysh,
+ "ip ospf authentication-key AUTH_KEY",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Authentication password (key)\n"
+ "The OSPF password (key)")
+
+DEFSH (VTYSH_ZEBRA, ipv6_nd_other_config_flag_cmd_vtysh,
+ "ipv6 nd other-config-flag",
+ "IP information\n"
+ "Neighbor discovery\n"
+ "Other statefull configuration flag\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_neighbor_advertised_route_cmd_vtysh,
+ "show bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+ "Show running system information\n"
+ "BGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display the routes advertised to a BGP neighbor\n")
+
+DEFSH (VTYSH_OSPFD, interface_ip_ospf_authentication_addr_cmd_vtysh,
+ "ip ospf authentication A.B.C.D",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Enable authentication on this interface\n"
+ "Address of interface")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, clear_ip_prefix_list_name_prefix_cmd_vtysh,
+ "clear ip prefix-list WORD A.B.C.D/M",
+ "Reset functions\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, bgp_client_to_client_reflection_cmd_vtysh,
+ "bgp client-to-client reflection",
+ "BGP specific commands\n"
+ "Configure client to client route reflection\n"
+ "reflection of routes allowed\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_external_soft_in_cmd_vtysh,
+ "clear bgp external soft in",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all external peers\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD, no_rip_redistribute_type_routemap_cmd_vtysh,
+ "no redistribute (kernel|connected|static|ospf|bgp) route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Open Shortest Path First (OSPF)\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_mask_summary_as_set_cmd_vtysh,
+ "no aggregate-address A.B.C.D A.B.C.D summary-only as-set",
+ "Negate a command or set its defaults\n"
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n"
+ "Filter more specific routes from updates\n"
+ "Generate AS set path information\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_tags_cmd_vtysh,
+ "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn tags",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display VPNv4 NLRI specific information\n"
+ "Display information for a route distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "Display BGP tags for prefixes\n")
+
+DEFSH (VTYSH_BGPD, no_set_ecommunity_soo_cmd_vtysh,
+ "no set extcommunity soo",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "BGP extended community attribute\n"
+ "Site-of-Origin extended community\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_exact_cmd_vtysh,
+ "access-list WORD (deny|permit) A.B.C.D/M exact-match",
+ "Add an access list entry\n"
+ "IP zebra access-list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 10.0.0.0/8\n"
+ "Exact match of the prefixes\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_route_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) A.B.C.D",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Network in the BGP routing table to display\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_cmd_vtysh,
+ "clear bgp ipv6 *",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all peers\n")
+
+DEFSH (VTYSH_BGPD, bgp_confederation_peers_cmd_vtysh,
+ "bgp confederation peers .<1-65535>",
+ "BGP specific commands\n"
+ "AS confederation parameters\n"
+ "Peer ASs in BGP confederation\n"
+ "AS number\n")
+
+DEFSH (VTYSH_BGPD, no_set_ecommunity_soo_val_cmd_vtysh,
+ "no set extcommunity soo .ASN:nn_or_IP-address:nn",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "BGP extended community attribute\n"
+ "Site-of-Origin extended community\n"
+ "VPN extended community\n")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_metric_routemap_cmd_vtysh,
+ "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Routing Information Protocol (RIP)\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Metric for redistributed routes\n"
+ "OSPF default metric\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_cost_addr_cmd_vtysh,
+ "ip ospf cost <1-65535> A.B.C.D",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Interface cost\n"
+ "Cost\n"
+ "Address of interface")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_soft_in_cmd_vtysh,
+ "clear bgp ipv6 external soft in",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all external peers\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD, show_ip_rip_cmd_vtysh,
+ "show ip rip",
+ "Show running system information\n"
+ "IP information\n"
+ "Show RIP routes\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_ipv4_in_cmd_vtysh,
+ "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD, show_debugging_rip_cmd_vtysh,
+ "show debugging rip",
+ "Show running system information\n"
+ "Debugging functions (see also 'undebug')\n"
+ "RIP information\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_network_mask_route_map_cmd_vtysh,
+ "no network A.B.C.D mask A.B.C.D route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Network mask\n"
+ "Network mask\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+
+DEFSH (VTYSH_BGPD, set_local_pref_cmd_vtysh,
+ "set local-preference <0-4294967295>",
+ "Set values in destination routing protocol\n"
+ "BGP local preference path attribute\n"
+ "Preference value\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_activate_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "activate",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Enable the Address Family for this Neighbor\n")
+
+DEFSH (VTYSH_RIPD, no_rip_redistribute_type_metric_cmd_vtysh,
+ "no redistribute (kernel|connected|static|ospf|bgp) metric <0-16>",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Open Shortest Path First (OSPF)\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Metric\n"
+ "Metric value\n")
+
+DEFSH (VTYSH_ZEBRA, no_debug_zebra_kernel_cmd_vtysh,
+ "no debug zebra kernel",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "Zebra configuration\n"
+ "Debug option set for zebra between kernel interface\n")
+
+DEFSH (VTYSH_BGPD, no_set_ipv6_nexthop_global_val_cmd_vtysh,
+ "no set ipv6 next-hop global X:X::X:X",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "IPv6 information\n"
+ "IPv6 next-hop address\n"
+ "IPv6 global address\n"
+ "IPv6 address of next hop\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_soft_in_cmd_vtysh,
+ "clear bgp ipv6 * soft in",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all peers\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community4_cmd_vtysh,
+ "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_neighbors_peer_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X)",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n")
+
+DEFSH (VTYSH_RIPD, no_rip_split_horizon_cmd_vtysh,
+ "no ip split-horizon",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Perform split horizon\n")
+
+DEFSH (VTYSH_BGPD, neighbor_local_as_no_prepend_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as <1-65535> no-prepend",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Specify a local-as number\n"
+ "AS number used as local AS\n"
+ "Do not prepend local-as to updates from ebgp peers\n")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_type_routemap_cmd_vtysh,
+ "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Routing Information Protocol (RIP)\n"
+ "Border Gateway Protocol (BGP)\n"
+ "OSPF exterior metric type for redistributed routes\n"
+ "Set OSPF External Type 1 metrics\n"
+ "Set OSPF External Type 2 metrics\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_mask_as_set_cmd_vtysh,
+ "no aggregate-address A.B.C.D A.B.C.D as-set",
+ "Negate a command or set its defaults\n"
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n"
+ "Generate AS set path information\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_external_inter_cmd_vtysh,
+ "distance ospf external <1-255> inter-area <1-255>",
+ "Define an administrative distance\n"
+ "OSPF Administrative distance\n"
+ "External routes\n"
+ "Distance for external routes\n"
+ "Inter-area routes\n"
+ "Distance for inter-area routes\n")
+
+DEFSH (VTYSH_RIPD, accept_lifetime_month_day_month_day_cmd_vtysh,
+ "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>",
+ "Set accept lifetime of the key\n"
+ "Time to start\n"
+ "Month of the year to start\n"
+ "Day of th month to start\n"
+ "Year to start\n"
+ "Time to expire\n"
+ "Month of the year to expire\n"
+ "Day of th month to expire\n"
+ "Year to expire\n")
+
+DEFSH (VTYSH_BGPD, no_set_originator_id_val_cmd_vtysh,
+ "no set originator-id A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "BGP originator ID attribute\n"
+ "IP address of originator\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_neighbor_routes_cmd_vtysh,
+ "show ip bgp vpnv4 all neighbors A.B.C.D routes",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display VPNv4 NLRI specific information\n"
+ "Display information about all VPNv4 NLRIs\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Display routes learned from neighbor\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_bgp_metric_routemap_cmd_vtysh,
+ "no redistribute bgp metric <0-16> route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Metric\n"
+ "Metric value\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_routemap_cmd_vtysh,
+ "default-information originate route-map WORD",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community_list_exact_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) community-list WORD exact-match",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the community-list\n"
+ "community-list name\n"
+ "Exact match of the communities\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_remark_cmd_vtysh,
+ "access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE",
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP extended access list\n"
+ "IP standard access list (expanded range)\n"
+ "IP extended access list (expanded range)\n"
+ "IP zebra access-list\n"
+ "Access list entry comment\n"
+ "Comment up to 100 characters\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_prefix_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_router_id_cmd_vtysh,
+ "no bgp router-id",
+ "Negate a command or set its defaults\n"
+ "BGP information\n"
+ "Override configured router identifier\n")
+
+DEFSH (VTYSH_BGPD, dump_bgp_all_interval_cmd_vtysh,
+ "dump bgp all PATH INTERVAL",
+ "Dump packet\n"
+ "BGP packet dump\n"
+ "Dump all BGP packets\n"
+ "Output filename\n"
+ "Interval of output\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_filter_list_cmd_vtysh,
+ "show ipv6 mbgp filter-list WORD",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "MBGP information\n"
+ "Display routes conforming to the filter-list\n"
+ "Regular expression access list name\n")
+
+DEFSH (VTYSH_BGPD, dump_bgp_updates_cmd_vtysh,
+ "dump bgp updates PATH",
+ "Dump packet\n"
+ "BGP packet dump\n"
+ "Dump BGP updates only\n"
+ "Output filename\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_network_backdoor_cmd_vtysh,
+ "no network A.B.C.D/M backdoor",
+ "Negate a command or set its defaults\n"
+ "Specify a network to announce via BGP\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Specify a BGP backdoor route\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_in_cmd_vtysh,
+ "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_soft_in_cmd_vtysh,
+ "clear bgp (A.B.C.D|X:X::X:X) soft in",
+ "Reset functions\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "BGP IPv6 neighbor to clear\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPF6D, redistribute_ospf6_cmd_vtysh,
+ "redistribute ospf6",
+ "Redistribute control\n"
+ "OSPF6 route\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_seq_ge_le_cmd_vtysh,
+ "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_dead_interval_cmd_vtysh,
+ "no ip ospf dead-interval",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Interval after which a neighbor is declared dead\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_le_cmd_vtysh,
+ "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>",
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+
+DEFSH (VTYSH_OSPF6D, router_id_cmd_vtysh,
+ "router-id ROUTER_ID",
+ "Configure ospf Router-ID.\n"
+ "specify by IPv4 address notation(e.g. 0.0.0.0)\n")
+
+DEFSH (VTYSH_BGPD, bgp_bestpath_med2_cmd_vtysh,
+ "bgp bestpath med confed missing-as-worst",
+ "BGP specific commands\n"
+ "Change the default bestpath selection\n"
+ "MED attribute\n"
+ "Compare MED among confederation paths\n"
+ "Treat missing MED as the least preferred one\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_in_cmd_vtysh,
+ "clear bgp ipv6 * in",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all peers\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community3_cmd_vtysh,
+ "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, ip_extcommunity_list_standard2_cmd_vtysh,
+ "ip extcommunity-list <1-99> (deny|permit)",
+ "IP information\n"
+ "Add a extended community list entry\n"
+ "Extended Community list number (standard)\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n")
+
+DEFSH (VTYSH_OSPFD, passive_interface_addr_cmd_vtysh,
+ "passive-interface IFNAME A.B.C.D",
+ "Suppress routing updates on an interface\n"
+ "Interface's name\n")
+
+DEFSH (VTYSH_BGPD, neighbor_ebgp_multihop_ttl_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "ebgp-multihop <1-255>",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Allow EBGP neighbors not on directly connected networks\n"
+ "maximum hop count\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_flap_prefix_longer_cmd_vtysh,
+ "show ip bgp flap-statistics A.B.C.D/M longer-prefixes",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display flap statistics of routes\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Display route and more specific routes\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_peer_group_cmd_vtysh,
+ "no neighbor WORD peer-group",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor tag\n"
+ "Configure peer-group\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_route_ifname_cmd_vtysh,
+ "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n")
+
+DEFSH (VTYSH_RIPD, rip_distance_source_access_list_cmd_vtysh,
+ "distance <1-255> A.B.C.D/M WORD",
+ "Administrative distance\n"
+ "Distance value\n"
+ "IP source prefix\n"
+ "Access list name\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv6_rmap_metric_cmd_vtysh,
+ "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPFv3)\n"
+ "Routing Information Protocol (RIPng)\n"
+ "Static routes\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n"
+ "Metric for redistributed routes\n"
+ "Default metric\n")
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_advertise_prefix_list_cmd_vtysh,
+ "ipv6 ospf6 advertise prefix-list WORD",
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Advertising options\n"
+ "Filter prefix using prefix-list\n"
+ "Prefix list name\n"
+ )
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_transmitdelay_cmd_vtysh,
+ "ipv6 ospf6 transmit-delay TRANSMITDELAY",
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Link state transmit delay\n"
+ "<1-65535> Seconds\n"
+ )
+
+DEFSH (VTYSH_BGPD, neighbor_maximum_prefix_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X) " "maximum-prefix <1-4294967295>",
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Maximum number of prefix accept from this peer\n"
+ "maximum no. of prefix limit\n")
+
+DEFSH (VTYSH_BGPD, vpnv4_network_cmd_vtysh,
+ "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD",
+ "Specify a network to announce via BGP\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Specify Route Distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "BGP tag\n"
+ "tag value\n")
+
+DEFSH (VTYSH_ZEBRA, show_ipv6_route_addr_cmd_vtysh,
+ "show ipv6 route X:X::X:X",
+ "Show running system information\n"
+ "IP information\n"
+ "IPv6 routing table\n"
+ "IPv6 Address\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_neighbors_peer_cmd_vtysh,
+ "show ip bgp neighbors (A.B.C.D|X:X::X:X)",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_nsm_cmd_vtysh,
+ "debug ospf nsm",
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n"
+ "OSPF Neighbor State Machine\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_message_digest_key_cmd_vtysh,
+ "ip ospf message-digest-key <1-255> md5 KEY",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Message digest authentication password (key)\n"
+ "Key ID\n"
+ "Use MD5 algorithm\n"
+ "The OSPF password (key)")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_bgp_metric_routemap_cmd_vtysh,
+ "redistribute bgp metric <0-16> route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Metric\n"
+ "Metric value\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, bgp_default_local_preference_cmd_vtysh,
+ "bgp default local-preference <0-4294967295>",
+ "BGP specific commands\n"
+ "Configure BGP defaults\n"
+ "local preference (higher=more preferred)\n"
+ "Configure default local preference value\n")
+
+DEFSH (VTYSH_RIPD, rip_distance_source_cmd_vtysh,
+ "distance <1-255> A.B.C.D/M",
+ "Administrative distance\n"
+ "Distance value\n"
+ "IP source prefix\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_seq_le_cmd_vtysh,
+ "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128>",
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_regexp_cmd_vtysh,
+ "show bgp regexp .LINE",
+ "Show running system information\n"
+ "BGP information\n"
+ "Display routes matching the AS path regular expression\n"
+ "A regular-expression to match the BGP AS paths\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_regexp_cmd_vtysh,
+ "show ipv6 bgp regexp .LINE",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display routes matching the AS path regular expression\n"
+ "A regular-expression to match the BGP AS paths\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_priority_cmd_vtysh,
+ "no ip ospf priority",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Router priority\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_set_ip_nexthop_cmd_vtysh,
+ "no set ip next-hop",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "IP information\n"
+ "Next hop address\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_dead_interval_addr_cmd_vtysh,
+ "ip ospf dead-interval <1-65535> A.B.C.D",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Interval after which a neighbor is declared dead\n"
+ "Seconds\n"
+ "Address of interface")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_name_seq_cmd_vtysh,
+ "show ipv6 prefix-list WORD seq <1-4294967295>",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ipv6_access_list_cmd_vtysh,
+ "ipv6 access-list WORD (deny|permit) X:X::X:X/M",
+ "IPv6 information\n"
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 3ffe:506::/32\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_cmd_vtysh,
+ "clear ip bgp external",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all external peers\n")
+
+DEFSH (VTYSH_OSPFD, no_area_authentication_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) authentication",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Enable authentication\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_seq_ge_le_cmd_vtysh,
+ "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>",
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+
+DEFSH (VTYSH_BGPD, no_set_aspath_prepend_val_cmd_vtysh,
+ "no set as-path prepend .<1-65535>",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "Prepend string for a BGP AS-path attribute\n"
+ "Prepend to the as-path\n"
+ "AS number\n")
+
+DEFSH (VTYSH_OSPFD, area_stub_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) stub",
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Configure OSPF area as stub\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_database_cmd_vtysh,
+ "show ipv6 ospf6 database",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "LSA Database\n"
+ )
+
+DEFSH (VTYSH_RIPD, no_rip_default_metric_val_cmd_vtysh,
+ "no default-metric <1-16>",
+ "Negate a command or set its defaults\n"
+ "Set a metric of redistribute routes\n"
+ "Default metric\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_prefix_cmd_vtysh,
+ "show ip bgp A.B.C.D/M",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_external_in_cmd_vtysh,
+ "clear bgp external in",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all external peers\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ip_access_list_name_cmd_vtysh,
+ "show ip access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)",
+ "Show running system information\n"
+ "IP information\n"
+ "List IP access lists\n"
+ "IP standard access list\n"
+ "IP extended access list\n"
+ "IP standard access list (expanded range)\n"
+ "IP extended access list (expanded range)\n"
+ "IP zebra access-list\n")
+
+DEFSH (VTYSH_BGPD, set_community_delete_cmd_vtysh,
+ "set comm-list (<1-99>|<100-199>|WORD) delete",
+ "Set values in destination routing protocol\n"
+ "set BGP community list (for deletion)\n"
+ "Community-list number (standard)\n"
+ "Communitly-list number (expanded)\n"
+ "Community-list name\n"
+ "Delete matching communities\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community3_exact_cmd_vtysh,
+ "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, no_ip_community_list_all_cmd_vtysh,
+ "no ip community-list (WORD|<1-99>|<100-199>)",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Add a community list entry\n"
+ "Community list name\n"
+ "Community list number (standard)\n"
+ "Community list number (expanded)\n")
+
+DEFSH (VTYSH_RIPD, rip_redistribute_rip_cmd_vtysh,
+ "redistribute rip",
+ "Redistribute information from another routing protocol\n"
+ "Routing Information Protocol (RIP)\n")
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_hellointerval_cmd_vtysh,
+ "ipv6 ospf6 hello-interval HELLO_INTERVAL",
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Time between HELLO packets\n"
+ "<1-65535> Seconds\n"
+ )
+
+DEFSH (VTYSH_RIPNGD, no_ripng_passive_interface_cmd_vtysh,
+ "no passive-interface IFNAME",
+ "Negate a command or set its defaults\n"
+ "Suppress routing updates on an interface\n"
+ "Interface name\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_network_mask_natural_backdoor_cmd_vtysh,
+ "no network A.B.C.D backdoor",
+ "Negate a command or set its defaults\n"
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Specify a BGP backdoor route\n")
+
+DEFSH (VTYSH_ZEBRA, multicast_cmd_vtysh,
+ "multicast",
+ "Set multicast flag to interface\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_external_inter_intra_cmd_vtysh,
+ "distance ospf external <1-255> inter-area <1-255> intra-area <1-255>",
+ "Define an administrative distance\n"
+ "OSPF Administrative distance\n"
+ "External routes\n"
+ "Distance for external routes\n"
+ "Inter-area routes\n"
+ "Distance for inter-area routes\n"
+ "Intra-area routes\n"
+ "Distance for intra-area routes\n")
+
+DEFSH (VTYSH_RIPD, rip_redistribute_type_cmd_vtysh,
+ "redistribute (kernel|connected|static|ospf|bgp)",
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Open Shortest Path First (OSPF)\n"
+ "Border Gateway Protocol (BGP)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_host_host_cmd_vtysh,
+ "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D host A.B.C.D",
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "A single source host\n"
+ "Source address\n"
+ "A single destination host\n"
+ "Destination address\n")
+
+DEFSH (VTYSH_BGPD, bgp_config_type_cmd_vtysh,
+ "bgp config-type (cisco|zebra)",
+ "BGP information\n"
+ "Configuration type\n"
+ "cisco\n"
+ "zebra\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community2_exact_cmd_vtysh,
+ "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_view_cmd_vtysh,
+ "show ip bgp view WORD",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP view\n"
+ "BGP view name\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_dampening_address_mask_cmd_vtysh,
+ "clear ip bgp dampening A.B.C.D A.B.C.D",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear route flap dampening information\n"
+ "Network to clear damping information\n"
+ "Network mask\n")
+
+DEFSH (VTYSH_OSPFD, area_authentication_message_digest_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) authentication message-digest",
+ "OSPF area parameters\n"
+ "Enable authentication\n"
+ "Use message-digest authentication\n")
+
+DEFSH (VTYSH_OSPFD, no_area_range_advertise_cost_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise cost <0-16777215>",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Configure OSPF area range for route summarization\n"
+ "area range prefix\n"
+ "advertise this range\n"
+ "User specified metric for this range\n"
+ "Advertised metric for this range\n")
+
+DEFSH (VTYSH_RIPD, no_rip_neighbor_cmd_vtysh,
+ "no neighbor A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Specify a neighbor router\n"
+ "Neighbor address\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_connected_metric_routemap_cmd_vtysh,
+ "redistribute connected metric <0-16> route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Metric\n"
+ "Metric value\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_deterministic_med_cmd_vtysh,
+ "no bgp deterministic-med",
+ "Negate a command or set its defaults\n"
+ "BGP specific commands\n"
+ "Pick the best-MED path among paths advertised from the neighboring AS\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community4_exact_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, no_set_aggregator_as_cmd_vtysh,
+ "no set aggregator as",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "BGP aggregator attribute\n"
+ "AS number of aggregator\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_soft_cmd_vtysh,
+ "clear bgp ipv6 * soft",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all peers\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_param1_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>",
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv4_cmd_vtysh,
+ "no redistribute (connected|kernel|ospf|rip|static)",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPF)\n"
+ "Routing Information Protocol (RIP)\n"
+ "Static routes\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_ipv4_soft_in_cmd_vtysh,
+ "clear ip bgp external ipv4 (unicast|multicast) soft in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all external peers\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_cmd_vtysh,
+ "ipv6 prefix-list WORD (deny|permit) (X:X::X:X/M|any)",
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Any prefix match. Same as \"::0/0 le 128\"\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_vpnv4_soft_cmd_vtysh,
+ "clear ip bgp * vpnv4 unicast soft",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Address family\n"
+ "Address Family Modifier\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, debug_bgp_keepalive_cmd_vtysh,
+ "debug bgp keepalives",
+ "Debugging functions (see also 'undebug')\n"
+ "BGP information\n"
+ "BGP keepalives\n")
+
+DEFSH (VTYSH_BGPD, no_router_bgp_cmd_vtysh,
+ "no router bgp <1-65535>",
+ "Negate a command or set its defaults\n"
+ "Enable a routing process\n"
+ "BGP information\n"
+ "AS number\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_route_ifname_pref_cmd_vtysh,
+ "ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>",
+ "IP information\n"
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Distance value for this prefix\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_transmit_delay_addr_cmd_vtysh,
+ "no ip ospf transmit-delay A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Link state transmit delay\n"
+ "Address of interface")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_ge_cmd_vtysh,
+ "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128>",
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_cmd_vtysh,
+ "distance <1-255>",
+ "Define an administrative distance\n"
+ "OSPF Administrative distance\n")
+
+DEFSH (VTYSH_OSPFD, area_range_advertise_cost_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise cost <0-16777215>",
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Configure OSPF area range for route summarization\n"
+ "area range prefix\n"
+ "advertise this range\n"
+ "User specified metric for this range\n"
+ "Advertised metric for this range\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_remark_cmd_vtysh,
+ "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP extended access list\n"
+ "IP standard access list (expanded range)\n"
+ "IP extended access list (expanded range)\n"
+ "IP zebra access-list\n"
+ "Access list entry comment\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_connected_routemap_cmd_vtysh,
+ "no redistribute connected route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged5_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path next-hop med",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "As-path attribute\n"
+ "Nexthop attribute\n"
+ "Med attribute\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_distance_ospf_cmd_vtysh,
+ "no distance ospf",
+ "Negate a command or set its defaults\n"
+ "Define an administrative distance\n"
+ "OSPF Administrative distance\n"
+ "OSPF Distance\n")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_metric_cmd_vtysh,
+ "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214>",
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Routing Information Protocol (RIP)\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Metric for redistributed routes\n"
+ "OSPF default metric\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_neighbor_cmd_vtysh,
+ "show ipv6 ospf6 neighbor",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Neighbor list\n"
+ )
+
+DEFSH (VTYSH_RIPD, key_string_cmd_vtysh,
+ "key-string LINE",
+ "Set key string\n"
+ "The key\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_enforce_multihop_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "enforce-multihop",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Enforce EBGP neighbors perform multihop\n")
+
+DEFSH (VTYSH_RIPNGD, debug_ripng_events_cmd_vtysh,
+ "debug ripng events",
+ "Debugging functions (see also 'undebug')\n"
+ "RIPng configuration\n"
+ "Debug option set for ripng events\n")
+
+DEFSH (VTYSH_OSPF6D, no_redistribute_ospf6_cmd_vtysh,
+ "no redistribute ospf6",
+ "Negate a command or set its defaults\n"
+ "Redistribute control\n"
+ "OSPF6 route\n")
+
+DEFSH (VTYSH_BGPD, neighbor_description_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "description .LINE",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Neighbor specific description\n"
+ "Up to 80 characters describing this neighbor\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_route_pref_cmd_vtysh,
+ "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Distance value for this prefix\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_packet_send_recv_cmd_vtysh,
+ "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv|detail)",
+ "Debugging functions\n"
+ "OSPF information\n"
+ "OSPF packets\n"
+ "OSPF Hello\n"
+ "OSPF Database Description\n"
+ "OSPF Link State Request\n"
+ "OSPF Link State Update\n"
+ "OSPF Link State Acknowledgment\n"
+ "OSPF all packets\n"
+ "Packet sent\n"
+ "Packet received\n"
+ "Detail information\n")
+
+DEFSH (VTYSH_OSPFD, area_range_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M",
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Configure OSPF area range for route summarization\n"
+ "area range prefix\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_seq_le_ge_cmd_vtysh,
+ "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128> ge <0-128>",
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_ipv4_in_prefix_filter_cmd_vtysh,
+ "clear ip bgp external ipv4 (unicast|multicast) in prefix-filter",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all external peers\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig inbound update\n"
+ "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_any_mask_cmd_vtysh,
+ "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any A.B.C.D A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Any source host\n"
+ "Destination address\n"
+ "Destination Wildcard bits\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_authentication_key_chain2_cmd_vtysh,
+ "no ip rip authentication key-chain LINE",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Authentication control\n"
+ "Authentication key-chain\n"
+ "name of key-chain\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_cidr_only_cmd_vtysh,
+ "show ip bgp cidr-only",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display only routes with non-natural netmasks\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_description_cmd_vtysh,
+ "no ipv6 prefix-list WORD description",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Prefix-list specific description\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_send_version_num_cmd_vtysh,
+ "no ip rip send version (1|2)",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Advertisement transmission\n"
+ "Version control\n"
+ "Version 1\n"
+ "Version 2\n")
+
+DEFSH (VTYSH_OSPFD, no_refresh_timer_cmd_vtysh,
+ "no refresh timer",
+ "Adjust refresh parameters\n"
+ "Unset refresh timer\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_ospf6_routemap_cmd_vtysh,
+ "redistribute ospf6 route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "IPv6 Open Shortest Path First (OSPFv3)\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_ZEBRA, no_shutdown_if_cmd_vtysh,
+ "no shutdown",
+ "Negate a command or set its defaults\n"
+ "Shutdown the selected interface\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_soft_in_cmd_vtysh,
+ "clear ip bgp view WORD * soft in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP view\n"
+ "view name\n"
+ "Clear all peers\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, show_ip_extcommunity_list_arg_cmd_vtysh,
+ "show ip extcommunity-list (<1-199>|WORD)",
+ "Show running system information\n"
+ "IP information\n"
+ "List extended-community list\n"
+ "Extcommunity-list number\n"
+ "Extcommunity-list name\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_cmd_vtysh,
+ "clear bgp ipv6 peer-group WORD",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_exact_cmd_vtysh,
+ "no access-list WORD (deny|permit) A.B.C.D/M exact-match",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP zebra access-list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 10.0.0.0/8\n"
+ "Exact match of the prefixes\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_soft_in_cmd_vtysh,
+ "clear ip bgp A.B.C.D soft in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_cost_addr_cmd_vtysh,
+ "no ip ospf cost A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Interface cost\n"
+ "Address of interface")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, rmap_onmatch_next_cmd_vtysh,
+ "on-match next",
+ "Exit policy on matches\n"
+ "Next clause\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_route_cmd_vtysh,
+ "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE)",
+ "IP information\n"
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n")
+
+DEFSH (VTYSH_BGPD, neighbor_enforce_multihop_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "enforce-multihop",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Enforce EBGP neighbors perform multihop\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_topology_router_cmd_vtysh,
+ "show ipv6 ospf6 topology (A.B.C.D|<0-4294967295>|detail)",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Inter Area topology information\n"
+ "Specify Router-ID\n"
+ "Specify Router-ID\n"
+ "Detailed information\n"
+ )
+
+DEFSH (VTYSH_OSPFD, debug_ospf_packet_all_cmd_vtysh,
+ "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)",
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n"
+ "OSPF packets\n"
+ "OSPF Hello\n"
+ "OSPF Database Description\n"
+ "OSPF Link State Request\n"
+ "OSPF Link State Update\n"
+ "OSPF Link State Acknowledgment\n"
+ "OSPF all packets\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_in_prefix_filter_cmd_vtysh,
+ "clear ip bgp <1-65535> in prefix-filter",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Soft reconfig inbound update\n"
+ "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, no_match_aspath_cmd_vtysh,
+ "no match as-path",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "Match BGP AS path list\n")
+
+DEFSH (VTYSH_RIPD, no_debug_rip_events_cmd_vtysh,
+ "no debug rip events",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "RIP information\n"
+ "RIP events\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_network_mask_natural_cmd_vtysh,
+ "no network A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Specify a network to announce via BGP\n"
+ "Network number\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged5_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path next-hop med",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "As-path attribute\n"
+ "Nexthop attribute\n"
+ "Med attribute\n")
+
+DEFSH (VTYSH_RIPD, rip_default_information_originate_cmd_vtysh,
+ "default-information originate",
+ "Control distribution of default route\n"
+ "Distribute a default route\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_abr_type_cmd_vtysh,
+ "no ospf abr-type (cisco|ibm|shortcut)",
+ "Negate a command or set its defaults\n"
+ "OSPF specific commands\n"
+ "Set OSPF ABR type\n"
+ "Alternative ABR, cisco implementation\n"
+ "Alternative ABR, IBM implementation\n"
+ "Shortcut ABR\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv6_rmap_cmd_vtysh,
+ "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPFv3)\n"
+ "Routing Information Protocol (RIPng)\n"
+ "Static routes\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_transmit_delay_cmd_vtysh,
+ "no ospf transmit-delay",
+ "Negate a command or set its defaults\n"
+ "OSPF interface commands\n"
+ "Link state transmit delay\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ipv6_access_list_remark_cmd_vtysh,
+ "ipv6 access-list WORD remark .LINE",
+ "IPv6 information\n"
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n"
+ "Access list entry comment\n"
+ "Comment up to 100 characters\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_detail_cmd_vtysh,
+ "show ipv6 prefix-list detail",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Detail of prefix lists\n")
+
+DEFSH (VTYSH_BGPD, ip_extcommunity_list_standard_cmd_vtysh,
+ "ip extcommunity-list <1-99> (deny|permit) .AA:NN",
+ "IP information\n"
+ "Add a extended community list entry\n"
+ "Extended Community list number (standard)\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n"
+ "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_nd_reachable_time_cmd_vtysh,
+ "no ipv6 nd reachable-time",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Neighbor discovery\n"
+ "Reachable time\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community3_exact_cmd_vtysh,
+ "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "MBGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_ge_le_cmd_vtysh,
+ "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128> le <0-128>",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_retransmit_interval_cmd_vtysh,
+ "no ip ospf retransmit-interval",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Time between retransmitting lost link state advertisements\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community2_cmd_vtysh,
+ "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_mask_as_set_summary_cmd_vtysh,
+ "aggregate-address A.B.C.D A.B.C.D as-set summary-only",
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n"
+ "Generate AS set path information\n"
+ "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_mask_cmd_vtysh,
+ "no aggregate-address A.B.C.D A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_prefix_longer_cmd_vtysh,
+ "show ip bgp A.B.C.D/M longer-prefixes",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Display route and more specific routes\n")
+
+DEFSH (VTYSH_BGPD, set_metric_cmd_vtysh,
+ "set metric (<0-4294967295>|<+/-metric>)",
+ "Set values in destination routing protocol\n"
+ "Metric value for destination routing protocol\n"
+ "Metric value\n"
+ "Add or subtract metric\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community_cmd_vtysh,
+ "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, ipv6_bgp_neighbor_routes_cmd_vtysh,
+ "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display routes learned from neighbor\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_description_arg_cmd_vtysh,
+ "no ip prefix-list WORD description .LINE",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Prefix-list specific description\n"
+ "Up to 80 characters describing this prefix-list\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_neighbors_cmd_vtysh,
+ "show ip bgp neighbors",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n")
+
+DEFSH (VTYSH_BGPD, neighbor_advertise_interval_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X) " "advertisement-interval <0-600>",
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Minimum interval between sending BGP routing updates\n"
+ "time in seconds\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_soft_cmd_vtysh,
+ "clear ip bgp external soft",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all external peers\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_remove_private_as_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "remove-private-AS",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Remove private AS number from outbound updates\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_send_version_cmd_vtysh,
+ "no ip rip send version",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Advertisement transmission\n"
+ "Version control\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_external_in_prefix_filter_cmd_vtysh,
+ "clear bgp external in prefix-filter",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all external peers\n"
+ "Soft reconfig inbound update\n"
+ "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_route_cmd_vtysh,
+ "show ip bgp A.B.C.D",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Network in the BGP routing table to display\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, clear_ipv6_prefix_list_name_cmd_vtysh,
+ "clear ipv6 prefix-list WORD",
+ "Reset functions\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_timers_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "timers",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP per neighbor timers\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_soft_in_cmd_vtysh,
+ "clear ip bgp peer-group WORD soft in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_type_routemap_cmd_vtysh,
+ "default-information originate always metric-type (1|2) route-map WORD",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "Always advertise default route\n"
+ "OSPF metric type for default routes\n"
+ "Set OSPF External Type 1 metrics\n"
+ "Set OSPF External Type 2 metrics\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, ip_extcommunity_list_expanded_cmd_vtysh,
+ "ip extcommunity-list <100-199> (deny|permit) .LINE",
+ "IP information\n"
+ "Add a extended community list entry\n"
+ "Extended Community list number (expanded)\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n"
+ "An ordered list as a regular-expression\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ipv6_access_list_exact_cmd_vtysh,
+ "ipv6 access-list WORD (deny|permit) X:X::X:X/M exact-match",
+ "IPv6 information\n"
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 3ffe:506::/32\n"
+ "Exact match of the prefixes\n")
+
+DEFSH (VTYSH_BGPD, show_ip_community_list_arg_cmd_vtysh,
+ "show ip community-list (<1-199>|WORD)",
+ "Show running system information\n"
+ "IP information\n"
+ "List community-list\n"
+ "Community-list number\n"
+ "Community-list name\n")
+
+DEFSH (VTYSH_BGPD, bgp_timers_cmd_vtysh,
+ "timers bgp <0-65535> <0-65535>",
+ "Adjust routing timers\n"
+ "BGP timers\n"
+ "Keepalive interval\n"
+ "Holdtime\n")
+
+DEFSH (VTYSH_RIPD, rip_neighbor_cmd_vtysh,
+ "neighbor A.B.C.D",
+ "Specify a neighbor router\n"
+ "Neighbor address\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_prefix_first_match_cmd_vtysh,
+ "show ipv6 prefix-list WORD X:X::X:X/M first-match",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "First matched prefix\n")
+
+DEFSH (VTYSH_BGPD, neighbor_shutdown_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "shutdown",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Administratively shut down this neighbor\n")
+
+DEFSH (VTYSH_BGPD, no_debug_bgp_fsm_cmd_vtysh,
+ "no debug bgp fsm",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "BGP information\n"
+ "Finite State Machine\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_soft_in_cmd_vtysh,
+ "clear bgp ipv6 <1-65535> soft in",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear peers with the AS number\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, neighbor_weight_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "weight <0-65535>",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Set default weight for routes from this neighbor\n"
+ "default weight\n")
+
+DEFSH (VTYSH_BGPD, neighbor_transparent_nexthop_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X) " "transparent-nexthop",
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Do not change nexthop even peer is EBGP peer\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_soft_cmd_vtysh,
+ "clear ip bgp A.B.C.D soft",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_neighbors_peer_cmd_vtysh,
+ "show ip bgp vpnv4 all neighbors A.B.C.D",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display VPNv4 NLRI specific information\n"
+ "Display information about all VPNv4 NLRIs\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community_list_cmd_vtysh,
+ "show ipv6 bgp community-list WORD",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Display routes matching the community-list\n"
+ "community-list name\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_vpnv4_soft_in_cmd_vtysh,
+ "clear ip bgp A.B.C.D vpnv4 unicast soft in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "Address family\n"
+ "Address Family Modifier\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_le_cmd_vtysh,
+ "no ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_bestpath_med2_cmd_vtysh,
+ "no bgp bestpath med confed missing-as-worst",
+ "Negate a command or set its defaults\n"
+ "BGP specific commands\n"
+ "Change the default bestpath selection\n"
+ "MED attribute\n"
+ "Compare MED among confederation paths\n"
+ "Treat missing MED as the least preferred one\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_priority_cmd_vtysh,
+ "no ospf priority",
+ "Negate a command or set its defaults\n"
+ "OSPF interface commands\n"
+ "Router priority\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_mask_natural_cmd_vtysh,
+ "network A.B.C.D",
+ "Specify a network to announce via BGP\n"
+ "Network number\n")
+
+DEFSH (VTYSH_OSPFD, area_stub_nosum_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) stub no-summary",
+ "OSPF stub parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Configure OSPF area as stub\n"
+ "Do not inject inter-area routes into stub\n")
+
+DEFSH (VTYSH_BGPD, no_synchronization_cmd_vtysh,
+ "no synchronization",
+ "Negate a command or set its defaults\n"
+ "Perform IGP synchronization\n")
+
+DEFSH (VTYSH_OSPFD, no_area_range_not_advertise_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M not-advertise",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "OSPF area range for route DoNotAdvertise\n"
+ "area range prefix\n"
+ "do not advertise this range\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, set_ip_nexthop_cmd_vtysh,
+ "set ip next-hop A.B.C.D",
+ "Set values in destination routing protocol\n"
+ "IP information\n"
+ "Next hop address\n"
+ "IP address of next hop\n")
+
+DEFSH (VTYSH_RIPD, no_rip_version_val_cmd_vtysh,
+ "no version <1-2>",
+ "Negate a command or set its defaults\n"
+ "Set routing protocol version\n"
+ "version\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_scan_time_cmd_vtysh,
+ "no bgp scan-time",
+ "Negate a command or set its defaults\n"
+ "BGP specific commands\n"
+ "Configure background scanner interval\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_connected_metric_cmd_vtysh,
+ "no redistribute connected metric",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Metric\n")
+
+DEFSH (VTYSH_OSPF6D, debug_ospf6_all_cmd_vtysh,
+ "debug ospf6 all",
+ "Debugging functions (see also 'undebug')\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Turn on ALL OSPFv3 debugging\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_authentication_key_addr_cmd_vtysh,
+ "no ip ospf authentication-key A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Authentication password (key)\n"
+ "Address of interface")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_route_cmd_vtysh,
+ "no route IPV6ADDR",
+ "Negate a command or set its defaults\n"
+ "Static route setup\n"
+ "Delete static RIPng route announcement\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_nsm_sub_cmd_vtysh,
+ "debug ospf nsm (status|events|timers)",
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n"
+ "OSPF Neighbor State Machine\n"
+ "NSM Status Information\n"
+ "NSM Event Information\n"
+ "NSM Timer Information\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_vpnv4_soft_out_cmd_vtysh,
+ "clear ip bgp <1-65535> vpnv4 unicast soft out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, no_debug_bgp_all_cmd_vtysh,
+ "no debug all bgp",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "Enable all debugging\n"
+ "BGP information\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_vpnv4_soft_out_cmd_vtysh,
+ "clear ip bgp * vpnv4 unicast soft out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Address family\n"
+ "Address Family Modifier\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_distance_cmd_vtysh,
+ "no distance bgp <1-255> <1-255> <1-255>",
+ "Negate a command or set its defaults\n"
+ "Define an administrative distance\n"
+ "BGP distance\n"
+ "Distance for routes external to the AS\n"
+ "Distance for routes internal to the AS\n"
+ "Distance for local routes\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_soft_out_cmd_vtysh,
+ "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD, no_rip_timers_cmd_vtysh,
+ "no timers basic",
+ "Negate a command or set its defaults\n"
+ "Adjust routing timers\n"
+ "Basic routing protocol update timers\n")
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_passive_cmd_vtysh,
+ "ipv6 ospf6 passive",
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "passive interface: No Adjacency will be formed on this I/F\n"
+ )
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_inter_external_intra_cmd_vtysh,
+ "distance ospf inter-area <1-255> external <1-255> intra-area <1-255>",
+ "Define an administrative distance\n"
+ "OSPF Administrative distance\n"
+ "Inter-area routes\n"
+ "Distance for inter-area routes\n"
+ "External routes\n"
+ "Distance for external routes\n"
+ "Intra-area routes\n"
+ "Distance for intra-area routes\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_type_metric_routemap_cmd_vtysh,
+ "default-information originate always metric-type (1|2) metric <0-16777214> route-map WORD",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "Always advertise default route\n"
+ "OSPF metric type for default routes\n"
+ "Set OSPF External Type 1 metrics\n"
+ "Set OSPF External Type 2 metrics\n"
+ "OSPF default metric\n"
+ "OSPF metric\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_RIPNGD, no_debug_ripng_events_cmd_vtysh,
+ "no debug ripng events",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "RIPng configuration\n"
+ "Debug option set for ripng events\n")
+
+DEFSH (VTYSH_RIPD, accept_lifetime_duration_month_day_cmd_vtysh,
+ "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> duration <1-2147483646>",
+ "Set accept lifetime of the key\n"
+ "Time to start\n"
+ "Month of the year to start\n"
+ "Day of th month to start\n"
+ "Year to start\n"
+ "Duration of the key\n"
+ "Duration seconds\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_ospf6_metric_routemap_cmd_vtysh,
+ "redistribute ospf6 metric <0-16> route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "IPv6 Open Shortest Path First (OSPFv3)\n"
+ "Metric\n"
+ "Metric value\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_match_metric_cmd_vtysh,
+ "no match metric",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "Match metric of route\n")
+
+DEFSH (VTYSH_RIPD, match_ip_next_hop_cmd_vtysh,
+ "match ip next-hop WORD",
+ "Match values from routing table\n"
+ "IP information\n"
+ "Match next-hop address of route\n"
+ "IP access-list name\n")
+
+DEFSH (VTYSH_ZEBRA, ip_irdp_cmd_vtysh,
+ "ip irdp",
+ "IP information\n"
+ "ICMP Router discovery on this interface\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_summary_only_cmd_vtysh,
+ "aggregate-address A.B.C.D/M summary-only",
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_in_prefix_filter_cmd_vtysh,
+ "clear bgp ipv6 <1-65535> in prefix-filter",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear peers with the AS number\n"
+ "Soft reconfig inbound update\n"
+ "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_network_route_map_cmd_vtysh,
+ "no network A.B.C.D/M route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Specify a network to announce via BGP\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_instance_neighbors_peer_cmd_vtysh,
+ "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X)",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP view\n"
+ "View name\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_connected_cmd_vtysh,
+ "no redistribute connected",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Connected\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_summary_as_set_cmd_vtysh,
+ "aggregate-address A.B.C.D/M summary-only as-set",
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Filter more specific routes from updates\n"
+ "Generate AS set path information\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_in_cmd_vtysh,
+ "clear ip bgp external in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all external peers\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD, no_debug_rip_packet_direct_cmd_vtysh,
+ "no debug rip packet (recv|send)",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "RIP information\n"
+ "RIP packet\n"
+ "RIP option set for receive packet\n"
+ "RIP option set for send packet\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community2_exact_cmd_vtysh,
+ "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, no_neighbor_nexthop_self_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "next-hop-self",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Disable the next hop calculation for this neighbor\n")
+
+DEFSH (VTYSH_OSPFD, area_range_not_advertise_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M not-advertise",
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "OSPF area range for route DoNotAdvertise\n"
+ "area range prefix\n"
+ "do not advertise this range\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_authentication_mode_type_cmd_vtysh,
+ "no ip rip authentication mode (md5|text)",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Authentication control\n"
+ "Authentication mode\n"
+ "Keyed message digest\n"
+ "Clear text authentication\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_summary_cmd_vtysh,
+ "show ipv6 prefix-list summary",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Summary of prefix lists\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_any_cmd_vtysh,
+ "no access-list WORD (deny|permit) any",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP zebra access-list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 10.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, bgp_bestpath_med3_cmd_vtysh,
+ "bgp bestpath med missing-as-worst confed",
+ "BGP specific commands\n"
+ "Change the default bestpath selection\n"
+ "MED attribute\n"
+ "Treat missing MED as the least preferred one\n"
+ "Compare MED among confederation paths\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community4_cmd_vtysh,
+ "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_retransmit_interval_addr_cmd_vtysh,
+ "ip ospf retransmit-interval <3-65535> A.B.C.D",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Time between retransmitting lost link state advertisements\n"
+ "Seconds\n"
+ "Address of interface")
+
+DEFSH (VTYSH_RIPD, match_ip_address_cmd_vtysh,
+ "match ip address WORD",
+ "Match values from routing table\n"
+ "IP information\n"
+ "Match address of route\n"
+ "IP access-list name\n")
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_deadinterval_cmd_vtysh,
+ "ipv6 ospf6 dead-interval ROUTER_DEAD_INTERVAL",
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Interval after which a neighbor is declared dead\n"
+ "<1-65535> Seconds\n"
+ )
+
+DEFSH (VTYSH_OSPFD, debug_ospf_zebra_sub_cmd_vtysh,
+ "debug ospf zebra (interface|redistribute)",
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n"
+ "OSPF Zebra information\n"
+ "Zebra interface\n"
+ "Zebra redistribute\n")
+
+DEFSH (VTYSH_BGPD, match_aspath_cmd_vtysh,
+ "match as-path WORD",
+ "Match values from routing table\n"
+ "Match BGP AS path list\n"
+ "AS path access-list name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_flap_cidr_only_cmd_vtysh,
+ "show ip bgp flap-statistics cidr-only",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display flap statistics of routes\n"
+ "Display only routes with non-natural netmasks\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_description_arg_cmd_vtysh,
+ "no ipv6 prefix-list WORD description .LINE",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Prefix-list specific description\n"
+ "Up to 80 characters describing this prefix-list\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_nd_ra_interval_cmd_vtysh,
+ "no ipv6 nd ra-interval",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Neighbor discovery\n"
+ "Router Advertisement interval\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd_vtysh,
+ "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in prefix-filter",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig inbound update\n"
+ "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_soft_cmd_vtysh,
+ "clear ip bgp * soft",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_static_metric_routemap_cmd_vtysh,
+ "redistribute static metric <0-16> route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "Static routes\n"
+ "Metric\n"
+ "Metric value\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv6_rmap_metric_cmd_vtysh,
+ "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>",
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPFv3)\n"
+ "Routing Information Protocol (RIPng)\n"
+ "Static routes\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n"
+ "Metric for redistributed routes\n"
+ "Default metric\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_route_map_cmd_vtysh,
+ "show bgp ipv6 route-map WORD",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Display routes matching the route-map\n"
+ "A route-map to match on\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_next_hop_prefix_list_cmd_vtysh,
+ "no match ip next-hop prefix-list",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "IP information\n"
+ "Match next-hop address of route\n"
+ "Match entries of prefix-lists\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_set_peer_group_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X) " "peer-group WORD",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Member of the peer-group\n"
+ "peer-group name\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_neighbor_routes_cmd_vtysh,
+ "show bgp neighbors (A.B.C.D|X:X::X:X) routes",
+ "Show running system information\n"
+ "BGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display routes learned from neighbor\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_route_prefix_cmd_vtysh,
+ "show ipv6 ospf6 route (X::X|detail)",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Routing table\n"
+ "match IPv6 prefix\n"
+ )
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_bgp_cmd_vtysh,
+ "redistribute bgp",
+ "Redistribute information from another routing protocol\n"
+ "Border Gateway Protocol (BGP)\n")
+
+DEFSH (VTYSH_ZEBRA, ip_irdp_multicast_cmd_vtysh,
+ "ip irdp multicast",
+ "IP information\n"
+ "ICMP Router discovery on this interface\n"
+ "Send IRDP advertisement to the multicast address\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_host_mask_cmd_vtysh,
+ "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D A.B.C.D A.B.C.D",
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "A single source host\n"
+ "Source address\n"
+ "Destination address\n"
+ "Destination Wildcard bits\n")
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_authtype_authkey_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication|) "
+ "(authentication-key|)",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Enable authentication on this virtual link\n" "dummy string \n"
+ "Authentication password (key)\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_BGPD, debug_bgp_events_cmd_vtysh,
+ "debug bgp events",
+ "Debugging functions (see also 'undebug')\n"
+ "BGP information\n"
+ "BGP events\n")
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_param1_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval)",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_seq_ge_cmd_vtysh,
+ "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32>",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+
+DEFSH (VTYSH_RIPNGD, debug_ripng_packet_cmd_vtysh,
+ "debug ripng packet",
+ "Debugging functions (see also 'undebug')\n"
+ "RIPng configuration\n"
+ "Debug option set for ripng packet\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_out_cmd_vtysh,
+ "clear ip bgp <1-65535> out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_static_metric_cmd_vtysh,
+ "no redistribute static metric",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Static routes\n"
+ "Metric\n")
+
+DEFSH (VTYSH_OSPFD, no_interface_ip_ospf_authentication_cmd_vtysh,
+ "no ip ospf authentication",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Enable authentication on this interface\n")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_routemap_cmd_vtysh,
+ "redistribute (kernel|connected|static|rip|bgp) route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Routing Information Protocol (RIP)\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community2_exact_cmd_vtysh,
+ "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_OSPFD, no_neighbor_priority_pollinterval_cmd_vtysh,
+ "no neighbor A.B.C.D priority <0-255> poll-interval <1-65535>",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor IP address\n"
+ "Neighbor Priority\n"
+ "Priority\n"
+ "Dead Neighbor Polling interval\n"
+ "Seconds\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_external_soft_cmd_vtysh,
+ "clear bgp external soft",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all external peers\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, no_ipv6_aggregate_address_cmd_vtysh,
+ "no aggregate-address X:X::X:X/M",
+ "Negate a command or set its defaults\n"
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_all_in_prefix_filter_cmd_vtysh,
+ "clear bgp * in prefix-filter",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Soft reconfig inbound update\n"
+ "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_timers_connect_val_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X) " "timers connect <0-65535>",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "BGP per neighbor timers\n"
+ "BGP connect timer\n"
+ "Connect timer\n")
+
+DEFSH (VTYSH_OSPFD, no_auto_cost_reference_bandwidth_cmd_vtysh,
+ "no auto-cost reference-bandwidth",
+ "Negate a command or set its defaults\n"
+ "Calculate OSPF interface cost according to bandwidth\n"
+ "Use reference bandwidth method to assign OSPF cost\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_cmd_vtysh,
+ "show ip bgp",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_message_digest_key_addr_cmd_vtysh,
+ "ip ospf message-digest-key <1-255> md5 KEY A.B.C.D",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Message digest authentication password (key)\n"
+ "Key ID\n"
+ "Use MD5 algorithm\n"
+ "The OSPF password (key)"
+ "Address of interface")
+
+DEFSH (VTYSH_BGPD, show_debugging_bgp_cmd_vtysh,
+ "show debugging bgp",
+ "Show running system information\n"
+ "Debugging functions (see also 'undebug')\n"
+ "BGP information\n")
+
+DEFSH (VTYSH_OSPFD|VTYSH_OSPF6D, ospf6_routemap_set_metric_type_cmd_vtysh,
+ "set metric-type (type-1|type-2)",
+ "Set value\n"
+ "Type of metric\n"
+ "OSPF6 external type 1 metric\n"
+ "OSPF6 external type 2 metric\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_mask_summary_only_cmd_vtysh,
+ "aggregate-address A.B.C.D A.B.C.D summary-only",
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n"
+ "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_passive_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "passive",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Don't send open messages to this neighbor\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_standard_cmd_vtysh,
+ "access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D A.B.C.D",
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP standard access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Address to match\n"
+ "Wildcard bits\n")
+
+DEFSH (VTYSH_ZEBRA, no_zebra_interface_cmd_vtysh,
+ "no interface IFNAME",
+ "Delete a pseudo interface's configuration\n"
+ "Interface's name\n")
+
+DEFSH (VTYSH_RIPD, debug_rip_zebra_cmd_vtysh,
+ "debug rip zebra",
+ "Debugging functions (see also 'undebug')\n"
+ "RIP information\n"
+ "RIP and ZEBRA communication\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_mask_any_cmd_vtysh,
+ "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D any",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Source address\n"
+ "Source wildcard bits\n"
+ "Any destination host\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_paths_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) paths",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Path information\n")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_type_metric_routemap_cmd_vtysh,
+ "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214> route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Routing Information Protocol (RIP)\n"
+ "Border Gateway Protocol (BGP)\n"
+ "OSPF exterior metric type for redistributed routes\n"
+ "Set OSPF External Type 1 metrics\n"
+ "Set OSPF External Type 2 metrics\n"
+ "Metric for redistributed routes\n"
+ "OSPF default metric\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_group_soft_out_cmd_vtysh,
+ "clear bgp peer-group WORD soft out",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, no_area_filter_list_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) filter-list prefix WORD (in|out)",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Filter networks between OSPF areas\n"
+ "Filter prefixes between OSPF areas\n"
+ "Name of an IP prefix-list\n"
+ "Filter networks sent to this area\n"
+ "Filter networks sent from this area\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_route_cmd_vtysh,
+ "show ipv6 bgp X:X::X:X",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Network in the BGP routing table to display\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_mask_natural_backdoor_cmd_vtysh,
+ "network A.B.C.D backdoor",
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Specify a BGP backdoor route\n")
+
+DEFSH (VTYSH_RIPD, rip_route_cmd_vtysh,
+ "route A.B.C.D/M",
+ "RIP static route configuration\n"
+ "IP prefix <network>/<length>\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_cost_cmd_vtysh,
+ "no ospf cost",
+ "Negate a command or set its defaults\n"
+ "OSPF interface commands\n"
+ "Interface cost\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_all_soft_out_cmd_vtysh,
+ "clear bgp * soft out",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_sequence_number_cmd_vtysh,
+ "ipv6 prefix-list sequence-number",
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Include/exclude sequence numbers in NVGEN\n")
+
+DEFSH (VTYSH_RIPD, no_debug_rip_packet_cmd_vtysh,
+ "no debug rip packet",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "RIP information\n"
+ "RIP packet\n")
+
+DEFSH (VTYSH_ZEBRA, show_ip_route_prefix_longer_cmd_vtysh,
+ "show ip route A.B.C.D/M longer-prefixes",
+ "Show running system information\n"
+ "IP information\n"
+ "IP routing table\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Show route matching the specified Network/Mask pair only\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ipv6_access_list_name_cmd_vtysh,
+ "show ipv6 access-list WORD",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "List IPv6 access lists\n"
+ "IPv6 zebra access-list\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_ripng_cmd_vtysh,
+ "no redistribute ripng",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "RIPng route\n")
+
+DEFSH (VTYSH_BGPD, no_set_community_val_cmd_vtysh,
+ "no set community .AA:NN",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "BGP community attribute\n"
+ "Community number in aa:nn format or local-AS|no-advertise|no-export|internet or additive\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_group_out_cmd_vtysh,
+ "clear bgp peer-group WORD out",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_prefix_longer_cmd_vtysh,
+ "show ipv6 prefix-list WORD X:X::X:X/M longer",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Lookup longer prefix\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv4_metric_cmd_vtysh,
+ "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPF)\n"
+ "Routing Information Protocol (RIP)\n"
+ "Static routes\n"
+ "Metric for redistributed routes\n"
+ "Default metric\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_authkey_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication-key|) AUTH_KEY",
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Authentication password (key)\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_flap_prefix_list_cmd_vtysh,
+ "show ip bgp flap-statistics prefix-list WORD",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display flap statistics of routes\n"
+ "Display routes conforming to the prefix-list\n"
+ "IP prefix-list name\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_aggregate_address_cmd_vtysh,
+ "no aggregate-address X:X::X:X/M",
+ "Negate a command or set its defaults\n"
+ "Delete aggregate RIPng route announcement\n"
+ "Aggregate network")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_neighbor_routes_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display routes learned from neighbor\n")
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_retransmitinterval_cmd_vtysh,
+ "ipv6 ospf6 retransmit-interval RXMTINTERVAL",
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Time between retransmitting lost link state advertisements\n"
+ "<1-65535> Seconds\n"
+ )
+
+DEFSH (VTYSH_RIPD, debug_rip_packet_detail_cmd_vtysh,
+ "debug rip packet (recv|send) detail",
+ "Debugging functions (see also 'undebug')\n"
+ "RIP information\n"
+ "RIP packet\n"
+ "RIP receive packet\n"
+ "RIP send packet\n"
+ "Detailed information display\n")
+
+DEFSH (VTYSH_ZEBRA, show_ip_route_protocol_cmd_vtysh,
+ "show ip route (bgp|connected|kernel|ospf|rip|static)",
+ "Show running system information\n"
+ "IP information\n"
+ "IP routing table\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Connected\n"
+ "Kernel\n"
+ "Open Shortest Path First (OSPF)\n"
+ "Routing Information Protocol (RIP)\n"
+ "Static routes\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_client_to_client_reflection_cmd_vtysh,
+ "no bgp client-to-client reflection",
+ "Negate a command or set its defaults\n"
+ "BGP specific commands\n"
+ "Configure client to client route reflection\n"
+ "reflection of routes allowed\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_rmap_onmatch_next_cmd_vtysh,
+ "no on-match next",
+ "Negate a command or set its defaults\n"
+ "Exit policy on matches\n"
+ "Next clause\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_multiple_instance_cmd_vtysh,
+ "no bgp multiple-instance",
+ "Negate a command or set its defaults\n"
+ "BGP information\n"
+ "BGP multiple instance\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_nsm_sub_cmd_vtysh,
+ "no debug ospf nsm (status|events|timers)",
+ "Negate a command or set its defaults\n"
+ "Debugging functions\n"
+ "OSPF information\n"
+ "OSPF Interface State Machine\n"
+ "NSM Status Information\n"
+ "NSM Event Information\n"
+ "NSM Timer Information\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_param2_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>",
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n")
+
+DEFSH (VTYSH_BGPD, bgp_distance_cmd_vtysh,
+ "distance bgp <1-255> <1-255> <1-255>",
+ "Define an administrative distance\n"
+ "BGP distance\n"
+ "Distance for routes external to the AS\n"
+ "Distance for routes internal to the AS\n"
+ "Distance for local routes\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_group_soft_cmd_vtysh,
+ "clear bgp peer-group WORD soft",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv4_metric_rmap_cmd_vtysh,
+ "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPF)\n"
+ "Routing Information Protocol (RIP)\n"
+ "Static routes\n"
+ "Metric for redistributed routes\n"
+ "Default metric\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_host_any_cmd_vtysh,
+ "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D any",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "A single source host\n"
+ "Source address\n"
+ "Any destination host\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_attr_info_cmd_vtysh,
+ "show ip bgp attribute-info",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "List all bgp attribute information\n")
+
+DEFSH (VTYSH_RIPNGD, no_default_information_originate_cmd_vtysh,
+ "no default-information originate",
+ "Negate a command or set its defaults\n"
+ "Default route information\n"
+ "Distribute default route\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_standard_host_cmd_vtysh,
+ "no access-list (<1-99>|<1300-1999>) (deny|permit) host A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP standard access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "A single host address\n"
+ "Address to match\n")
+
+DEFSH (VTYSH_RIPD, show_ip_protocols_rip_cmd_vtysh,
+ "show ip protocols",
+ "Show running system information\n"
+ "IP information\n"
+ "IP routing protocol process parameters and statistics\n")
+
+DEFSH (VTYSH_RIPD, send_lifetime_day_month_day_month_cmd_vtysh,
+ "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>",
+ "Set send lifetime of the key\n"
+ "Time to start\n"
+ "Day of th month to start\n"
+ "Month of the year to start\n"
+ "Year to start\n"
+ "Time to expire\n"
+ "Day of th month to expire\n"
+ "Month of the year to expire\n"
+ "Year to expire\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_topology_cmd_vtysh,
+ "show ipv6 ospf6 topology",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Inter Area topology information\n"
+ )
+
+DEFSH (VTYSH_OSPFD, no_ospf_redistribute_source_cmd_vtysh,
+ "no redistribute (kernel|connected|static|rip|bgp)",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Routing Information Protocol (RIP)\n"
+ "Border Gateway Protocol (BGP)\n")
+
+DEFSH (VTYSH_RIPD, ip_rip_receive_version_cmd_vtysh,
+ "ip rip receive version (1|2)",
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Advertisement reception\n"
+ "Version control\n"
+ "RIP version 1\n"
+ "RIP version 2\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_priority_addr_cmd_vtysh,
+ "ip ospf priority <0-255> A.B.C.D",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Router priority\n"
+ "Priority\n"
+ "Address of interface")
+
+DEFSH (VTYSH_ZEBRA, debug_zebra_events_cmd_vtysh,
+ "debug zebra events",
+ "Debugging functions (see also 'undebug')\n"
+ "Zebra configuration\n"
+ "Debug option set for zebra events\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community_cmd_vtysh,
+ "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, match_metric_cmd_vtysh,
+ "match metric <0-4294967295>",
+ "Match values from routing table\n"
+ "Match metric of route\n"
+ "Metric value\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_prefix_longer_cmd_vtysh,
+ "show bgp ipv6 X:X::X:X/M longer-prefixes",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "IPv6 prefix <network>/<length>\n"
+ "Display route and more specific routes\n")
+
+DEFSH (VTYSH_OSPF6D, no_ipv6_ospf6_passive_cmd_vtysh,
+ "no ipv6 ospf6 passive",
+ "Negate a command or set its defaults\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "passive interface: No Adjacency will be formed on this I/F\n"
+ )
+
+DEFSH (VTYSH_RIPD, accept_lifetime_infinite_day_month_cmd_vtysh,
+ "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> infinite",
+ "Set accept lifetime of the key\n"
+ "Time to start\n"
+ "Day of th month to start\n"
+ "Month of the year to start\n"
+ "Year to start\n"
+ "Never expires")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged6_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path med next-hop",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "As-path attribute\n"
+ "Med attribute\n"
+ "Nexthop attribute\n")
+
+DEFSH (VTYSH_OSPFD, no_area_import_list_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) import-list NAME",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Unset the filter for networks announced to other areas\n"
+ "Name of the access-list\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_seq_ge_cmd_vtysh,
+ "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128>",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+
+DEFSH (VTYSH_OSPFD, no_interface_ip_ospf_authentication_addr_cmd_vtysh,
+ "no ip ospf authentication A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Enable authentication on this interface\n"
+ "Address of interface")
+
+DEFSH (VTYSH_BGPD, neighbor_route_reflector_client_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "route-reflector-client",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Configure a neighbor as Route Reflector client\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community_list_cmd_vtysh,
+ "show bgp community-list WORD",
+ "Show running system information\n"
+ "BGP information\n"
+ "Display routes matching the community-list\n"
+ "community-list name\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_ripng_cmd_vtysh,
+ "redistribute ripng",
+ "Redistribute information from another routing protocol\n"
+ "RIPng route\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_standard_host_cmd_vtysh,
+ "access-list (<1-99>|<1300-1999>) (deny|permit) host A.B.C.D",
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP standard access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "A single host address\n"
+ "Address to match\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_bgp_metric_cmd_vtysh,
+ "redistribute bgp metric <0-16>",
+ "Redistribute information from another routing protocol\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Metric\n"
+ "Metric value\n")
+
+DEFSH (VTYSH_OSPF6D|VTYSH_BGPD, match_ipv6_address_prefix_list_cmd_vtysh,
+ "match ipv6 address prefix-list WORD",
+ "Match values from routing table\n"
+ "IPv6 information\n"
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_neighbor_received_prefix_filter_cmd_vtysh,
+ "show bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter",
+ "Show running system information\n"
+ "BGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display information received from a BGP neighbor\n"
+ "Display the prefixlist filter\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_instance_neighbors_cmd_vtysh,
+ "show ip bgp view WORD neighbors",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP view\n"
+ "View name\n"
+ "Detailed information on TCP and BGP neighbor connections\n")
+
+DEFSH (VTYSH_OSPF6D, show_zebra_cmd_vtysh,
+ "show zebra",
+ "Show running system information\n"
+ "Zebra information\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_out_cmd_vtysh,
+ "clear bgp (A.B.C.D|X:X::X:X) out",
+ "Reset functions\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "BGP IPv6 neighbor to clear\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_description_cmd_vtysh,
+ "no ip prefix-list WORD description",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Prefix-list specific description\n")
+
+DEFSH (VTYSH_ZEBRA, no_ip_forwarding_cmd_vtysh,
+ "no ip forwarding",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Turn off IP forwarding")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_bgp_routemap_cmd_vtysh,
+ "redistribute bgp route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, no_debug_bgp_update_cmd_vtysh,
+ "no debug bgp updates",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "BGP information\n"
+ "BGP updates\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_ospf6_cmd_vtysh,
+ "no redistribute ospf6",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "IPv6 Open Shortest Path First (OSPFv3)\n")
+
+DEFSH (VTYSH_ZEBRA, no_ip_address_cmd_vtysh,
+ "no ip address A.B.C.D/M",
+ "Negate a command or set its defaults\n"
+ "Interface Internet Protocol config commands\n"
+ "Set the IP address of an interface\n"
+ "IP Address (e.g. 10.0.0.1/8)")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_route_map_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) route-map WORD",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the route-map\n"
+ "A route-map to match on\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_address_cmd_vtysh,
+ "no ipv6 address X:X::X:X/M",
+ "Negate a command or set its defaults\n"
+ "Interface Internet Protocol config commands\n"
+ "Set the IP address of an interface\n"
+ "IPv6 address (e.g. 3ffe:506::1/48)\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_shutdown_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "shutdown",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Administratively shut down this neighbor\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_authentication_string2_cmd_vtysh,
+ "no ip rip authentication string LINE",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Authentication control\n"
+ "Authentication string\n"
+ "Authentication string\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_network_cmd_vtysh,
+ "ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Network type\n"
+ "Specify OSPF broadcast multi-access network\n"
+ "Specify OSPF NBMA network\n"
+ "Specify OSPF point-to-multipoint network\n"
+ "Specify OSPF point-to-point network\n")
+
+DEFSH (VTYSH_BGPD, neighbor_send_community_type_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community (both|extended|standard)",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Send Community attribute to this neighbor\n"
+ "Send Standard and Extended Community attributes\n"
+ "Send Extended Community attributes\n"
+ "Send Standard Community attributes\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_kernel_metric_cmd_vtysh,
+ "no redistribute kernel metric",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Metric\n")
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv4_rmap_cmd_vtysh,
+ "redistribute (connected|kernel|ospf|rip|static) route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPF)\n"
+ "Routing Information Protocol (RIP)\n"
+ "Static routes\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_le_cmd_vtysh,
+ "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128>",
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_cmd_vtysh,
+ "redistribute (kernel|connected|static|rip|bgp)",
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Routing Information Protocol (RIP)\n"
+ "Border Gateway Protocol (BGP)\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_nd_prefix_advertisement_cmd_vtysh,
+ "ipv6 nd prefix-advertisement IPV6PREFIX VALID PREFERRED [onlink] [autoconfig]",
+ "IP information\n"
+ "Neighbor discovery\n"
+ "Prefix information\n"
+ "IPv6 prefix\n"
+ "Valid lifetime in seconds\n"
+ "Preferred lifetime in seconds\n"
+ "On link flag\n"
+ "Autonomous address-configuration flag\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ipv6_access_list_cmd_vtysh,
+ "show ipv6 access-list",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "List IPv6 access lists\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_override_capability_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "override-capability",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Override capability negotiation result\n")
+
+DEFSH (VTYSH_BGPD, undebug_bgp_update_cmd_vtysh,
+ "undebug bgp updates",
+ "Disable debugging functions (see also 'debug')\n"
+ "BGP information\n"
+ "BGP updates\n")
+
+DEFSH (VTYSH_RIPNGD, no_debug_ripng_packet_cmd_vtysh,
+ "no debug ripng packet",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "RIPng configuration\n"
+ "Debug option set for ripng packet\n")
+
+DEFSH (VTYSH_ZEBRA, ip_route_pref_cmd_vtysh,
+ "ip route A.B.C.D/M (A.B.C.D|INTERFACE) <1-255>",
+ "IP information\n"
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Distance value for this route\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_prefix_list_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) prefix-list WORD",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes conforming to the prefix-list\n"
+ "IP prefix-list name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community2_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged6_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path med next-hop",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "As-path attribute\n"
+ "Med attribute\n"
+ "Nexthop attribute\n")
+
+DEFSH (VTYSH_OSPFD, no_timers_spf_cmd_vtysh,
+ "no timers spf",
+ "Negate a command or set its defaults\n"
+ "Adjust routing timers\n"
+ "OSPF SPF timers\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_flap_filter_list_cmd_vtysh,
+ "show ip bgp flap-statistics filter-list WORD",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display flap statistics of routes\n"
+ "Display routes conforming to the filter-list\n"
+ "Regular expression access list name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd_vtysh,
+ "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display VPNv4 NLRI specific information\n"
+ "Display information for a route distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Display the routes advertised to a BGP neighbor\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_kernel_routemap_cmd_vtysh,
+ "no redistribute kernel route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_route_cmd_vtysh,
+ "show ip bgp vpnv4 all A.B.C.D",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display VPNv4 NLRI specific information\n"
+ "Display information about all VPNv4 NLRIs\n"
+ "Network in the BGP routing table to display\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_regexp_cmd_vtysh,
+ "show bgp ipv6 regexp .LINE",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Display routes matching the AS path regular expression\n"
+ "A regular-expression to match the BGP AS paths\n")
+
+DEFSH (VTYSH_OSPFD, no_passive_interface_addr_cmd_vtysh,
+ "no passive-interface IFNAME A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Allow routing updates on an interface\n"
+ "Interface's name\n")
+
+DEFSH (VTYSH_OSPFD, ospf_authentication_key_cmd_vtysh,
+ "ospf authentication-key AUTH_KEY",
+ "OSPF interface commands\n"
+ "Authentication password (key)\n"
+ "The OSPF password (key)")
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_priority_cmd_vtysh,
+ "ipv6 ospf6 priority PRIORITY",
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Router priority\n"
+ "<0-255> Priority\n"
+ )
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_md5_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(message-digest-key|) <1-255>",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_RIPD, no_rip_distance_source_access_list_cmd_vtysh,
+ "no distance <1-255> A.B.C.D/M WORD",
+ "Negate a command or set its defaults\n"
+ "Administrative distance\n"
+ "Distance value\n"
+ "IP source prefix\n"
+ "Access list name\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_router_id_cmd_vtysh,
+ "no ospf router-id",
+ "Negate a command or set its defaults\n"
+ "OSPF specific commands\n"
+ "router-id for the OSPF process\n")
+
+DEFSH (VTYSH_BGPD, bgp_bestpath_compare_router_id_cmd_vtysh,
+ "bgp bestpath compare-routerid",
+ "BGP specific commands\n"
+ "Change the default bestpath selection\n"
+ "Compare router-id for identical EBGP paths\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_bgp_metric_val_cmd_vtysh,
+ "no redistribute bgp metric <0-16>",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Metric\n"
+ "Metric value\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community3_cmd_vtysh,
+ "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_ZEBRA, debug_zebra_packet_direct_cmd_vtysh,
+ "debug zebra packet (recv|send)",
+ "Debugging functions (see also 'undebug')\n"
+ "Zebra configuration\n"
+ "Debug option set for zebra packet\n"
+ "Debug option set for receive packet\n"
+ "Debug option set for send packet\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_area_topology_router_cmd_vtysh,
+ "show ipv6 ospf6 area A.B.C.D topology (A.B.C.D|<0-4294967295>|detail)",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Area information\n"
+ "Area ID (as an IPv4 notation)\n"
+ "Shortest Path First tree information\n"
+ "Displays SPF topology table\n"
+ "Specify Router-ID\n"
+ "Specify Router-ID\n"
+ )
+
+DEFSH (VTYSH_OSPFD, no_router_id_cmd_vtysh,
+ "no router-id",
+ "Negate a command or set its defaults\n"
+ "router-id for the OSPF process\n")
+
+DEFSH (VTYSH_BGPD, set_ipv6_nexthop_global_cmd_vtysh,
+ "set ipv6 next-hop global X:X::X:X",
+ "Set values in destination routing protocol\n"
+ "IPv6 information\n"
+ "IPv6 next-hop address\n"
+ "IPv6 global address\n"
+ "IPv6 address of next hop\n")
+
+DEFSH (VTYSH_RIPNGD, no_debug_ripng_packet_direct_cmd_vtysh,
+ "no debug ripng packet (recv|send)",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "RIPng configuration\n"
+ "Debug option set for ripng packet\n"
+ "Debug option set for receive packet\n"
+ "Debug option set for send packet\n")
+
+DEFSH (VTYSH_RIPD, send_lifetime_infinite_month_day_cmd_vtysh,
+ "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> infinite",
+ "Set send lifetime of the key\n"
+ "Time to start\n"
+ "Month of the year to start\n"
+ "Day of th month to start\n"
+ "Year to start\n"
+ "Never expires")
+
+DEFSH (VTYSH_BGPD, no_set_local_pref_val_cmd_vtysh,
+ "no set local-preference <0-4294967295>",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "BGP local preference path attribute\n"
+ "Preference value\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_ospf6_cmd_vtysh,
+ "redistribute ospf6",
+ "Redistribute information from another routing protocol\n"
+ "IPv6 Open Shortest Path First (OSPFv3)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_any_any_cmd_vtysh,
+ "access-list (<100-199>|<2000-2699>) (deny|permit) ip any any",
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Any source host\n"
+ "Any destination host\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_local_as_val_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as <1-65535>",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Specify a local-as number\n"
+ "AS number used as local AS\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_mask_host_cmd_vtysh,
+ "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D host A.B.C.D",
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Source address\n"
+ "Source wildcard bits\n"
+ "A single destination host\n"
+ "Destination address\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_name_cmd_vtysh,
+ "show ip prefix-list WORD",
+ "Show running system information\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n")
+
+DEFSH (VTYSH_ZEBRA, show_ipv6_route_prefix_cmd_vtysh,
+ "show ipv6 route X:X::X:X/M",
+ "Show running system information\n"
+ "IP information\n"
+ "IPv6 routing table\n"
+ "IPv6 prefix\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_vpnv4_soft_cmd_vtysh,
+ "clear ip bgp A.B.C.D vpnv4 unicast soft",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "Address family\n"
+ "Address Family Modifier\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_next_hop_cmd_vtysh,
+ "no match ip next-hop",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "IP information\n"
+ "Match next-hop address of route\n")
+
+DEFSH (VTYSH_OSPF6D, ospf6_routemap_no_set_forwarding_cmd_vtysh,
+ "no set forwarding-address X:X::X:X",
+ "Negate a command or set its defaults\n"
+ "Set value\n"
+ "Forwarding Address\n"
+ "IPv6 Address\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community2_cmd_vtysh,
+ "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "MBGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_OSPFD, no_area_range_cost_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M cost <0-16777215>",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Configure OSPF area range for route summarization\n"
+ "area range prefix\n"
+ "User specified metric for this range\n"
+ "Advertised metric for this range\n")
+
+DEFSH (VTYSH_RIPD, ip_rip_authentication_key_chain_cmd_vtysh,
+ "ip rip authentication key-chain LINE",
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Authentication control\n"
+ "Authentication key-chain\n"
+ "name of key-chain\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_distribute_list_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "distribute-list (<1-199>|<1300-2699>|WORD) (in|out)",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Filter updates to/from this neighbor\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n"
+ "Filter incoming updates\n"
+ "Filter outgoing updates\n")
+
+DEFSH (VTYSH_ZEBRA, show_table_cmd_vtysh,
+ "show table",
+ "Show running system information\n"
+ "default routing table to use for all clients\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv6_metric_cmd_vtysh,
+ "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPFv3)\n"
+ "Routing Information Protocol (RIPng)\n"
+ "Static routes\n"
+ "Metric for redistributed routes\n"
+ "Default metric\n")
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_authkey_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication-key|)",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Authentication password (key)\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_cmd_vtysh,
+ "show ipv6 prefix-list",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "Build a prefix list\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_prefix_longer_cmd_vtysh,
+ "show ip prefix-list WORD A.B.C.D/M longer",
+ "Show running system information\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Lookup longer prefix\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_inter_intra_external_cmd_vtysh,
+ "distance ospf inter-area <1-255> intra-area <1-255> external <1-255>",
+ "Define an administrative distance\n"
+ "OSPF Administrative distance\n"
+ "Inter-area routes\n"
+ "Distance for inter-area routes\n"
+ "Intra-area routes\n"
+ "Distance for intra-area routes\n"
+ "External routes\n"
+ "Distance for external routes\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_bestpath_med3_cmd_vtysh,
+ "no bgp bestpath med missing-as-worst confed",
+ "Negate a command or set its defaults\n"
+ "BGP specific commands\n"
+ "Change the default bestpath selection\n"
+ "MED attribute\n"
+ "Treat missing MED as the least preferred one\n"
+ "Compare MED among confederation paths\n")
+
+DEFSH (VTYSH_RIPNGD, debug_ripng_packet_direct_cmd_vtysh,
+ "debug ripng packet (recv|send)",
+ "Debugging functions (see also 'undebug')\n"
+ "RIPng configuration\n"
+ "Debug option set for ripng packet\n"
+ "Debug option set for receive packet\n"
+ "Debug option set for send packet\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_soft_in_cmd_vtysh,
+ "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_ZEBRA, ip_address_secondary_cmd_vtysh,
+ "ip address A.B.C.D/M secondary",
+ "Interface Internet Protocol config commands\n"
+ "Set the IP address of an interface\n"
+ "IP address (e.g. 10.0.0.1/8)\n"
+ "Secondary IP address\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_soft_out_cmd_vtysh,
+ "clear ip bgp * soft out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_neighbor_received_prefix_filter_cmd_vtysh,
+ "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display information received from a BGP neighbor\n"
+ "Display the prefixlist filter\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_ipv4_soft_cmd_vtysh,
+ "clear ip bgp * ipv4 (unicast|multicast) soft",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Address family\n"
+ "Address Family Modifier\n"
+ "Address Family Modifier\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_ipv4_soft_out_cmd_vtysh,
+ "clear ip bgp * ipv4 (unicast|multicast) soft out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD, accept_lifetime_day_month_day_month_cmd_vtysh,
+ "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>",
+ "Set accept lifetime of the key\n"
+ "Time to start\n"
+ "Day of th month to start\n"
+ "Month of the year to start\n"
+ "Year to start\n"
+ "Time to expire\n"
+ "Day of th month to expire\n"
+ "Month of the year to expire\n"
+ "Year to expire\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_cluster_id_cmd_vtysh,
+ "no bgp cluster-id",
+ "Negate a command or set its defaults\n"
+ "BGP information\n"
+ "Configure Route-Reflector Cluster-id\n")
+
+DEFSH (VTYSH_BGPD, neighbor_maximum_prefix_warning_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X) " "maximum-prefix <1-4294967295> warning-only",
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Maximum number of prefix accept from this peer\n"
+ "maximum no. of prefix limit\n"
+ "Only give warning message when limit is exceeded\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_OSPFD, no_area_stub_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) stub",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Configure OSPF area as stub\n")
+
+DEFSH (VTYSH_ZEBRA, no_debug_zebra_events_cmd_vtysh,
+ "no debug zebra events",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "Zebra configuration\n"
+ "Debug option set for zebra events\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_in_cmd_vtysh,
+ "clear bgp ipv6 peer-group WORD in",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_prefix_list_cmd_vtysh,
+ "show ipv6 bgp prefix-list WORD",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Display routes matching the prefix-list\n"
+ "IPv6 prefix-list name\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_distance2_cmd_vtysh,
+ "no distance bgp",
+ "Negate a command or set its defaults\n"
+ "Define an administrative distance\n"
+ "BGP distance\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_in_cmd_vtysh,
+ "clear bgp ipv6 external WORD in",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all external peers\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, no_set_aggregator_as_val_cmd_vtysh,
+ "no set aggregator as <1-65535> A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "BGP aggregator attribute\n"
+ "AS number of aggregator\n"
+ "AS number\n"
+ "IP address of aggregator\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_metric_type_routemap_cmd_vtysh,
+ "default-information originate metric <0-16777214> metric-type (1|2) route-map WORD",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "OSPF default metric\n"
+ "OSPF metric\n"
+ "OSPF metric type for default routes\n"
+ "Set OSPF External Type 1 metrics\n"
+ "Set OSPF External Type 2 metrics\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, ip_community_list_name_standard_cmd_vtysh,
+ "ip community-list standard WORD (deny|permit) .AA:NN",
+ "IP information\n"
+ "Add a community list entry\n"
+ "Add a standard community-list entry\n"
+ "Community list name\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n"
+ "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_database_type_self_cmd_vtysh,
+ "show ip ospf database (" "asbr-summary|external|network|router|summary" "" "" ") (self-originate|)",
+ "Show running system information\n"
+ "IP information\n"
+ "OSPF information\n"
+ "Database summary\n"
+ "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "" "" "" ""
+ "Self-originated link states\n")
+
+DEFSH (VTYSH_BGPD, bgp_router_id_cmd_vtysh,
+ "bgp router-id A.B.C.D",
+ "BGP information\n"
+ "Override configured router identifier\n"
+ "Manually configured router identifier\n")
+
+DEFSH (VTYSH_ZEBRA, show_ip_forwarding_cmd_vtysh,
+ "show ip forwarding",
+ "Show running system information\n"
+ "IP information\n"
+ "IP forwarding status\n")
+
+DEFSH (VTYSH_BGPD, ip_community_list_standard_cmd_vtysh,
+ "ip community-list <1-99> (deny|permit) .AA:NN",
+ "IP information\n"
+ "Add a community list entry\n"
+ "Community list number (standard)\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n"
+ "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n")
+
+DEFSH (VTYSH_ZEBRA, no_multicast_cmd_vtysh,
+ "no multicast",
+ "Negate a command or set its defaults\n"
+ "Unset multicast flag to interface\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_instance_ipv4_summary_cmd_vtysh,
+ "show ip bgp view WORD ipv4 (unicast|multicast) summary",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP view\n"
+ "View name\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_soft_cmd_vtysh,
+ "clear bgp (A.B.C.D|X:X::X:X) soft",
+ "Reset functions\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "BGP IPv6 neighbor to clear\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_cmd_vtysh,
+ "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Source address\n"
+ "Source wildcard bits\n"
+ "Destination address\n"
+ "Destination Wildcard bits\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_filter_list_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) filter-list WORD",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes conforming to the filter-list\n"
+ "Regular expression access list name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_summary_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) summary",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_RIPD, no_rip_redistribute_type_metric_routemap_cmd_vtysh,
+ "no redistribute (kernel|connected|static|ospf|bgp) metric <0-16> route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Open Shortest Path First (OSPF)\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Metric\n"
+ "Metric value\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_ipv4_soft_cmd_vtysh,
+ "clear ip bgp external ipv4 (unicast|multicast) soft",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all external peers\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_soft_out_cmd_vtysh,
+ "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft out",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "BGP neighbor address to clear\n"
+ "BGP IPv6 neighbor to clear\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_route_cmd_vtysh,
+ "show ip ospf route",
+ "Show running system information\n"
+ "IP information\n"
+ "OSPF information\n"
+ "OSPF routing table\n")
+
+DEFSH (VTYSH_OSPFD, interface_ip_ospf_authentication_args_addr_cmd_vtysh,
+ "ip ospf authentication (null|message-digest) A.B.C.D",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Enable authentication on this interface\n"
+ "Use null authentication\n"
+ "Use message-digest authentication\n"
+ "Address of interface")
+
+DEFSH (VTYSH_OSPFD, area_vlink_authtype_args_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication|) (message-digest|null)",
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Enable authentication on this virtual link\n" "dummy string \n" "Use null authentication\n" "Use message-digest authentication\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_network_cmd_vtysh,
+ "no network A.B.C.D/M",
+ "Negate a command or set its defaults\n"
+ "Specify a network to announce via BGP\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, no_ip_as_path_cmd_vtysh,
+ "no ip as-path access-list WORD (deny|permit) .LINE",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "BGP autonomous system path filter\n"
+ "Specify an access list name\n"
+ "Regular expression access list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "A regular-expression to match the BGP AS paths\n")
+
+DEFSH (VTYSH_BGPD, neighbor_distribute_list_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "distribute-list (<1-199>|<1300-2699>|WORD) (in|out)",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Filter updates to/from this neighbor\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n"
+ "Filter incoming updates\n"
+ "Filter outgoing updates\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_le_ge_cmd_vtysh,
+ "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32> ge <0-32>",
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ipv6_access_list_all_cmd_vtysh,
+ "no ipv6 access-list WORD",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n")
+
+DEFSH (VTYSH_BGPD, ip_community_list_name_expanded_cmd_vtysh,
+ "ip community-list expanded WORD (deny|permit) .LINE",
+ "IP information\n"
+ "Add a community list entry\n"
+ "Add an expanded community-list entry\n"
+ "Community list name\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n"
+ "An ordered list as a regular-expression\n")
+
+DEFSH (VTYSH_BGPD, neighbor_timers_connect_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X) " "timers connect <0-65535>",
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "BGP per neighbor timers\n"
+ "BGP connect timer\n"
+ "Connect timer\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_address_cmd_vtysh,
+ "ipv6 address X:X::X:X/M",
+ "Interface Internet Protocol config commands\n"
+ "Set the IP address of an interface\n"
+ "IPv6 address (e.g. 3ffe:506::1/48)\n")
+
+DEFSH (VTYSH_BGPD, ip_community_list_expanded_cmd_vtysh,
+ "ip community-list <100-199> (deny|permit) .LINE",
+ "IP information\n"
+ "Add a community list entry\n"
+ "Community list number (expanded)\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n"
+ "An ordered list as a regular-expression\n")
+
+DEFSH (VTYSH_RIPD, rip_offset_list_ifname_cmd_vtysh,
+ "offset-list WORD (in|out) <0-16> IFNAME",
+ "Modify RIP metric\n"
+ "Access-list name\n"
+ "For incoming updates\n"
+ "For outgoing updates\n"
+ "Metric value\n"
+ "Interface to match\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_prefix_longer_cmd_vtysh,
+ "show ipv6 mbgp X:X::X:X/M longer-prefixes",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "MBGP information\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Display route and more specific routes\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_ism_sub_cmd_vtysh,
+ "debug ospf ism (status|events|timers)",
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n"
+ "OSPF Interface State Machine\n"
+ "ISM Status Information\n"
+ "ISM Event Information\n"
+ "ISM TImer Information\n")
+
+DEFSH (VTYSH_BGPD, neighbor_send_community_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Send Community attribute to this neighbor\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_route_map_cmd_vtysh,
+ "show bgp route-map WORD",
+ "Show running system information\n"
+ "BGP information\n"
+ "Display routes matching the route-map\n"
+ "A route-map to match on\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_route_cmd_vtysh,
+ "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display VPNv4 NLRI specific information\n"
+ "Display information for a route distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "Network in the BGP routing table to display\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_route_ifname_pref_cmd_vtysh,
+ "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Distance value for this prefix\n")
+
+DEFSH (VTYSH_BGPD, dump_bgp_updates_interval_cmd_vtysh,
+ "dump bgp updates PATH INTERVAL",
+ "Dump packet\n"
+ "BGP packet dump\n"
+ "Dump BGP updates only\n"
+ "Output filename\n"
+ "Interval of output\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_confederation_identifier_arg_cmd_vtysh,
+ "no bgp confederation identifier <1-65535>",
+ "Negate a command or set its defaults\n"
+ "BGP specific commands\n"
+ "AS confederation parameters\n"
+ "AS number\n"
+ "Set routing domain confederation AS\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_database_type_cmd_vtysh,
+ "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*|dump|summary)",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "LSA Database\n"
+ "Router-LSA\n"
+ "Network-LSA\n"
+ "AS-External-LSA\n"
+ "Intra-Area-Prefix-LSA\n"
+ "Inter-Area-Router-LSA\n"
+ "Inter-Area-Prefix-LSA\n"
+ "Link-LSA\n"
+ "All LS Type\n"
+ "Dump raw LSA data in Hex\n"
+ "show summary of LSA\n"
+ )
+
+DEFSH (VTYSH_BGPD, no_neighbor_route_server_client_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "route-server-client",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Configure a neighbor as Route Server client\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community_all_cmd_vtysh,
+ "show ip bgp community",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n")
+
+DEFSH (VTYSH_OSPFD, ospf_message_digest_key_cmd_vtysh,
+ "ospf message-digest-key <1-255> md5 KEY",
+ "OSPF interface commands\n"
+ "Message digest authentication password (key)\n"
+ "Key ID\n"
+ "Use MD5 algorithm\n"
+ "The OSPF password (key)")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_ipv4_soft_in_cmd_vtysh,
+ "clear ip bgp * ipv4 (unicast|multicast) soft in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_in_prefix_filter_cmd_vtysh,
+ "clear bgp ipv6 (A.B.C.D|X:X::X:X) in prefix-filter",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "BGP neighbor address to clear\n"
+ "BGP IPv6 neighbor to clear\n"
+ "Soft reconfig inbound update\n"
+ "Push out the existing ORF prefix-list\n")
+
+DEFSH (VTYSH_BGPD, no_match_community_cmd_vtysh,
+ "no match community",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "Match BGP community list\n")
+
+DEFSH (VTYSH_RIPD, rip_redistribute_type_metric_cmd_vtysh,
+ "redistribute (kernel|connected|static|ospf|bgp) metric <0-16>",
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Open Shortest Path First (OSPF)\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Metric\n"
+ "Metric value\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_summary_cmd_vtysh,
+ "show ip bgp vpnv4 all summary",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display VPNv4 NLRI specific information\n"
+ "Display information about all VPNv4 NLRIs\n"
+ "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community2_exact_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_regexp_cmd_vtysh,
+ "show ipv6 mbgp regexp .LINE",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display routes matching the AS path regular expression\n"
+ "A regular-expression to match the MBGP AS paths\n")
+
+DEFSH (VTYSH_BGPD, no_set_community_delete_cmd_vtysh,
+ "no set comm-list",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "set BGP community list (for deletion)\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_zebra_cmd_vtysh,
+ "no debug ospf zebra",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n"
+ "OSPF Zebra information\n")
+
+DEFSH (VTYSH_ZEBRA, debug_zebra_packet_cmd_vtysh,
+ "debug zebra packet",
+ "Debugging functions (see also 'undebug')\n"
+ "Zebra configuration\n"
+ "Debug option set for zebra packet\n")
+
+DEFSH (VTYSH_RIPD, no_rip_redistribute_rip_cmd_vtysh,
+ "no redistribute rip",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Routing Information Protocol (RIP)\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_metric_type_cmd_vtysh,
+ "default-information originate metric <0-16777214> metric-type (1|2)",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "OSPF default metric\n"
+ "OSPF metric\n"
+ "OSPF metric type for default routes\n"
+ "Set OSPF External Type 1 metrics\n"
+ "Set OSPF External Type 2 metrics\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_ipv4_out_cmd_vtysh,
+ "clear ip bgp * ipv4 (unicast|multicast) out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD, no_rip_version_cmd_vtysh,
+ "no version",
+ "Negate a command or set its defaults\n"
+ "Set routing protocol version\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_area_topology_cmd_vtysh,
+ "show ipv6 ospf6 area A.B.C.D topology",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Area information\n"
+ "Area ID (as an IPv4 notation)\n"
+ "Shortest Path First tree information\n"
+ "Displays SPF topology table\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_match_metric_val_cmd_vtysh,
+ "no match metric <0-4294967295>",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "Match metric of route\n"
+ "Metric value\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_flap_prefix_cmd_vtysh,
+ "show ip bgp flap-statistics A.B.C.D/M",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display flap statistics of routes\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, bgp_always_compare_med_cmd_vtysh,
+ "bgp always-compare-med",
+ "BGP specific commands\n"
+ "Allow comparing MED from different neighbors\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_instance_all_soft_out_cmd_vtysh,
+ "clear bgp view WORD * soft out",
+ "Reset functions\n"
+ "BGP information\n"
+ "BGP view\n"
+ "view name\n"
+ "Clear all peers\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_param2_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval)",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_neighbor_advertised_route_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display the routes advertised to a BGP neighbor\n")
+
+DEFSH (VTYSH_RIPD, rip_offset_list_cmd_vtysh,
+ "offset-list WORD (in|out) <0-16>",
+ "Modify RIP metric\n"
+ "Access-list name\n"
+ "For incoming updates\n"
+ "For outgoing updates\n"
+ "Metric value\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_out_cmd_vtysh,
+ "clear bgp ipv6 <1-65535> out",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear peers with the AS number\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, dump_bgp_routes_cmd_vtysh,
+ "dump bgp routes-mrt PATH",
+ "Dump packet\n"
+ "BGP packet dump\n"
+ "Dump whole BGP routing table\n"
+ "Output filename\n")
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_authtype_md5_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication|) "
+ "(message-digest-key|)",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Enable authentication on this virtual link\n" "dummy string \n"
+ "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_OSPF6D, no_ipv6_ospf6_advertise_prefix_list_cmd_vtysh,
+ "no ipv6 ospf6 advertise prefix-list",
+ "Negate a command or set its defaults\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Advertising options\n"
+ "Filter prefix using prefix-list\n"
+ )
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_route_ospf6_external_cmd_vtysh,
+ "show ipv6 ospf6 route redistribute",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Routing Table\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "redistributing External information\n"
+ )
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd_vtysh,
+ "show ip bgp vpnv4 all neighbors A.B.C.D advertised-routes",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display VPNv4 NLRI specific information\n"
+ "Display information about all VPNv4 NLRIs\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Display the routes advertised to a BGP neighbor\n")
+
+DEFSH (VTYSH_RIPD, rip_passive_interface_cmd_vtysh,
+ "passive-interface IFNAME",
+ "Suppress routing updates on an interface\n"
+ "Interface name\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_lsa_cmd_vtysh,
+ "no debug ospf lsa",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n"
+ "OSPF Link State Advertisement\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_network_cmd_vtysh,
+ "no network IF_OR_ADDR",
+ "Negate a command or set its defaults\n"
+ "RIPng enable on specified interface or network.\n"
+ "Interface or address")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_metric_type_cmd_vtysh,
+ "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> metric-type (1|2)",
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Routing Information Protocol (RIP)\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Metric for redistributed routes\n"
+ "OSPF default metric\n"
+ "OSPF exterior metric type for redistributed routes\n"
+ "Set OSPF External Type 1 metrics\n"
+ "Set OSPF External Type 2 metrics\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_external_soft_out_cmd_vtysh,
+ "clear bgp external soft out",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all external peers\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_name_standard_cmd_vtysh,
+ "no ip extcommunity-list standard WORD (deny|permit) .AA:NN",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Add a extended community list entry\n"
+ "Specify standard extcommunity-list\n"
+ "Extended Community list name\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n"
+ "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_default_metric_cmd_vtysh,
+ "no default-metric",
+ "Negate a command or set its defaults\n"
+ "Set metric of redistributed routes\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_paths_cmd_vtysh,
+ "show ip bgp paths",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Path information\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_neighbor_advertised_route_cmd_vtysh,
+ "show ip bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display the routes advertised to a BGP neighbor\n")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_type_cmd_vtysh,
+ "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2)",
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Routing Information Protocol (RIP)\n"
+ "Border Gateway Protocol (BGP)\n"
+ "OSPF exterior metric type for redistributed routes\n"
+ "Set OSPF External Type 1 metrics\n"
+ "Set OSPF External Type 2 metrics\n")
+
+DEFSH (VTYSH_BGPD, match_ipv6_next_hop_cmd_vtysh,
+ "match ipv6 next-hop X:X::X:X",
+ "Match values from routing table\n"
+ "IPv6 information\n"
+ "Match IPv6 next-hop address of route\n"
+ "IPv6 address of next hop\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_transmit_delay_cmd_vtysh,
+ "ip ospf transmit-delay <1-65535>",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Link state transmit delay\n"
+ "Seconds\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_vpnv4_soft_in_cmd_vtysh,
+ "clear ip bgp <1-65535> vpnv4 unicast soft in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD, rip_redistribute_type_routemap_cmd_vtysh,
+ "redistribute (kernel|connected|static|ospf|bgp) route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Open Shortest Path First (OSPF)\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_filter_list_cmd_vtysh,
+ "show ipv6 bgp filter-list WORD",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Display routes conforming to the filter-list\n"
+ "Regular expression access list name\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_instance_ipv6_summary_cmd_vtysh,
+ "show bgp view WORD ipv6 summary",
+ "Show running system information\n"
+ "BGP information\n"
+ "BGP view\n"
+ "View name\n"
+ "Address family\n"
+ "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_nd_ra_lifetime_cmd_vtysh,
+ "no ipv6 nd ra-lifetime",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Neighbor discovery\n"
+ "Router lifetime\n")
+
+DEFSH (VTYSH_OSPFD, no_area_export_list_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) export-list NAME",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Unset the filter for networks announced to other areas\n"
+ "Name of the access-list\n")
+
+DEFSH (VTYSH_BGPD, bgp_distance_source_cmd_vtysh,
+ "distance <1-255> A.B.C.D/M",
+ "Define an administrative distance\n"
+ "Administrative distance\n"
+ "IP source prefix\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_neighbor_received_prefix_filter_cmd_vtysh,
+ "show ip bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display information received from a BGP neighbor\n"
+ "Display the prefixlist filter\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_neighbor_routes_cmd_vtysh,
+ "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display routes learned from neighbor\n")
+
+DEFSH (VTYSH_BGPD, no_set_origin_cmd_vtysh,
+ "no set origin",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "BGP origin code\n")
+
+DEFSH (VTYSH_BGPD, no_set_community_delete_val_cmd_vtysh,
+ "no set comm-list (<1-99>|<100-199>|WORD) delete",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "set BGP community list (for deletion)\n"
+ "Community-list number (standard)\n"
+ "Communitly-list number (expanded)\n"
+ "Community-list name\n"
+ "Delete matching communities\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_bestpath_aspath_ignore_cmd_vtysh,
+ "no bgp bestpath as-path ignore",
+ "Negate a command or set its defaults\n"
+ "BGP specific commands\n"
+ "Change the default bestpath selection\n"
+ "AS-path attribute\n"
+ "Ignore as-path length in selecting a route\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community_exact_cmd_vtysh,
+ "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "MBGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_scan_cmd_vtysh,
+ "show ip bgp scan",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP scan status\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_nd_suppress_ra_cmd_vtysh,
+ "no ipv6 nd suppress-ra",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Neighbor discovery\n"
+ "Suppress Router Advertisement\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_cluster_id_arg_cmd_vtysh,
+ "no bgp cluster-id A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "BGP information\n"
+ "Configure Route-Reflector Cluster-id\n"
+ "Route-Reflector Cluster-id in IP address format\n")
+
+DEFSH (VTYSH_OSPFD, no_area_shortcut_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) shortcut (enable|disable)",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Deconfigure the area's shortcutting mode\n"
+ "Deconfigure enabled shortcutting through the area\n"
+ "Deconfigure disabled shortcutting through the area\n")
+
+DEFSH (VTYSH_OSPF6D, interface_area_passive_cmd_vtysh,
+ "interface IFNAME area A.B.C.D passive",
+ "Enable routing on an IPv6 interface\n"
+ "Interface name(e.g. ep0)\n"
+ "Set the OSPF6 area ID\n"
+ "OSPF6 area ID in IPv4 address notation\n"
+ "Suppress routing updates on an interface\n"
+ )
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_database_type_id_cmd_vtysh,
+ "show ip ospf database (" "asbr-summary|external|network|router|summary" "" "" ") A.B.C.D",
+ "Show running system information\n"
+ "IP information\n"
+ "OSPF information\n"
+ "Database summary\n"
+ "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "" "" "" ""
+ "Link State ID (as an IP address)\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_confederation_peers_cmd_vtysh,
+ "no bgp confederation peers .<1-65535>",
+ "Negate a command or set its defaults\n"
+ "BGP specific commands\n"
+ "AS confederation parameters\n"
+ "Peer ASs in BGP confederation\n"
+ "AS number\n")
+
+DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_name_expanded_cmd_vtysh,
+ "no ip extcommunity-list expanded WORD (deny|permit) .LINE",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Add a extended community list entry\n"
+ "Specify expanded extcommunity-list\n"
+ "Community list name\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n"
+ "An ordered list as a regular-expression\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community_list_exact_cmd_vtysh,
+ "show bgp community-list WORD exact-match",
+ "Show running system information\n"
+ "BGP information\n"
+ "Display routes matching the community-list\n"
+ "community-list name\n"
+ "Exact match of the communities\n")
+
+DEFSH (VTYSH_BGPD, ipv6_bgp_neighbor_received_routes_cmd_vtysh,
+ "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) received-routes",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display the received routes from neighbor\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_hello_interval_cmd_vtysh,
+ "no ospf hello-interval",
+ "Negate a command or set its defaults\n"
+ "OSPF interface commands\n"
+ "Time between HELLO packets\n")
+
+DEFSH (VTYSH_BGPD, no_set_weight_cmd_vtysh,
+ "no set weight",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "BGP weight for routing table\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_neighbor_int_detail_cmd_vtysh,
+ "show ip ospf neighbor A.B.C.D detail",
+ "Show running system information\n"
+ "IP information\n"
+ "OSPF information\n"
+ "Neighbor list\n"
+ "Interface address\n"
+ "detail of all neighbors")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community_list_cmd_vtysh,
+ "show bgp ipv6 community-list WORD",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Display routes matching the community-list\n"
+ "community-list name\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_group_in_prefix_filter_cmd_vtysh,
+ "clear bgp peer-group WORD in prefix-filter",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Soft reconfig inbound update\n"
+ "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, set_ecommunity_rt_cmd_vtysh,
+ "set extcommunity rt .ASN:nn_or_IP-address:nn",
+ "Set values in destination routing protocol\n"
+ "BGP extended community attribute\n"
+ "Route Target extened communityt\n"
+ "VPN extended community\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_description_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "description",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Neighbor specific description\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_seq_le_cmd_vtysh,
+ "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32>",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_md5_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(message-digest-key|) <1-255> md5 KEY",
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_forwarding_cmd_vtysh,
+ "no ipv6 forwarding",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Doesn't forward IPv6 protocol packet")
+
+DEFSH (VTYSH_BGPD, show_bgp_community_cmd_vtysh,
+ "show bgp community (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_OSPFD, ospf_router_id_cmd_vtysh,
+ "ospf router-id A.B.C.D",
+ "OSPF specific commands\n"
+ "router-id for the OSPF process\n"
+ "OSPF router-id in IP address format\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community_exact_cmd_vtysh,
+ "show bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, no_neighbor_capability_orf_prefix_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "capability orf prefix-list (both|send|receive)",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Advertise capability to the peer\n"
+ "Advertise ORF capability to the peer\n"
+ "Advertise prefixlist ORF capability to this neighbor\n"
+ "Capability to SEND and RECEIVE the ORF to/from this neighbor\n"
+ "Capability to RECEIVE the ORF from this neighbor\n"
+ "Capability to SEND the ORF to this neighbor\n")
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_hello_interval_addr_cmd_vtysh,
+ "ip ospf hello-interval <1-65535> A.B.C.D",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Time between HELLO packets\n"
+ "Seconds\n"
+ "Address of interface")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_mask_summary_only_cmd_vtysh,
+ "no aggregate-address A.B.C.D A.B.C.D summary-only",
+ "Negate a command or set its defaults\n"
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n"
+ "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_external_intra_cmd_vtysh,
+ "distance ospf external <1-255> intra-area <1-255>",
+ "Define an administrative distance\n"
+ "OSPF Administrative distance\n"
+ "External routes\n"
+ "Distance for external routes\n"
+ "Intra-area routes\n"
+ "Distance for intra-area routes\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_param3_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>",
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n")
+
+DEFSH (VTYSH_BGPD, neighbor_soft_reconfiguration_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "soft-reconfiguration inbound",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Per neighbor soft reconfiguration\n"
+ "Allow inbound soft reconfiguration for this neighbor\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ipv6_access_list_exact_cmd_vtysh,
+ "no ipv6 access-list WORD (deny|permit) X:X::X:X/M exact-match",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 3ffe:506::/32\n"
+ "Exact match of the prefixes\n")
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv4_metric_rmap_cmd_vtysh,
+ "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPF)\n"
+ "Routing Information Protocol (RIP)\n"
+ "Static routes\n"
+ "Metric for redistributed routes\n"
+ "Default metric\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_in_prefix_filter_cmd_vtysh,
+ "clear ip bgp external in prefix-filter",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all external peers\n"
+ "Soft reconfig inbound update\n"
+ "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv6_cmd_vtysh,
+ "no redistribute (connected|kernel|ospf6|ripng|static)",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPFv3)\n"
+ "Routing Information Protocol (RIPng)\n"
+ "Static routes\n")
+
+DEFSH (VTYSH_ZEBRA, show_ipv6_route_cmd_vtysh,
+ "show ipv6 route",
+ "Show running system information\n"
+ "IP information\n"
+ "IPv6 routing table\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_fast_external_failover_cmd_vtysh,
+ "no bgp fast-external-failover",
+ "Negate a command or set its defaults\n"
+ "BGP information\n"
+ "Immediately reset session if a link to a directly connected external peer goes down\n")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_mask_as_set_summary_cmd_vtysh,
+ "no aggregate-address A.B.C.D A.B.C.D as-set summary-only",
+ "Negate a command or set its defaults\n"
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n"
+ "Generate AS set path information\n"
+ "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_soft_out_cmd_vtysh,
+ "clear ip bgp external soft out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all external peers\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_summary_cmd_vtysh,
+ "show bgp ipv6 summary",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_regexp_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) regexp .LINE",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the AS path regular expression\n"
+ "A regular-expression to match the BGP AS paths\n")
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_authtype_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication|)",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Enable authentication on this virtual link\n" "dummy string \n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_vpnv4_out_cmd_vtysh,
+ "clear ip bgp * vpnv4 unicast out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Address family\n"
+ "Address Family Modifier\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_ZEBRA, no_ip_address_label_cmd_vtysh,
+ "no ip address A.B.C.D/M label LINE",
+ "Negate a command or set its defaults\n"
+ "Interface Internet Protocol config commands\n"
+ "Set the IP address of an interface\n"
+ "IP address (e.g. 10.0.0.1/8)\n"
+ "Label of this address\n"
+ "Label\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged7_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop med as-path",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "Nexthop attribute\n"
+ "Med attribute\n"
+ "As-path attribute\n")
+
+DEFSH (VTYSH_BGPD, no_ipv6_bgp_network_route_map_cmd_vtysh,
+ "no network X:X::X:X/M route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Specify a network to announce via BGP\n"
+ "IPv6 prefix <network>/<length>\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_ipv4_soft_cmd_vtysh,
+ "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "Address family\n"
+ "Address Family Modifier\n"
+ "Address Family Modifier\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, neighbor_ebgp_multihop_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "ebgp-multihop",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Allow EBGP neighbors not on directly connected networks\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_authentication_key_cmd_vtysh,
+ "no ip ospf authentication-key",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Authentication password (key)\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_neighbor_routes_cmd_vtysh,
+ "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display VPNv4 NLRI specific information\n"
+ "Display information for a route distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Display routes learned from neighbor\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_ism_sub_cmd_vtysh,
+ "no debug ospf ism (status|events|timers)",
+ "Negate a command or set its defaults\n"
+ "Debugging functions\n"
+ "OSPF information\n"
+ "OSPF Interface State Machine\n"
+ "ISM Status Information\n"
+ "ISM Event Information\n"
+ "ISM Timer Information\n")
+
+DEFSH (VTYSH_OSPFD, refresh_timer_cmd_vtysh,
+ "refresh timer <10-1800>",
+ "Adjust refresh parameters\n"
+ "Set refresh timer\n"
+ "Timer value in seconds\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_nd_managed_config_flag_cmd_vtysh,
+ "ipv6 nd managed-config-flag",
+ "IP information\n"
+ "Neighbor discovery\n"
+ "Managed address configuration flag\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_intra_inter_cmd_vtysh,
+ "distance ospf intra-area <1-255> inter-area <1-255>",
+ "Define an administrative distance\n"
+ "OSPF Administrative distance\n"
+ "Intra-area routes\n"
+ "Distance for intra-area routes\n"
+ "Inter-area routes\n"
+ "Distance for inter-area routes\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_ospf6_metric_val_cmd_vtysh,
+ "no redistribute ospf6 metric <0-16>",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "IPv6 Open Shortest Path First (OSPFv3)\n"
+ "Metric\n"
+ "Metric value\n")
+
+DEFSH (VTYSH_BGPD, no_set_ipv6_nexthop_local_val_cmd_vtysh,
+ "no set ipv6 next-hop local X:X::X:X",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "IPv6 information\n"
+ "IPv6 next-hop address\n"
+ "IPv6 local address\n"
+ "IPv6 address of next hop\n")
+
+DEFSH (VTYSH_BGPD, ip_community_list_name_standard2_cmd_vtysh,
+ "ip community-list standard WORD (deny|permit)",
+ "IP information\n"
+ "Add a community list entry\n"
+ "Add a standard community-list entry\n"
+ "Community list name\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_capability_route_refresh_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "capability route-refresh",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Advertise capability to the peer\n"
+ "Advertise route-refresh capability to this neighbor\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_cmd_vtysh,
+ "no access-list WORD (deny|permit) A.B.C.D/M",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP zebra access-list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 10.0.0.0/8\n")
+
+DEFSH (VTYSH_ZEBRA, show_zebra_client_cmd_vtysh,
+ "show zebra client",
+ "Show running system information\n"
+ "Zebra information"
+ "Client information")
+
+DEFSH (VTYSH_BGPD, neighbor_allowas_in_arg_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "allowas-in <1-10>",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Accept as-path with my AS present in it\n"
+ "Number of occurances of AS number\n")
+
+DEFSH (VTYSH_BGPD, bgp_cluster_id_cmd_vtysh,
+ "bgp cluster-id A.B.C.D",
+ "BGP information\n"
+ "Configure Route-Reflector Cluster-id\n"
+ "Route-Reflector Cluster-id in IP address format\n")
+
+DEFSH (VTYSH_BGPD, no_router_bgp_view_cmd_vtysh,
+ "no router bgp <1-65535> view WORD",
+ "Negate a command or set its defaults\n"
+ "Enable a routing process\n"
+ "BGP information\n"
+ "AS number\n"
+ "BGP view\n"
+ "view name\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_packet_send_recv_cmd_vtysh,
+ "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv|detail)",
+ "Negate a command or set its defaults\n"
+ "Debugging functions\n"
+ "OSPF information\n"
+ "OSPF packets\n"
+ "OSPF Hello\n"
+ "OSPF Database Description\n"
+ "OSPF Link State Request\n"
+ "OSPF Link State Update\n"
+ "OSPF Link State Acknowledgment\n"
+ "OSPF all packets\n"
+ "Packet sent\n"
+ "Packet received\n"
+ "Detail Information\n")
+
+DEFSH (VTYSH_BGPD, no_set_community_cmd_vtysh,
+ "no set community",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "BGP community attribute\n")
+
+DEFSH (VTYSH_OSPFD|VTYSH_OSPF6D, ospf6_routemap_no_set_metric_type_cmd_vtysh,
+ "no set metric-type (type-1|type-2)",
+ "Negate a command or set its defaults\n"
+ "Set value\n"
+ "Type of metric\n"
+ "OSPF6 external type 1 metric\n"
+ "OSPF6 external type 2 metric\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_name_seq_cmd_vtysh,
+ "show ip prefix-list WORD seq <1-4294967295>",
+ "Show running system information\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_soft_in_cmd_vtysh,
+ "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPFD, ospf_rfc1583_flag_cmd_vtysh,
+ "ospf rfc1583compatibility",
+ "OSPF specific commands\n"
+ "Enable the RFC1583Compatibility flag\n")
+
+DEFSH (VTYSH_ZEBRA, no_debug_zebra_packet_cmd_vtysh,
+ "no debug zebra packet",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "Zebra configuration\n"
+ "Debug option set for zebra packet\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community4_exact_cmd_vtysh,
+ "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_RIPD, ip_rip_authentication_mode_cmd_vtysh,
+ "ip rip authentication mode (md5|text)",
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Authentication control\n"
+ "Authentication mode\n"
+ "Keyed message digest\n"
+ "Clear text authentication\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_nd_send_ra_cmd_vtysh,
+ "no ipv6 nd send-ra",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Neighbor discovery\n"
+ "Send Router Advertisement\n")
+
+DEFSH (VTYSH_OSPFD, no_neighbor_pollinterval_cmd_vtysh,
+ "no neighbor A.B.C.D poll-interval <1-65535>",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor IP address\n"
+ "Dead Neighbor Polling interval\n"
+ "Seconds\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community_exact_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_soft_cmd_vtysh,
+ "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Address family\n"
+ "Address Family Modifier\n"
+ "Address Family Modifier\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_OSPFD, ospf_abr_type_cmd_vtysh,
+ "ospf abr-type (cisco|ibm|shortcut|standard)",
+ "OSPF specific commands\n"
+ "Set OSPF ABR type\n"
+ "Alternative ABR, cisco implementation\n"
+ "Alternative ABR, IBM implementation\n"
+ "Shortcut ABR\n"
+ "Standard behavior (RFC2328)\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_maximum_prefix_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X) " "maximum-prefix",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Maximum number of prefix accept from this peer\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_soft_cmd_vtysh,
+ "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "BGP neighbor address to clear\n"
+ "BGP IPv6 neighbor to clear\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_metric_type_cmd_vtysh,
+ "default-information originate always metric <0-16777214> metric-type (1|2)",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "Always advertise default route\n"
+ "OSPF default metric\n"
+ "OSPF metric\n"
+ "OSPF metric type for default routes\n"
+ "Set OSPF External Type 1 metrics\n"
+ "Set OSPF External Type 2 metrics\n")
+
+DEFSH (VTYSH_BGPD, neighbor_strict_capability_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X) " "strict-capability-match",
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Strict capability negotiation match\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community3_exact_cmd_vtysh,
+ "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, clear_bgp_instance_all_soft_cmd_vtysh,
+ "clear bgp view WORD * soft",
+ "Reset functions\n"
+ "BGP information\n"
+ "BGP view\n"
+ "view name\n"
+ "Clear all peers\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_in_cmd_vtysh,
+ "clear bgp (A.B.C.D|X:X::X:X) in",
+ "Reset functions\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "BGP IPv6 neighbor to clear\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_version_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X) " "version",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Neighbor's BGP version\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_prefix_cmd_vtysh,
+ "show ipv6 prefix-list WORD X:X::X:X/M",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+
+DEFSH (VTYSH_BGPD, ipv6_mbgp_neighbor_advertised_route_cmd_vtysh,
+ "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "MBGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display the routes advertised to a BGP neighbor\n")
+
+DEFSH (VTYSH_ZEBRA, show_ip_route_addr_cmd_vtysh,
+ "show ip route A.B.C.D",
+ "Show running system information\n"
+ "IP information\n"
+ "IP routing table\n"
+ "Network in the IP routing table to display\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_seq_le_cmd_vtysh,
+ "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128>",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community_list_cmd_vtysh,
+ "show ipv6 mbgp community-list WORD",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "MBGP information\n"
+ "Display routes matching the community-list\n"
+ "community-list name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community3_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged7_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop med as-path",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "Nexthop attribute\n"
+ "Med attribute\n"
+ "As-path attribute\n")
+
+DEFSH (VTYSH_BGPD, neighbor_default_originate_rmap_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X) " "default-originate route-map WORD",
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Originate default route to this neighbor\n"
+ "Route-map to specify criteria to originate default\n"
+ "route-map name\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_priority_cmd_vtysh,
+ "ip ospf priority <0-255>",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Router priority\n"
+ "Priority\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_connected_metric_routemap_cmd_vtysh,
+ "no redistribute connected metric <0-16> route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Metric\n"
+ "Metric value\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, neighbor_allowas_in_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "allowas-in",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Accept as-path with my AS present in it\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_ipv4_out_cmd_vtysh,
+ "clear ip bgp external ipv4 (unicast|multicast) out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all external peers\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, bgp_distance_source_access_list_cmd_vtysh,
+ "distance <1-255> A.B.C.D/M WORD",
+ "Define an administrative distance\n"
+ "Administrative distance\n"
+ "IP source prefix\n"
+ "Access list name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_regexp_cmd_vtysh,
+ "show ip bgp regexp .LINE",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display routes matching the AS path regular expression\n"
+ "A regular-expression to match the BGP AS paths\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_all_in_cmd_vtysh,
+ "clear bgp * in",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPF6D, show_debug_ospf6_cmd_vtysh,
+ "show debugging ospf6",
+ "Show running system information\n"
+ "Debugging functions (see also 'undebug')\n"
+ "Open Shortest Path First (OSPF) for IPv6\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community4_cmd_vtysh,
+ "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_summary_cmd_vtysh,
+ "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn summary",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display VPNv4 NLRI specific information\n"
+ "Display information for a route distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_in_cmd_vtysh,
+ "clear ip bgp A.B.C.D in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_out_cmd_vtysh,
+ "clear bgp ipv6 peer-group WORD out",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, debug_bgp_fsm_cmd_vtysh,
+ "debug bgp fsm",
+ "Debugging functions (see also 'undebug')\n"
+ "BGP information\n"
+ "BGP Finite State Machine\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_bgp_cmd_vtysh,
+ "no redistribute bgp",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Border Gateway Protocol (BGP)\n")
+
+DEFSH (VTYSH_RIPD, rip_timers_cmd_vtysh,
+ "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
+ "Adjust routing timers\n"
+ "Basic routing protocol update timers\n"
+ "Routing table update timer value in second. Default is 30.\n"
+ "Routing information timeout timer. Default is 180.\n"
+ "Garbage collection timer. Default is 120.\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_seq_ge_le_cmd_vtysh,
+ "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128> le <0-128>",
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+
+DEFSH (VTYSH_BGPD, old_ipv6_aggregate_address_cmd_vtysh,
+ "ipv6 bgp aggregate-address X:X::X:X/M",
+ "IPv6 information\n"
+ "BGP information\n"
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_ipv4_soft_in_cmd_vtysh,
+ "clear ip bgp view WORD * ipv4 (unicast|multicast) soft in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP view\n"
+ "view name\n"
+ "Clear all peers\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged1_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged (as-path|next-hop|med)",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "As-path attribute\n"
+ "Nexthop attribute\n"
+ "Med attribute\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD, no_match_interface_cmd_vtysh,
+ "no match interface",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "Match first hop interface of route\n")
+
+DEFSH (VTYSH_ZEBRA, show_ipv6_route_prefix_longer_cmd_vtysh,
+ "show ipv6 route X:X::X:X/M longer-prefixes",
+ "Show running system information\n"
+ "IP information\n"
+ "IPv6 routing table\n"
+ "IPv6 prefix\n"
+ "Show route matching the specified Network/Mask pair only\n")
+
+DEFSH (VTYSH_OSPFD, ospf_priority_cmd_vtysh,
+ "ospf priority <0-255>",
+ "OSPF interface commands\n"
+ "Router priority\n"
+ "Priority\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_description_cmd_vtysh,
+ "ipv6 prefix-list WORD description .LINE",
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Prefix-list specific description\n"
+ "Up to 80 characters describing this prefix-list\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community_all_cmd_vtysh,
+ "show bgp ipv6 community",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Display routes matching the communities\n")
+
+DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_name_all_cmd_vtysh,
+ "no ip extcommunity-list (standard|expanded) WORD",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Add a extended community list entry\n"
+ "Specify standard extcommunity-list\n"
+ "Specify expanded extcommunity-list\n"
+ "Extended Community list name\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_advertise_interval_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X) " "advertisement-interval",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Minimum interval between sending BGP routing updates\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community3_cmd_vtysh,
+ "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "MBGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_RIPD, send_lifetime_duration_day_month_cmd_vtysh,
+ "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> duration <1-2147483646>",
+ "Set send lifetime of the key\n"
+ "Time to start\n"
+ "Day of th month to start\n"
+ "Month of the year to start\n"
+ "Year to start\n"
+ "Duration of the key\n"
+ "Duration seconds\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_seq_cmd_vtysh,
+ "ip prefix-list WORD seq <1-4294967295> (deny|permit) (A.B.C.D/M|any)",
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_prefix_cmd_vtysh,
+ "no ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_as_soft_cmd_vtysh,
+ "clear bgp <1-65535> soft",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_cmd_vtysh,
+ "show bgp ipv6",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_ebgp_multihop_ttl_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "ebgp-multihop <1-255>",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Allow EBGP neighbors not on directly connected networks\n"
+ "maximum hop count\n")
+
+DEFSH (VTYSH_BGPD, bgp_scan_time_cmd_vtysh,
+ "bgp scan-time <5-60>",
+ "BGP specific commands\n"
+ "Configure background scanner interval\n"
+ "Scanner interval (seconds)\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_message_digest_key_addr_cmd_vtysh,
+ "no ip ospf message-digest-key <1-255> A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Message digest authentication password (key)\n"
+ "Key ID\n"
+ "Address of interface")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_name_cmd_vtysh,
+ "show ipv6 prefix-list WORD",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n")
+
+DEFSH (VTYSH_RIPNGD, show_debugging_ripng_cmd_vtysh,
+ "show debugging ripng",
+ "Show running system information\n"
+ "RIPng configuration\n"
+ "Debugging information\n")
+
+DEFSH (VTYSH_BGPD, ip_community_list_standard2_cmd_vtysh,
+ "ip community-list <1-99> (deny|permit)",
+ "IP information\n"
+ "Add a community list entry\n"
+ "Community list number (standard)\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ip_access_list_cmd_vtysh,
+ "show ip access-list",
+ "Show running system information\n"
+ "IP information\n"
+ "List IP access lists\n")
+
+DEFSH (VTYSH_BGPD, ipv6_bgp_neighbor_advertised_route_cmd_vtysh,
+ "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display the routes advertised to a BGP neighbor\n")
+
+DEFSH (VTYSH_BGPD, no_set_origin_val_cmd_vtysh,
+ "no set origin (egp|igp|incomplete)",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "BGP origin code\n"
+ "remote EGP\n"
+ "local IGP\n"
+ "unknown heritage\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_area_route_cmd_vtysh,
+ "show ipv6 ospf6 area A.B.C.D route",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Area information\n"
+ "Area ID (as an IPv4 notation)\n"
+ "Routing Table\n"
+ )
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_neighbor_routes_cmd_vtysh,
+ "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) routes",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display routes learned from neighbor\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_lsa_cmd_vtysh,
+ "debug ospf lsa",
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n"
+ "OSPF Link State Advertisement\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_dont_capability_negotiate_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "dont-capability-negotiate",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Do not perform capability negotiation\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_soft_cmd_vtysh,
+ "clear ip bgp view WORD * soft",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP view\n"
+ "view name\n"
+ "Clear all peers\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_dead_interval_cmd_vtysh,
+ "ip ospf dead-interval <1-65535>",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Interval after which a neighbor is declared dead\n"
+ "Seconds\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_inter_cmd_vtysh,
+ "distance ospf inter-area <1-255>",
+ "Define an administrative distance\n"
+ "OSPF Administrative distance\n"
+ "Inter-area routes\n"
+ "Distance for inter-area routes\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_message_digest_key_cmd_vtysh,
+ "no ip ospf message-digest-key <1-255>",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Message digest authentication password (key)\n"
+ "Key ID\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_soft_cmd_vtysh,
+ "clear ip bgp peer-group WORD soft",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_route_ospf6_external_prefix_cmd_vtysh,
+ "show ipv6 ospf6 route redistribute X::X",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Routing Table\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "redistributing External information\n"
+ "match IPv6 prefix\n"
+ )
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_ospf6_metric_cmd_vtysh,
+ "redistribute ospf6 metric <0-16>",
+ "Redistribute information from another routing protocol\n"
+ "IPv6 Open Shortest Path First (OSPFv3)\n"
+ "Metric\n"
+ "Metric value\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_soft_cmd_vtysh,
+ "clear ip bgp <1-65535> soft",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_ZEBRA, config_table_cmd_vtysh,
+ "table TABLENO",
+ "Configure target kernel routing table\n"
+ "TABLE integer\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_zebra_sub_cmd_vtysh,
+ "no debug ospf zebra (interface|redistribute)",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n"
+ "OSPF Zebra information\n"
+ "Zebra interface\n"
+ "Zebra redistribute\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_database_type_cmd_vtysh,
+ "show ip ospf database (" "asbr-summary|external|network|router|summary" "" "" "|max-age|self-originate)",
+ "Show running system information\n"
+ "IP information\n"
+ "OSPF information\n"
+ "Database summary\n"
+ "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "" "" "" ""
+ "LSAs in MaxAge list\n"
+ "Self-originated link states\n")
+
+DEFSH (VTYSH_BGPD, neighbor_prefix_list_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "prefix-list WORD (in|out)",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Filter updates to/from this neighbor\n"
+ "Name of a prefix list\n"
+ "Filter incoming updates\n"
+ "Filter outgoing updates\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_cmd_vtysh,
+ "no ip prefix-list WORD",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_standard_nomask_cmd_vtysh,
+ "access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D",
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP standard access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Address to match\n")
+
+DEFSH (VTYSH_BGPD, neighbor_default_originate_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X) " "default-originate",
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Originate default route to this neighbor\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_metric_cmd_vtysh,
+ "default-information originate always metric <0-16777214>",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "Always advertise default route\n"
+ "OSPF default metric\n"
+ "OSPF metric\n"
+ "OSPF metric type for default routes\n")
+
+DEFSH (VTYSH_RIPD, no_rip_route_cmd_vtysh,
+ "no route A.B.C.D/M",
+ "Negate a command or set its defaults\n"
+ "RIP static route configuration\n"
+ "IP prefix <network>/<length>\n")
+
+DEFSH (VTYSH_RIPD, rip_default_metric_cmd_vtysh,
+ "default-metric <1-16>",
+ "Set a metric of redistribute routes\n"
+ "Default metric\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_dead_interval_addr_cmd_vtysh,
+ "no ip ospf dead-interval A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Interval after which a neighbor is declared dead\n"
+ "Address of interface")
+
+DEFSH (VTYSH_RIPNGD, show_ipv6_ripng_cmd_vtysh,
+ "show ipv6 ripng",
+ "Show running system information\n"
+ "IP information\n"
+ "Show RIPng routes\n")
+
+DEFSH (VTYSH_OSPFD, ospf_compatible_rfc1583_cmd_vtysh,
+ "compatible rfc1583",
+ "OSPF compatibility list\n"
+ "compatible with RFC 1583\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_static_routemap_cmd_vtysh,
+ "no redistribute static route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Static routes\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged1_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged (as-path|next-hop|med)",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "As-path attribute\n"
+ "Nexthop attribute\n"
+ "Med attribute\n")
+
+DEFSH (VTYSH_BGPD, dump_bgp_routes_interval_cmd_vtysh,
+ "dump bgp routes-mrt PATH INTERVAL",
+ "Dump packet\n"
+ "BGP packet dump\n"
+ "Dump whole BGP routing table\n"
+ "Output filename\n"
+ "Interval of output\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_kernel_routemap_cmd_vtysh,
+ "redistribute kernel route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community4_exact_cmd_vtysh,
+ "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "MBGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, clear_bgp_as_soft_out_cmd_vtysh,
+ "clear bgp <1-65535> soft out",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_neighbors_cmd_vtysh,
+ "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display VPNv4 NLRI specific information\n"
+ "Display information for a route distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "Detailed information on TCP and BGP neighbor connections\n")
+
+DEFSH (VTYSH_OSPFD, interface_ip_ospf_authentication_args_cmd_vtysh,
+ "ip ospf authentication (null|message-digest)",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Enable authentication on this interface\n"
+ "Use null authentication\n"
+ "Use message-digest authentication\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_timers_cmd_vtysh,
+ "no timers basic",
+ "Negate a command or set its defaults\n"
+ "RIPng timers setup\n"
+ "Basic timer\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_cmd_vtysh,
+ "show ip prefix-list",
+ "Show running system information\n"
+ "IP information\n"
+ "Build a prefix list\n")
+
+DEFSH (VTYSH_BGPD, no_match_community_val_cmd_vtysh,
+ "no match community (<1-99>|<100-199>|WORD)",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "Match BGP community list\n"
+ "Community-list number (standard)\n"
+ "Community-list number (expanded)\n"
+ "Community-list name\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_set_ip_nexthop_val_cmd_vtysh,
+ "no set ip next-hop A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "IP information\n"
+ "Next hop address\n"
+ "IP address of next hop\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_sequence_number_cmd_vtysh,
+ "no ip prefix-list sequence-number",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Include/exclude sequence numbers in NVGEN\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_in_cmd_vtysh,
+ "clear bgp ipv6 <1-65535> in",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear peers with the AS number\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_receive_version_cmd_vtysh,
+ "no ip rip receive version",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Advertisement reception\n"
+ "Version control\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_cmd_vtysh,
+ "default-information originate always",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "Always advertise default route\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_vpnv4_in_cmd_vtysh,
+ "clear ip bgp * vpnv4 unicast in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Address family\n"
+ "Address Family Modifier\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPF6D, no_ipv6_ospf6_advertise_force_prefix_cmd_vtysh,
+ "no ipv6 ospf6 advertise force-prefix",
+ "Negate a command or set its defaults\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Advertising options\n"
+ "Force to advertise prefix, applicable if Loopback or P-to-P\n"
+ )
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_neighbor_received_routes_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received-routes",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display the received routes from neighbor\n")
+
+DEFSH (VTYSH_BGPD, no_debug_bgp_normal_cmd_vtysh,
+ "no debug bgp",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "BGP information\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_vpnv4_out_cmd_vtysh,
+ "clear ip bgp A.B.C.D vpnv4 unicast out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "Address family\n"
+ "Address Family Modifier\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_metric_routemap_cmd_vtysh,
+ "default-information originate always metric <0-16777214> route-map WORD",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "Always advertise default route\n"
+ "OSPF default metric\n"
+ "OSPF metric\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_metric_cmd_vtysh,
+ "default-information originate metric <0-16777214>",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "OSPF default metric\n"
+ "OSPF metric\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_summary_cmd_vtysh,
+ "show ipv6 mbgp summary",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "MBGP information\n"
+ "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_OSPFD, no_refresh_timer_val_cmd_vtysh,
+ "no refresh timer <10-1800>",
+ "Adjust refresh parameters\n"
+ "Unset refresh timer\n"
+ "Timer value in seconds\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_standard_cmd_vtysh,
+ "no access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP standard access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Address to match\n"
+ "Wildcard bits\n")
+
+DEFSH (VTYSH_ZEBRA, shutdown_if_cmd_vtysh,
+ "shutdown",
+ "Shutdown the selected interface\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv6_metric_rmap_cmd_vtysh,
+ "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPFv3)\n"
+ "Routing Information Protocol (RIPng)\n"
+ "Static routes\n"
+ "Metric for redistributed routes\n"
+ "Default metric\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_route_reflector_client_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "route-reflector-client",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Configure a neighbor as Route Reflector client\n")
+
+DEFSH (VTYSH_RIPD, no_rip_distance_source_cmd_vtysh,
+ "no distance <1-255> A.B.C.D/M",
+ "Negate a command or set its defaults\n"
+ "Administrative distance\n"
+ "Distance value\n"
+ "IP source prefix\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_soft_out_cmd_vtysh,
+ "clear ip bgp view WORD * soft out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP view\n"
+ "view name\n"
+ "Clear all peers\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_event_cmd_vtysh,
+ "no debug ospf event",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n"
+ "OSPF event information\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_cmd_vtysh,
+ "clear ip bgp (A.B.C.D|X:X::X:X)",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP neighbor IP address to clear\n"
+ "BGP IPv6 neighbor to clear\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_dampened_paths_cmd_vtysh,
+ "show ip bgp dampened-paths",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display paths suppressed due to dampening\n")
+
+DEFSH (VTYSH_BGPD, no_debug_bgp_filter_cmd_vtysh,
+ "no debug bgp filters",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "BGP information\n"
+ "BGP filters\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, clear_ip_prefix_list_cmd_vtysh,
+ "clear ip prefix-list",
+ "Reset functions\n"
+ "IP information\n"
+ "Build a prefix list\n")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_summary_as_set_cmd_vtysh,
+ "no aggregate-address A.B.C.D/M summary-only as-set",
+ "Negate a command or set its defaults\n"
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Filter more specific routes from updates\n"
+ "Generate AS set path information\n")
+
+DEFSH (VTYSH_RIPD, debug_rip_events_cmd_vtysh,
+ "debug rip events",
+ "Debugging functions (see also 'undebug')\n"
+ "RIP information\n"
+ "RIP events\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_distribute_list_out_cmd_vtysh,
+ "no distribute-list WORD out (kernel|connected|static|rip|bgp)",
+ "Negate a command or set its defaults\n"
+ "Filter networks in routing updates\n"
+ "Access-list name\n"
+ "Filter outgoing routing updates\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Routing Information Protocol (RIP)\n"
+ "Border Gateway Protocol (BGP)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_prefix_cmd_vtysh,
+ "no ipv6 prefix-list WORD (deny|permit) (X:X::X:X/M|any)",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Any prefix match. Same as \"::0/0 le 128\"\n")
+
+DEFSH (VTYSH_BGPD, no_set_ecommunity_rt_cmd_vtysh,
+ "no set extcommunity rt",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "BGP extended community attribute\n"
+ "Route Target extened communityt\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged10_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med as-path next-hop",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "Med attribute\n"
+ "As-path attribute\n"
+ "Nexthop attribute\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_soft_cmd_vtysh,
+ "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, undebug_bgp_normal_cmd_vtysh,
+ "undebug bgp",
+ "Disable debugging functions (see also 'debug')\n"
+ "BGP information\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_retransmit_interval_addr_cmd_vtysh,
+ "no ip ospf retransmit-interval A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Time between retransmitting lost link state advertisements\n"
+ "Address of interface")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_bgp_routemap_cmd_vtysh,
+ "no redistribute bgp route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_in_prefix_filter_cmd_vtysh,
+ "clear ip bgp * in prefix-filter",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Soft reconfig inbound update\n"
+ "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, neighbor_transparent_as_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X) " "transparent-as",
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Do not append my AS number even peer is EBGP peer\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ipv6_access_list_remark_cmd_vtysh,
+ "no ipv6 access-list WORD remark",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n"
+ "Access list entry comment\n")
+
+DEFSH (VTYSH_BGPD, no_match_community_exact_cmd_vtysh,
+ "no match community (<1-99>|<100-199>|WORD) exact-match",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "Match BGP community list\n"
+ "Community-list number (standard)\n"
+ "Community-list number (expanded)\n"
+ "Community-list name\n"
+ "Do exact matching of communities\n")
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_param3_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval)",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_in_prefix_filter_cmd_vtysh,
+ "clear ip bgp <1-65535> ipv4 (unicast|multicast) in prefix-filter",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig inbound update\n"
+ "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_out_cmd_vtysh,
+ "clear bgp ipv6 external WORD out",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all external peers\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_inter_intra_cmd_vtysh,
+ "distance ospf inter-area <1-255> intra-area <1-255>",
+ "Define an administrative distance\n"
+ "OSPF Administrative distance\n"
+ "Inter-area routes\n"
+ "Distance for inter-area routes\n"
+ "Intra-area routes\n"
+ "Distance for intra-area routes\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_vpnv4_out_cmd_vtysh,
+ "clear ip bgp <1-65535> vpnv4 unicast out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_summary_cmd_vtysh,
+ "show bgp summary",
+ "Show running system information\n"
+ "BGP information\n"
+ "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_BGPD, bgp_deterministic_med_cmd_vtysh,
+ "bgp deterministic-med",
+ "BGP specific commands\n"
+ "Pick the best-MED path among paths advertised from the neighboring AS\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_le_ge_cmd_vtysh,
+ "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128> ge <0-128>",
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, undebug_bgp_filter_cmd_vtysh,
+ "undebug bgp filters",
+ "Disable debugging functions (see also 'debug')\n"
+ "BGP information\n"
+ "BGP filters\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_cmd_vtysh,
+ "show ipv6 ospf6",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_in_prefix_filter_cmd_vtysh,
+ "clear bgp ipv6 external in prefix-filter",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all external peers\n"
+ "Soft reconfig inbound update\n"
+ "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_area_spf_node_cmd_vtysh,
+ "show ipv6 ospf6 area A.B.C.D spf node",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Area information\n"
+ "Area ID (as an IPv4 notation)\n"
+ "Shortest Path First caculation\n"
+ "vertex infomation\n"
+ )
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv4_cmd_vtysh,
+ "redistribute (connected|kernel|ospf|rip|static)",
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPF)\n"
+ "Routing Information Protocol (RIP)\n"
+ "Static routes\n")
+
+DEFSH (VTYSH_BGPD, neighbor_filter_list_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "filter-list WORD (in|out)",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Establish BGP filters\n"
+ "AS path access-list name\n"
+ "Filter incoming routes\n"
+ "Filter outgoing routes\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged10_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med as-path next-hop",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "Med attribute\n"
+ "As-path attribute\n"
+ "Nexthop attribute\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, clear_ip_prefix_list_name_cmd_vtysh,
+ "clear ip prefix-list WORD",
+ "Reset functions\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n")
+
+DEFSH (VTYSH_ZEBRA, show_ip_route_cmd_vtysh,
+ "show ip route",
+ "Show running system information\n"
+ "IP information\n"
+ "IP routing table\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_connected_cmd_vtysh,
+ "redistribute connected",
+ "Redistribute information from another routing protocol\n"
+ "Connected\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community_cmd_vtysh,
+ "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "MBGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, ip_community_list_cmd_vtysh,
+ "ip community-list WORD (deny|permit) .AA:NN",
+ "IP information\n"
+ "Add a community list entry\n"
+ "Community list name\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n"
+ "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_in_prefix_filter_cmd_vtysh,
+ "clear bgp (A.B.C.D|X:X::X:X) in prefix-filter",
+ "Reset functions\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "BGP IPv6 neighbor to clear\n"
+ "Soft reconfig inbound update\n"
+ "Push out the existing ORF prefix-list\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_intra_external_cmd_vtysh,
+ "distance ospf intra-area <1-255> external <1-255>",
+ "Define an administrative distance\n"
+ "OSPF Administrative distance\n"
+ "Intra-area routes\n"
+ "Distance for intra-area routes\n"
+ "External routes\n"
+ "Distance for external routes\n")
+
+DEFSH (VTYSH_BGPD, ipv6_mbgp_neighbor_received_routes_cmd_vtysh,
+ "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) received-routes",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "MBGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display the received routes from neighbor\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_metric_type_routemap_cmd_vtysh,
+ "default-information originate always metric <0-16777214> metric-type (1|2) route-map WORD",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "Always advertise default route\n"
+ "OSPF default metric\n"
+ "OSPF metric\n"
+ "OSPF metric type for default routes\n"
+ "Set OSPF External Type 1 metrics\n"
+ "Set OSPF External Type 2 metrics\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_seq_cmd_vtysh,
+ "no ip prefix-list WORD seq <1-4294967295> (deny|permit) (A.B.C.D/M|any)",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n")
+
+DEFSH (VTYSH_OSPF6D, interface_area_plist_passive_cmd_vtysh,
+ "interface IFNAME area A.B.C.D prefix-list WORD passive",
+ "Enable routing on an IPv6 interface\n"
+ "Interface name(e.g. ep0)\n"
+ "Set the OSPF6 area ID\n"
+ "OSPF6 area ID in IPv4 address notation\n"
+ "Advertise I/F Address only match entries of prefix-list\n"
+ "IPv6 prefix-list name\n"
+ "IPv6 prefix-list name\n"
+ "Suppress routing updates on an interface\n"
+ )
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_seq_le_ge_cmd_vtysh,
+ "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128> ge <0-128>",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_in_prefix_filter_cmd_vtysh,
+ "clear bgp ipv6 * in prefix-filter",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all peers\n"
+ "Soft reconfig inbound update\n"
+ "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_neighbors_cmd_vtysh,
+ "show ip bgp vpnv4 all neighbors",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display VPNv4 NLRI specific information\n"
+ "Display information about all VPNv4 NLRIs\n"
+ "Detailed information on TCP and BGP neighbor connections\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_neighbors_cmd_vtysh,
+ "show bgp ipv6 neighbors",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Detailed information on TCP and BGP neighbor connections\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_kernel_metric_routemap_cmd_vtysh,
+ "no redistribute kernel metric <0-16> route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Metric\n"
+ "Metric value\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, old_no_ipv6_aggregate_address_summary_only_cmd_vtysh,
+ "no ipv6 bgp aggregate-address X:X::X:X/M summary-only",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_summary_cmd_vtysh,
+ "show ipv6 bgp summary",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_in_prefix_filter_cmd_vtysh,
+ "clear ip bgp view WORD * in prefix-filter",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP view\n"
+ "view name\n"
+ "Clear all peers\n"
+ "Soft reconfig inbound update\n"
+ "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_standard_cmd_vtysh,
+ "no ip extcommunity-list <1-99> (deny|permit) .AA:NN",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Add a extended community list entry\n"
+ "Extended Community list number (standard)\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n"
+ "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distribute_list_out_cmd_vtysh,
+ "distribute-list WORD out (kernel|connected|static|rip|bgp)",
+ "Filter networks in routing updates\n"
+ "Access-list name\n"
+ "Filter outgoing routing updates\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Routing Information Protocol (RIP)\n"
+ "Border Gateway Protocol (BGP)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ipv6_access_list_remark_arg_cmd_vtysh,
+ "no ipv6 access-list WORD remark .LINE",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n"
+ "Access list entry comment\n"
+ "Comment up to 100 characters\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_flap_statistics_cmd_vtysh,
+ "show ip bgp flap-statistics",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display flap statistics of routes\n")
+
+DEFSH (VTYSH_ZEBRA, show_ip_route_supernets_cmd_vtysh,
+ "show ip route supernets-only",
+ "Show running system information\n"
+ "IP information\n"
+ "IP routing table\n"
+ "Show supernet entries only\n")
+
+DEFSH (VTYSH_BGPD, set_ipv6_nexthop_local_cmd_vtysh,
+ "set ipv6 next-hop local X:X::X:X",
+ "Set values in destination routing protocol\n"
+ "IPv6 information\n"
+ "IPv6 next-hop address\n"
+ "IPv6 local address\n"
+ "IPv6 address of next hop\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_rfc1583_flag_cmd_vtysh,
+ "no ospf rfc1583compatibility",
+ "Negate a command or set its defaults\n"
+ "OSPF specific commands\n"
+ "Disable the RFC1583Compatibility flag\n")
+
+DEFSH (VTYSH_BGPD, neighbor_route_map_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "route-map WORD (in|out)",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Apply route map to neighbor\n"
+ "Name of route map\n"
+ "Apply map to incoming routes\n"
+ "Apply map to outbound routes\n")
+
+DEFSH (VTYSH_BGPD, no_debug_bgp_keepalive_cmd_vtysh,
+ "no debug bgp keepalives",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "BGP information\n"
+ "BGP keepalives\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community3_exact_cmd_vtysh,
+ "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_topology_router_lsid_cmd_vtysh,
+ "show ipv6 ospf6 topology (A.B.C.D|<0-4294967295>) (A.B.C.D|<0-4294967295>)",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Inter Area topology information\n"
+ "Specify Router-ID\n"
+ "Specify Router-ID\n"
+ "Specify Link State ID\n"
+ "Specify Link State ID\n"
+ )
+
+DEFSH (VTYSH_BGPD, no_bgp_network_mask_natural_route_map_cmd_vtysh,
+ "no network A.B.C.D route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community_all_cmd_vtysh,
+ "show ipv6 mbgp community",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "MBGP information\n"
+ "Display routes matching the communities\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_route_map_cmd_vtysh,
+ "no route-map WORD (deny|permit) <1-65535>",
+ "Negate a command or set its defaults\n"
+ "Create route-map or enter route-map command mode\n"
+ "Route map tag\n"
+ "Route map denies set operations\n"
+ "Route map permits set operations\n"
+ "Sequence to insert to/delete from existing route-map entry\n")
+
+DEFSH (VTYSH_ZEBRA, ip_address_cmd_vtysh,
+ "ip address A.B.C.D/M",
+ "Interface Internet Protocol config commands\n"
+ "Set the IP address of an interface\n"
+ "IP address (e.g. 10.0.0.1/8)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_ge_cmd_vtysh,
+ "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128>",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_sequence_number_cmd_vtysh,
+ "no ipv6 prefix-list sequence-number",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Include/exclude sequence numbers in NVGEN\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast)",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_any_host_cmd_vtysh,
+ "access-list (<100-199>|<2000-2699>) (deny|permit) ip any host A.B.C.D",
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Any source host\n"
+ "A single destination host\n"
+ "Destination address\n")
+
+DEFSH (VTYSH_BGPD, ipv6_mbgp_neighbor_routes_cmd_vtysh,
+ "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "MBGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display routes learned from neighbor\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_param4_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>",
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n")
+
+DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_expanded_cmd_vtysh,
+ "no ip extcommunity-list <100-199> (deny|permit) .LINE",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Add a extended community list entry\n"
+ "Extended Community list number (expanded)\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n"
+ "An ordered list as a regular-expression\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_authentication_key_chain_cmd_vtysh,
+ "no ip rip authentication key-chain",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Authentication control\n"
+ "Authentication key-chain\n")
+
+DEFSH (VTYSH_ZEBRA, ip_route_mask_pref_cmd_vtysh,
+ "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) <1-255>",
+ "IP information\n"
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Distance value for this route\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_default_information_originate_cmd_vtysh,
+ "no default-information originate",
+ "Negate a command or set its defaults\n"
+ "Control distribution of default information\n"
+ "Distribute a default route\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_bestpath_med_cmd_vtysh,
+ "no bgp bestpath med (confed|missing-as-worst)",
+ "Negate a command or set its defaults\n"
+ "BGP specific commands\n"
+ "Change the default bestpath selection\n"
+ "MED attribute\n"
+ "Compare MED among confederation paths\n"
+ "Treat missing MED as the least preferred one\n")
+
+DEFSH (VTYSH_BGPD, neighbor_unsuppress_map_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "unsuppress-map WORD",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Route-map to selectively unsuppress suppressed routes\n"
+ "Name of route map\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_route_cmd_vtysh,
+ "route IPV6ADDR",
+ "Static route setup\n"
+ "Set static RIPng route announcement\n")
+
+DEFSH (VTYSH_ZEBRA, ip_route_cmd_vtysh,
+ "ip route A.B.C.D/M (A.B.C.D|INTERFACE)",
+ "IP information\n"
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_neighbor_damp_cmd_vtysh,
+ "show ip bgp neighbors (A.B.C.D|X:X::X:X) dampened-routes",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display the dampened routes received from neighbor\n")
+
+DEFSH (VTYSH_RIPD, send_lifetime_month_day_day_month_cmd_vtysh,
+ "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>",
+ "Set send lifetime of the key\n"
+ "Time to start\n"
+ "Month of the year to start\n"
+ "Day of th month to start\n"
+ "Year to start\n"
+ "Time to expire\n"
+ "Day of th month to expire\n"
+ "Month of the year to expire\n"
+ "Year to expire\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_route_map_all_cmd_vtysh,
+ "no route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Create route-map or enter route-map command mode\n"
+ "Route map tag\n")
+
+DEFSH (VTYSH_RIPD, no_rip_network_cmd_vtysh,
+ "no network (A.B.C.D/M|WORD)",
+ "Negate a command or set its defaults\n"
+ "Enable routing on an IP network\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Interface name\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_mask_route_map_cmd_vtysh,
+ "network A.B.C.D mask A.B.C.D route-map WORD",
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Network mask\n"
+ "Network mask\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+
+DEFSH (VTYSH_BGPD, set_vpnv4_nexthop_cmd_vtysh,
+ "set vpnv4 next-hop A.B.C.D",
+ "Set values in destination routing protocol\n"
+ "VPNv4 information\n"
+ "VPNv4 next-hop address\n"
+ "IP address of next hop\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_packet_send_recv_detail_cmd_vtysh,
+ "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) (detail|)",
+ "Negate a command or set its defaults\n"
+ "Debugging functions\n"
+ "OSPF information\n"
+ "OSPF packets\n"
+ "OSPF Hello\n"
+ "OSPF Database Description\n"
+ "OSPF Link State Request\n"
+ "OSPF Link State Update\n"
+ "OSPF Link State Acknowledgment\n"
+ "OSPF all packets\n"
+ "Packet sent\n"
+ "Packet received\n"
+ "Detail Information\n")
+
+DEFSH (VTYSH_RIPD, no_rip_default_metric_cmd_vtysh,
+ "no default-metric",
+ "Negate a command or set its defaults\n"
+ "Set a metric of redistribute routes\n"
+ "Default metric\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_soft_out_cmd_vtysh,
+ "clear ip bgp peer-group WORD soft out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_route_cmd_vtysh,
+ "show ipv6 mbgp X:X::X:X",
+ "Show running system information\n"
+ "IP information\n"
+ "MBGP information\n"
+ "Network in the MBGP routing table to display\n")
+
+DEFSH (VTYSH_OSPFD, neighbor_cmd_vtysh,
+ "neighbor A.B.C.D",
+ "Specify neighbor router\n"
+ "Neighbor IP address\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_ipv4_in_cmd_vtysh,
+ "clear ip bgp external ipv4 (unicast|multicast) in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all external peers\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPFD, area_range_advertise_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise",
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "OSPF area range for route advertise (default)\n"
+ "area range prefix\n"
+ "advertise this range\n")
+
+DEFSH (VTYSH_OSPFD, timers_spf_cmd_vtysh,
+ "timers spf <0-4294967295> <0-4294967295>",
+ "Adjust routing timers\n"
+ "OSPF SPF timers\n"
+ "Delay between receiving a change to SPF calculation\n"
+ "Hold time between consecutive SPF calculations\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_route_pref_cmd_vtysh,
+ "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>",
+ "IP information\n"
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Distance value for this prefix\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_default_local_preference_val_cmd_vtysh,
+ "no bgp default local-preference <0-4294967295>",
+ "Negate a command or set its defaults\n"
+ "BGP specific commands\n"
+ "Configure BGP defaults\n"
+ "local preference (higher=more preferred)\n"
+ "Configure default local preference value\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_timers_cmd_vtysh,
+ "timers basic <0-65535> <0-65535> <0-65535>",
+ "RIPng timers setup\n"
+ "Basic timer\n"
+ "Routing table update timer value in second. Default is 30.\n"
+ "Routing information timeout timer. Default is 180.\n"
+ "Garbage collection timer. Default is 120.\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged8_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop as-path med",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "Nexthop attribute\n"
+ "As-path attribute\n"
+ "Med attribute\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community2_cmd_vtysh,
+ "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_OSPFD, no_set_metric_type_cmd_vtysh,
+ "no set metric-type",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "Type of metric for destination routing protocol\n")
+
+DEFSH (VTYSH_BGPD, neighbor_peer_group_cmd_vtysh,
+ "neighbor WORD peer-group",
+ "Specify neighbor router\n"
+ "Neighbor tag\n"
+ "Configure peer-group\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community_exact_cmd_vtysh,
+ "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_OSPFD, no_area_range_subst_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M substitute A.B.C.D/M",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Deconfigure OSPF area range for route summarization\n"
+ "area range prefix\n"
+ "Do not advertise this range\n"
+ "Announce area range as another prefix\n"
+ "Network prefix to be announced instead of range\n")
+
+DEFSH (VTYSH_BGPD, bgp_enforce_first_as_cmd_vtysh,
+ "bgp enforce-first-as",
+ "BGP information\n"
+ "Enforce the first AS for EBGP routes\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community3_exact_cmd_vtysh,
+ "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_OSPFD, ospf_dead_interval_cmd_vtysh,
+ "ospf dead-interval <1-65535>",
+ "OSPF interface commands\n"
+ "Interval after which a neighbor is declared dead\n"
+ "Seconds\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_soft_cmd_vtysh,
+ "clear bgp ipv6 peer-group WORD soft",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_authtype_args_md5_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication|) (message-digest|null) "
+ "(message-digest-key|) <1-255> md5 KEY",
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Enable authentication on this virtual link\n" "dummy string \n" "Use null authentication\n" "Use message-digest authentication\n"
+ "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_BGPD, clear_bgp_external_cmd_vtysh,
+ "clear bgp external",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all external peers\n")
+
+DEFSH (VTYSH_BGPD, no_ip_community_list_name_standard_cmd_vtysh,
+ "no ip community-list standard WORD (deny|permit) .AA:NN",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Add a community list entry\n"
+ "Specify a standard community-list\n"
+ "Community list name\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n"
+ "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n")
+
+DEFSH (VTYSH_BGPD, neighbor_update_source_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "update-source WORD",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Source of routing updates\n"
+ "Interface name\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_in_cmd_vtysh,
+ "clear ip bgp peer-group WORD in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPFD, neighbor_priority_cmd_vtysh,
+ "neighbor A.B.C.D priority <0-255>",
+ "Specify neighbor router\n"
+ "Neighbor IP address\n"
+ "Neighbor Priority\n"
+ "Seconds\n")
+
+DEFSH (VTYSH_BGPD, ip_extcommunity_list_name_standard_cmd_vtysh,
+ "ip extcommunity-list standard WORD (deny|permit) .AA:NN",
+ "IP information\n"
+ "Add a extended community list entry\n"
+ "Specify standard extcommunity-list\n"
+ "Extended Community list name\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n"
+ "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n")
+
+DEFSH (VTYSH_BGPD, neighbor_capability_route_refresh_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "capability route-refresh",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Advertise capability to the peer\n"
+ "Advertise route-refresh capability to this neighbor\n")
+
+DEFSH (VTYSH_BGPD, no_ipv6_bgp_network_cmd_vtysh,
+ "no network X:X::X:X/M",
+ "Negate a command or set its defaults\n"
+ "Specify a network to announce via BGP\n"
+ "IPv6 prefix <network>/<length>\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_connected_metric_val_cmd_vtysh,
+ "no redistribute connected metric <0-16>",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Metric\n"
+ "Metric value\n")
+
+DEFSH (VTYSH_RIPD, ip_rip_receive_version_1_cmd_vtysh,
+ "ip rip receive version 1 2",
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Advertisement reception\n"
+ "Version control\n"
+ "RIP version 1\n"
+ "RIP version 2\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_network_mask_cmd_vtysh,
+ "no network A.B.C.D mask A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Network mask\n"
+ "Network mask\n")
+
+DEFSH (VTYSH_ZEBRA, show_interface_cmd_vtysh,
+ "show interface [IFNAME]",
+ "Show running system information\n"
+ "Interface status and configuration\n"
+ "Inteface name\n")
+
+DEFSH (VTYSH_OSPFD, no_router_ospf_cmd_vtysh,
+ "no router ospf",
+ "Negate a command or set its defaults\n"
+ "Enable a routing process\n"
+ "Start OSPF configuration\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_confederation_identifier_cmd_vtysh,
+ "no bgp confederation identifier",
+ "Negate a command or set its defaults\n"
+ "BGP specific commands\n"
+ "AS confederation parameters\n"
+ "AS number\n")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_metric_type_routemap_cmd_vtysh,
+ "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> metric-type (1|2) route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Routing Information Protocol (RIP)\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Metric for redistributed routes\n"
+ "OSPF default metric\n"
+ "OSPF exterior metric type for redistributed routes\n"
+ "Set OSPF External Type 1 metrics\n"
+ "Set OSPF External Type 2 metrics\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_local_as_val2_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as <1-65535> no-prepend",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Specify a local-as number\n"
+ "AS number used as local AS\n"
+ "Do not prepend local-as to updates from ebgp peers\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community_info_cmd_vtysh,
+ "show ip bgp community-info",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "List all bgp community information\n")
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv4_metric_cmd_vtysh,
+ "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>",
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPF)\n"
+ "Routing Information Protocol (RIP)\n"
+ "Static routes\n"
+ "Metric for redistributed routes\n"
+ "Default metric\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_cidr_only_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) cidr-only",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display only routes with non-natural netmasks\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ipv6_access_list_any_cmd_vtysh,
+ "ipv6 access-list WORD (deny|permit) any",
+ "IPv6 information\n"
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any prefixi to match\n")
+
+DEFSH (VTYSH_BGPD, undebug_bgp_fsm_cmd_vtysh,
+ "undebug bgp fsm",
+ "Disable debugging functions (see also 'debug')\n"
+ "Debugging functions (see also 'undebug')\n"
+ "BGP information\n"
+ "Finite State Machine\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_cmd_vtysh,
+ "ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)",
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_network_import_check_cmd_vtysh,
+ "no bgp network import-check",
+ "Negate a command or set its defaults\n"
+ "BGP specific commands\n"
+ "BGP network command\n"
+ "Check BGP network route exists in IGP\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_soft_out_cmd_vtysh,
+ "clear ip bgp A.B.C.D soft out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, no_ip_community_list_name_expanded_cmd_vtysh,
+ "no ip community-list expanded WORD (deny|permit) .LINE",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Add a community list entry\n"
+ "Specify an expanded community-list\n"
+ "Community list name\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n"
+ "An ordered list as a regular-expression\n")
+
+DEFSH (VTYSH_BGPD, ip_extcommunity_list_name_expanded_cmd_vtysh,
+ "ip extcommunity-list expanded WORD (deny|permit) .LINE",
+ "IP information\n"
+ "Add a extended community list entry\n"
+ "Specify expanded extcommunity-list\n"
+ "Extended Community list name\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n"
+ "An ordered list as a regular-expression\n")
+
+DEFSH (VTYSH_RIPD, no_rip_distance_cmd_vtysh,
+ "no distance <1-255>",
+ "Negate a command or set its defaults\n"
+ "Administrative distance\n"
+ "Distance value\n")
+
+DEFSH (VTYSH_ZEBRA, show_debugging_zebra_cmd_vtysh,
+ "show debugging zebra",
+ "Show running system information\n"
+ "Zebra configuration\n"
+ "Debugging information\n")
+
+DEFSH (VTYSH_OSPFD, area_authentication_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) authentication",
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Enable authentication\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community_list_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) community-list WORD",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the community-list\n"
+ "community-list name\n")
+
+DEFSH (VTYSH_RIPD, no_rip_offset_list_ifname_cmd_vtysh,
+ "no offset-list WORD (in|out) <0-16> IFNAME",
+ "Negate a command or set its defaults\n"
+ "Modify RIP metric\n"
+ "Access-list name\n"
+ "For incoming updates\n"
+ "For outgoing updates\n"
+ "Metric value\n"
+ "Interface to match\n")
+
+DEFSH (VTYSH_ZEBRA, show_ip_route_prefix_cmd_vtysh,
+ "show ip route A.B.C.D/M",
+ "Show running system information\n"
+ "IP information\n"
+ "IP routing table\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+
+DEFSH (VTYSH_OSPF6D, interface_area_plist_cmd_vtysh,
+ "interface IFNAME area A.B.C.D prefix-list WORD",
+ "Enable routing on an IPv6 interface\n"
+ "Interface name(e.g. ep0)\n"
+ "Set the OSPF6 area ID\n"
+ "OSPF6 area ID in IPv4 address notation\n"
+ "Advertise I/F Address only match entries of prefix-list\n"
+ "IPv6 prefix-list name\n"
+ )
+
+DEFSH (VTYSH_OSPFD, neighbor_priority_pollinterval_cmd_vtysh,
+ "neighbor A.B.C.D priority <0-255> poll-interval <1-65535>",
+ "Specify neighbor router\n"
+ "Neighbor IP address\n"
+ "Neighbor Priority\n"
+ "Priority\n"
+ "Dead Neighbor Polling interval\n"
+ "Seconds\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, rmap_onmatch_goto_cmd_vtysh,
+ "on-match goto <1-65535>",
+ "Exit policy on matches\n"
+ "Goto Clause number\n"
+ "Number\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_peer_group_remote_as_cmd_vtysh,
+ "no neighbor WORD remote-as <1-65535>",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor tag\n"
+ "Specify a BGP neighbor\n"
+ "AS number\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_mask_as_set_cmd_vtysh,
+ "aggregate-address A.B.C.D A.B.C.D as-set",
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n"
+ "Generate AS set path information\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_database_type_id_adv_router_cmd_vtysh,
+ "show ip ospf database (" "asbr-summary|external|network|router|summary" "" "" ") A.B.C.D adv-router A.B.C.D",
+ "Show running system information\n"
+ "IP information\n"
+ "OSPF information\n"
+ "Database summary\n"
+ "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "" "" "" ""
+ "Link State ID (as an IP address)\n"
+ "Advertising Router link states\n"
+ "Advertising Router (as an IP address)\n")
+
+DEFSH (VTYSH_BGPD, no_dump_bgp_all_cmd_vtysh,
+ "no dump bgp all [PATH] [INTERVAL]",
+ "Negate a command or set its defaults\n"
+ "Dump packet\n"
+ "BGP packet dump\n"
+ "Dump all BGP packets\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community4_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged8_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop as-path med",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "Nexthop attribute\n"
+ "As-path attribute\n"
+ "Med attribute\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_config_type_cmd_vtysh,
+ "no bgp config-type",
+ "Negate a command or set its defaults\n"
+ "BGP information\n"
+ "Display configuration type\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_view_prefix_cmd_vtysh,
+ "show ip bgp view WORD A.B.C.D/M",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP view\n"
+ "BGP view name\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_as_set_summary_cmd_vtysh,
+ "aggregate-address A.B.C.D/M as-set summary-only",
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Generate AS set path information\n"
+ "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_cmd_vtysh,
+ "show ipv6 bgp",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_out_cmd_vtysh,
+ "clear ip bgp peer-group WORD ipv4 (unicast|multicast) out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_ZEBRA, no_ip_address_secondary_cmd_vtysh,
+ "no ip address A.B.C.D/M secondary",
+ "Negate a command or set its defaults\n"
+ "Interface Internet Protocol config commands\n"
+ "Set the IP address of an interface\n"
+ "IP address (e.g. 10.0.0.1/8)\n"
+ "Secondary IP address\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_ipv4_soft_out_cmd_vtysh,
+ "clear ip bgp external ipv4 (unicast|multicast) soft out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all external peers\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_instance_all_cmd_vtysh,
+ "clear bgp view WORD *",
+ "Reset functions\n"
+ "BGP information\n"
+ "BGP view\n"
+ "view name\n"
+ "Clear all peers\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_port_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X) " "port",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Neighbor's BGP port\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_address_prefix_list_cmd_vtysh,
+ "no match ip address prefix-list",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "IP information\n"
+ "Match address of route\n"
+ "Match entries of prefix-lists\n")
+
+DEFSH (VTYSH_BGPD, neighbor_passive_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "passive",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Don't send open messages to this neighbor\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_all_out_cmd_vtysh,
+ "clear bgp * out",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, bgp_damp_set2_cmd_vtysh,
+ "bgp dampening <1-45>",
+ "BGP Specific commands\n"
+ "Enable route-flap dampening\n"
+ "Half-life time for the penalty\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_detail_cmd_vtysh,
+ "show ip prefix-list detail",
+ "Show running system information\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Detail of prefix lists\n")
+
+DEFSH (VTYSH_BGPD, neighbor_capability_dynamic_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "capability dynamic",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Advertise capability to the peer\n"
+ "Advertise dynamic capability to this neighbor\n")
+
+DEFSH (VTYSH_BGPD, neighbor_timers_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "timers <0-65535> <0-65535>",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP per neighbor timers\n"
+ "Keepalive interval\n"
+ "Holdtime\n")
+
+DEFSH (VTYSH_BGPD, undebug_bgp_all_cmd_vtysh,
+ "undebug all bgp",
+ "Disable debugging functions (see also 'debug')\n"
+ "Enable all debugging\n"
+ "BGP information\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_cmd_vtysh,
+ "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display VPNv4 NLRI specific information\n"
+ "Display information for a route distinguisher\n"
+ "VPN Route Distinguisher\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_prefix_list_cmd_vtysh,
+ "show bgp prefix-list WORD",
+ "Show running system information\n"
+ "BGP information\n"
+ "Display routes conforming to the prefix-list\n"
+ "IPv6 prefix-list name\n")
+
+DEFSH (VTYSH_BGPD, no_set_vpnv4_nexthop_val_cmd_vtysh,
+ "no set vpnv4 next-hop A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "VPNv4 information\n"
+ "VPNv4 next-hop address\n"
+ "IP address of next hop\n")
+
+DEFSH (VTYSH_OSPFD, area_filter_list_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) filter-list prefix WORD (in|out)",
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Filter networks between OSPF areas\n"
+ "Filter prefixes between OSPF areas\n"
+ "Name of an IP prefix-list\n"
+ "Filter networks sent to this area\n"
+ "Filter networks sent from this area\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_soft_out_cmd_vtysh,
+ "clear bgp ipv6 external soft out",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all external peers\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_interface_cmd_vtysh,
+ "show ip ospf interface [INTERFACE]",
+ "Show running system information\n"
+ "IP information\n"
+ "OSPF information\n"
+ "Interface information\n"
+ "Interface name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_neighbors_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) neighbors",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Detailed information on TCP and BGP neighbor connections\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_always_compare_med_cmd_vtysh,
+ "no bgp always-compare-med",
+ "Negate a command or set its defaults\n"
+ "BGP specific commands\n"
+ "Allow comparing MED from different neighbors\n")
+
+DEFSH (VTYSH_BGPD, old_no_ipv6_aggregate_address_cmd_vtysh,
+ "no ipv6 bgp aggregate-address X:X::X:X/M",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_type_metric_cmd_vtysh,
+ "default-information originate metric-type (1|2) metric <0-16777214>",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "OSPF metric type for default routes\n"
+ "Set OSPF External Type 1 metrics\n"
+ "Set OSPF External Type 2 metrics\n"
+ "OSPF default metric\n"
+ "OSPF metric\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged2_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path (next-hop|med)",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "As-path attribute\n"
+ "Nexthop attribute\n"
+ "Med attribute\n")
+
+DEFSH (VTYSH_RIPD, debug_rip_packet_cmd_vtysh,
+ "debug rip packet",
+ "Debugging functions (see also 'undebug')\n"
+ "RIP information\n"
+ "RIP packet\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_neighbor_advertised_route_cmd_vtysh,
+ "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display the routes advertised to a BGP neighbor\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_default_metric_cmd_vtysh,
+ "default-metric <1-16>",
+ "Set a metric of redistribute routes\n"
+ "Default metric\n")
+
+DEFSH (VTYSH_RIPD, no_rip_redistribute_type_cmd_vtysh,
+ "no redistribute (kernel|connected|static|ospf|bgp)",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Open Shortest Path First (OSPF)\n"
+ "Border Gateway Protocol (BGP)\n")
+
+DEFSH (VTYSH_BGPD, undebug_bgp_keepalive_cmd_vtysh,
+ "undebug bgp keepalives",
+ "Disable debugging functions (see also 'debug')\n"
+ "BGP information\n"
+ "BGP keepalives\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_import_check_cmd_vtysh,
+ "bgp network import-check",
+ "BGP specific commands\n"
+ "BGP network command\n"
+ "Check BGP network route exists in IGP\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_soft_out_cmd_vtysh,
+ "clear ip bgp <1-65535> soft out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_cmd_vtysh,
+ "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Source address\n"
+ "Source wildcard bits\n"
+ "Destination address\n"
+ "Destination Wildcard bits\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community4_cmd_vtysh,
+ "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "MBGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, ip_as_path_cmd_vtysh,
+ "ip as-path access-list WORD (deny|permit) .LINE",
+ "IP information\n"
+ "BGP autonomous system path filter\n"
+ "Specify an access list name\n"
+ "Regular expression access list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "A regular-expression to match the BGP AS paths\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_out_cmd_vtysh,
+ "clear ip bgp * out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD, send_lifetime_day_month_month_day_cmd_vtysh,
+ "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>",
+ "Set send lifetime of the key\n"
+ "Time to start\n"
+ "Day of th month to start\n"
+ "Month of the year to start\n"
+ "Year to start\n"
+ "Time to expire\n"
+ "Month of the year to expire\n"
+ "Day of th month to expire\n"
+ "Year to expire\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPF6D, no_router_zebra_cmd_vtysh,
+ "no router zebra",
+ "Negate a command or set its defaults\n"
+ "Configure routing process\n"
+ "Disable connection to zebra daemon\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_authentication_string_cmd_vtysh,
+ "no ip rip authentication string",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Authentication control\n"
+ "Authentication string\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_soft_out_cmd_vtysh,
+ "clear bgp ipv6 peer-group WORD soft out",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_route_map_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "route-map WORD (in|out)",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Apply route map to neighbor\n"
+ "Name of route map\n"
+ "Apply map to incoming routes\n"
+ "Apply map to outbound routes\n")
+
+DEFSH (VTYSH_BGPD, ipv6_aggregate_address_summary_only_cmd_vtysh,
+ "aggregate-address X:X::X:X/M summary-only",
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_transmit_delay_cmd_vtysh,
+ "no ip ospf transmit-delay",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Link state transmit delay\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_le_ge_cmd_vtysh,
+ "no ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32> ge <0-32>",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_prefix_cmd_vtysh,
+ "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D/M",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display VPNv4 NLRI specific information\n"
+ "Display information for a route distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_route_map_cmd_vtysh,
+ "network A.B.C.D/M route-map WORD",
+ "Specify a network to announce via BGP\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community_list_cmd_vtysh,
+ "show ip bgp community-list WORD",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display routes matching the community-list\n"
+ "community-list name\n")
+
+DEFSH (VTYSH_ZEBRA, no_ip_route_mask_cmd_vtysh,
+ "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE)",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n")
+
+DEFSH (VTYSH_RIPD, accept_lifetime_infinite_month_day_cmd_vtysh,
+ "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> infinite",
+ "Set accept lifetime of the key\n"
+ "Time to start\n"
+ "Month of the year to start\n"
+ "Day of th month to start\n"
+ "Year to start\n"
+ "Never expires")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_type_metric_cmd_vtysh,
+ "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214>",
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Routing Information Protocol (RIP)\n"
+ "Border Gateway Protocol (BGP)\n"
+ "OSPF exterior metric type for redistributed routes\n"
+ "Set OSPF External Type 1 metrics\n"
+ "Set OSPF External Type 2 metrics\n"
+ "Metric for redistributed routes\n"
+ "OSPF default metric\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_ipv4_out_cmd_vtysh,
+ "clear ip bgp A.B.C.D ipv4 (unicast|multicast) out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_in_cmd_vtysh,
+ "clear bgp ipv6 (A.B.C.D|X:X::X:X) in",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "BGP neighbor address to clear\n"
+ "BGP IPv6 neighbor to clear\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_out_cmd_vtysh,
+ "clear bgp ipv6 (A.B.C.D|X:X::X:X) out",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "BGP neighbor address to clear\n"
+ "BGP IPv6 neighbor to clear\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, neighbor_override_capability_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "override-capability",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Override capability negotiation result\n")
+
+DEFSH (VTYSH_BGPD, no_dump_bgp_updates_cmd_vtysh,
+ "no dump bgp updates [PATH] [INTERVAL]",
+ "Negate a command or set its defaults\n"
+ "Dump packet\n"
+ "BGP packet dump\n"
+ "Dump BGP updates only\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_lsa_sub_cmd_vtysh,
+ "debug ospf lsa (generate|flooding|install|refresh)",
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n"
+ "OSPF Link State Advertisement\n"
+ "LSA Generation\n"
+ "LSA Flooding\n"
+ "LSA Install/Delete\n"
+ "LSA Refresh\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_hello_interval_cmd_vtysh,
+ "ip ospf hello-interval <1-65535>",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Time between HELLO packets\n"
+ "Seconds\n")
+
+DEFSH (VTYSH_OSPF6D, passive_interface_cmd_vtysh,
+ "passive-interface IFNAME",
+ "Suppress routing updates on an interface\n"
+ "Interface name(e.g. ep0)\n")
+
+DEFSH (VTYSH_BGPD, neighbor_nexthop_self_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "next-hop-self",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Disable the next hop calculation for this neighbor\n")
+
+DEFSH (VTYSH_RIPD, accept_lifetime_month_day_day_month_cmd_vtysh,
+ "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>",
+ "Set accept lifetime of the key\n"
+ "Time to start\n"
+ "Month of the year to start\n"
+ "Day of th month to start\n"
+ "Year to start\n"
+ "Time to expire\n"
+ "Day of th month to expire\n"
+ "Month of the year to expire\n"
+ "Year to expire\n")
+
+DEFSH (VTYSH_ZEBRA, no_ip_route_mask_pref_cmd_vtysh,
+ "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) <1-255>",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Distance value for this route\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_prefix_longer_cmd_vtysh,
+ "show ipv6 bgp X:X::X:X/M longer-prefixes",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Display route and more specific routes\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_static_metric_val_cmd_vtysh,
+ "no redistribute static metric <0-16>",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Static routes\n"
+ "Metric\n"
+ "Metric value\n")
+
+DEFSH (VTYSH_BGPD, no_match_aspath_val_cmd_vtysh,
+ "no match as-path WORD",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "Match BGP AS path list\n"
+ "AS path access-list name\n")
+
+DEFSH (VTYSH_RIPD, no_key_chain_cmd_vtysh,
+ "no key chain WORD",
+ "Negate a command or set its defaults\n"
+ "Authentication key management\n"
+ "Key-chain management\n"
+ "Key-chain name\n")
+
+DEFSH (VTYSH_OSPF6D, show_version_ospf6_cmd_vtysh,
+ "show version ospf6",
+ "Show running system information\n"
+ "Displays ospf6d version\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_cmd_vtysh,
+ "clear bgp (A.B.C.D|X:X::X:X)",
+ "Reset functions\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "BGP IPv6 neighbor to clear\n")
+
+DEFSH (VTYSH_BGPD, bgp_damp_unset_cmd_vtysh,
+ "no bgp dampening",
+ "Negate a command or set its defaults\n"
+ "BGP Specific commands\n"
+ "Enable route-flap dampening\n")
+
+DEFSH (VTYSH_OSPFD, area_import_list_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) import-list NAME",
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Set the filter for networks from other areas announced to the specified one\n"
+ "Name of the access-list\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_metric_routemap_cmd_vtysh,
+ "default-information originate metric <0-16777214> route-map WORD",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "OSPF default metric\n"
+ "OSPF metric\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged2_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path (next-hop|med)",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "As-path attribute\n"
+ "Nexthop attribute\n"
+ "Med attribute\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_group_in_cmd_vtysh,
+ "clear bgp peer-group WORD in",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_dead_interval_cmd_vtysh,
+ "no ospf dead-interval",
+ "Negate a command or set its defaults\n"
+ "OSPF interface commands\n"
+ "Interval after which a neighbor is declared dead\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_all_cmd_vtysh,
+ "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP extended access list\n"
+ "IP standard access list (expanded range)\n"
+ "IP extended access list (expanded range)\n"
+ "IP zebra access-list name\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_seq_ge_cmd_vtysh,
+ "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32>",
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, no_set_ecommunity_rt_val_cmd_vtysh,
+ "no set extcommunity rt .ASN:nn_or_IP-address:nn",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "BGP extended community attribute\n"
+ "Route Target extened communityt\n"
+ "VPN extended community\n")
+
+DEFSH (VTYSH_BGPD, set_atomic_aggregate_cmd_vtysh,
+ "set atomic-aggregate",
+ "Set values in destination routing protocol\n"
+ "BGP atomic aggregate attribute\n" )
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_any_cmd_vtysh,
+ "access-list WORD (deny|permit) any",
+ "Add an access list entry\n"
+ "IP zebra access-list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 10.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_soft_cmd_vtysh,
+ "clear bgp ipv6 <1-65535> soft",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear peers with the AS number\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, debug_bgp_update_cmd_vtysh,
+ "debug bgp updates",
+ "Debugging functions (see also 'undebug')\n"
+ "BGP information\n"
+ "BGP updates\n")
+
+DEFSH (VTYSH_BGPD, no_ip_community_list_cmd_vtysh,
+ "no ip community-list WORD (deny|permit) .AA:NN",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Add a community list entry\n"
+ "Community list name\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n"
+ "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_advertise_interval_val_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X) " "advertisement-interval <0-600>",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Minimum interval between sending BGP routing updates\n"
+ "time in seconds\n")
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv6_metric_cmd_vtysh,
+ "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>",
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPFv3)\n"
+ "Routing Information Protocol (RIPng)\n"
+ "Static routes\n"
+ "Metric for redistributed routes\n"
+ "Default metric\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_prefix_cmd_vtysh,
+ "show bgp X:X::X:X/M",
+ "Show running system information\n"
+ "BGP information\n"
+ "IPv6 prefix <network>/<length>\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_prefix_cmd_vtysh,
+ "show ipv6 bgp X:X::X:X/M",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_out_cmd_vtysh,
+ "clear ip bgp <1-65535> ipv4 (unicast|multicast) out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_advertise_force_prefix_cmd_vtysh,
+ "ipv6 ospf6 advertise force-prefix",
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Advertising options\n"
+ "Force advertising prefix, applicable if Loopback or P-to-P\n"
+ )
+
+DEFSH (VTYSH_BGPD, show_bgp_filter_list_cmd_vtysh,
+ "show bgp filter-list WORD",
+ "Show running system information\n"
+ "BGP information\n"
+ "Display routes conforming to the filter-list\n"
+ "Regular expression access list name\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_in_cmd_vtysh,
+ "clear ip bgp <1-65535> ipv4 (unicast|multicast) in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_soft_out_cmd_vtysh,
+ "clear bgp (A.B.C.D|X:X::X:X) soft out",
+ "Reset functions\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "BGP IPv6 neighbor to clear\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD, rip_distance_cmd_vtysh,
+ "distance <1-255>",
+ "Administrative distance\n"
+ "Distance value\n")
+
+DEFSH (VTYSH_BGPD, set_origin_cmd_vtysh,
+ "set origin (egp|igp|incomplete)",
+ "Set values in destination routing protocol\n"
+ "BGP origin code\n"
+ "remote EGP\n"
+ "local IGP\n"
+ "unknown heritage\n")
+
+DEFSH (VTYSH_OSPFD, ospf_transmit_delay_cmd_vtysh,
+ "ospf transmit-delay <1-65535>",
+ "OSPF interface commands\n"
+ "Link state transmit delay\n"
+ "Seconds\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_port_val_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X) " "port <0-65535>",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Neighbor's BGP port\n"
+ "TCP port number\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ipv6_access_list_cmd_vtysh,
+ "no ipv6 access-list WORD (deny|permit) X:X::X:X/M",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 3ffe:506::/32\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_database_type_id_adv_router_cmd_vtysh,
+ "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*) (A.B.C.D|*) (A.B.C.D|*|dump|summary)",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "LSA Database\n"
+ "Router-LSA\n"
+ "Network-LSA\n"
+ "AS-External-LSA\n"
+ "Intra-Area-Prefix-LSA\n"
+ "Inter-Area-Router-LSA\n"
+ "Inter-Area-Prefix-LSA\n"
+ "Link-LSA\n"
+ "All LS Type\n"
+ "Link State ID\n"
+ "All Link State ID\n"
+ "Advertising Router\n"
+ "All Advertising Router\n"
+ "Dump raw LSA data in Hex\n"
+ "show summary of LSA\n"
+ )
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv6_metric_rmap_cmd_vtysh,
+ "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPFv3)\n"
+ "Routing Information Protocol (RIPng)\n"
+ "Static routes\n"
+ "Metric for redistributed routes\n"
+ "Default metric\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community_exact_cmd_vtysh,
+ "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, no_set_weight_val_cmd_vtysh,
+ "no set weight <0-4294967295>",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "BGP weight for routing table\n"
+ "Weight value\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_ebgp_multihop_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "ebgp-multihop",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Allow EBGP neighbors not on directly connected networks\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_nd_prefix_advertisement_no_val_cmd_vtysh,
+ "ipv6 nd prefix-advertisement IPV6PREFIX",
+ "IP information\n"
+ "Neighbor discovery\n"
+ "Prefix information\n"
+ "IPv6 prefix\n")
+
+DEFSH (VTYSH_BGPD, dump_bgp_all_cmd_vtysh,
+ "dump bgp all PATH",
+ "Dump packet\n"
+ "BGP packet dump\n"
+ "Dump all BGP packets\n"
+ "Output filename\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_ipv4_soft_out_cmd_vtysh,
+ "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_area_route_prefix_cmd_vtysh,
+ "show ipv6 ospf6 area A.B.C.D route (X::X|detail)",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Area information\n"
+ "Area ID (as an IPv4 notation)\n"
+ "Routing Table\n"
+ "Specify IPv6 address\n"
+ "Detailed information\n"
+ )
+
+DEFSH (VTYSH_RIPNGD, ripng_passive_interface_cmd_vtysh,
+ "passive-interface IFNAME",
+ "Suppress routing updates on an interface\n"
+ "Interface name\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_neighbors_peer_cmd_vtysh,
+ "show bgp neighbors (A.B.C.D|X:X::X:X)",
+ "Show running system information\n"
+ "BGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_packet_all_cmd_vtysh,
+ "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n"
+ "OSPF packets\n"
+ "OSPF Hello\n"
+ "OSPF Database Description\n"
+ "OSPF Link State Request\n"
+ "OSPF Link State Update\n"
+ "OSPF Link State Acknowledgment\n"
+ "OSPF all packets\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_seq_cmd_vtysh,
+ "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) (X:X::X:X/M|any)",
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Any prefix match. Same as \"::0/0 le 128\"\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_kernel_cmd_vtysh,
+ "no redistribute kernel",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n")
+
+DEFSH (VTYSH_BGPD, set_weight_cmd_vtysh,
+ "set weight <0-4294967295>",
+ "Set values in destination routing protocol\n"
+ "BGP weight for routing table\n"
+ "Weight value\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_type_routemap_cmd_vtysh,
+ "default-information originate metric-type (1|2) route-map WORD",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "OSPF metric type for default routes\n"
+ "Set OSPF External Type 1 metrics\n"
+ "Set OSPF External Type 2 metrics\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_bgp_metric_cmd_vtysh,
+ "no redistribute bgp metric",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Metric\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_network_cmd_vtysh,
+ "network IF_OR_ADDR",
+ "RIPng enable on specified interface or network.\n"
+ "Interface or address")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_seq_le_ge_cmd_vtysh,
+ "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32> ge <0-32>",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_default_metric_val_cmd_vtysh,
+ "no default-metric <0-16777214>",
+ "Negate a command or set its defaults\n"
+ "Set metric of redistributed routes\n"
+ "Default metric\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_external_cmd_vtysh,
+ "distance ospf external <1-255>",
+ "Define an administrative distance\n"
+ "OSPF Administrative distance\n"
+ "External routes\n"
+ "Distance for external routes\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_scan_time_val_cmd_vtysh,
+ "no bgp scan-time <5-60>",
+ "Negate a command or set its defaults\n"
+ "BGP specific commands\n"
+ "Configure background scanner interval\n"
+ "Scanner interval (seconds)\n")
+
+DEFSH (VTYSH_BGPD, old_ipv6_aggregate_address_summary_only_cmd_vtysh,
+ "ipv6 bgp aggregate-address X:X::X:X/M summary-only",
+ "IPv6 information\n"
+ "BGP information\n"
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_route_cmd_vtysh,
+ "show bgp X:X::X:X",
+ "Show running system information\n"
+ "BGP information\n"
+ "Network in the BGP routing table to display\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_database_type_adv_router_cmd_vtysh,
+ "show ip ospf database (" "asbr-summary|external|network|router|summary" "" "" ") adv-router A.B.C.D",
+ "Show running system information\n"
+ "IP information\n"
+ "OSPF information\n"
+ "Database summary\n"
+ "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "" "" "" ""
+ "Advertising Router link states\n"
+ "Advertising Router (as an IP address)\n")
+
+DEFSH (VTYSH_BGPD, no_ip_community_list_name_all_cmd_vtysh,
+ "no ip community-list (standard|expanded) WORD",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Add a community list entry\n"
+ "Add a standard community-list entry\n"
+ "Add an expanded community-list entry\n"
+ "Community list name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_neighbors_peer_cmd_vtysh,
+ "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display VPNv4 NLRI specific information\n"
+ "Display information about all VPNv4 NLRIs\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_in_cmd_vtysh,
+ "clear ip bgp <1-65535> in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD, ip_rip_send_version_cmd_vtysh,
+ "ip rip send version (1|2)",
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Advertisement transmission\n"
+ "Version control\n"
+ "RIP version 1\n"
+ "RIP version 2\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_authentication_key_cmd_vtysh,
+ "no ospf authentication-key",
+ "Negate a command or set its defaults\n"
+ "OSPF interface commands\n"
+ "Authentication password (key)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_host_host_cmd_vtysh,
+ "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D host A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "A single source host\n"
+ "Source address\n"
+ "A single destination host\n"
+ "Destination address\n")
+
+DEFSH (VTYSH_BGPD, neighbor_dont_capability_negotiate_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "dont-capability-negotiate",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Do not perform capability negotiation\n")
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_param4_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+ "(hello-interval|retransmit-interval|transmit-delay|dead-interval)",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+ "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_in_prefix_filter_cmd_vtysh,
+ "clear ip bgp A.B.C.D in prefix-filter",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "Soft reconfig inbound update\n"
+ "Push out the existing ORF prefix-list\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D",
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_weight_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "weight",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Set default weight for routes from this neighbor\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, clear_ipv6_prefix_list_name_prefix_cmd_vtysh,
+ "clear ipv6 prefix-list WORD X:X::X:X/M",
+ "Reset functions\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+
+DEFSH (VTYSH_ZEBRA, ip_irdp_address_preference_cmd_vtysh,
+ "ip irdp address A.B.C.D <0-2147483647>",
+ "IP information\n"
+ "ICMP Router discovery on this interface\n"
+ "Specify IRDP address and preference to proxy-advertise\n"
+ "Set IRDP address for proxy-advertise\n"
+ "Preference level\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_soft_in_cmd_vtysh,
+ "clear ip bgp external soft in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all external peers\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, no_set_vpnv4_nexthop_cmd_vtysh,
+ "no set vpnv4 next-hop",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "VPNv4 information\n"
+ "VPNv4 next-hop address\n")
+
+DEFSH (VTYSH_BGPD, bgp_multiple_instance_cmd_vtysh,
+ "bgp multiple-instance",
+ "BGP information\n"
+ "Enable bgp multiple instance\n")
+
+DEFSH (VTYSH_BGPD, no_set_ipv6_nexthop_global_cmd_vtysh,
+ "no set ipv6 next-hop global",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "IPv6 information\n"
+ "IPv6 next-hop address\n"
+ "IPv6 global address\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_neighbors_cmd_vtysh,
+ "show bgp neighbors",
+ "Show running system information\n"
+ "BGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n")
+
+DEFSH (VTYSH_RIPD, no_match_ip_next_hop_val_cmd_vtysh,
+ "no match ip next-hop WORD",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "IP information\n"
+ "Match next-hop address of route\n"
+ "IP access-list name\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community2_cmd_vtysh,
+ "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_prefix_list_cmd_vtysh,
+ "show bgp ipv6 prefix-list WORD",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Display routes conforming to the prefix-list\n"
+ "IPv6 prefix-list name\n")
+
+DEFSH (VTYSH_OSPFD, no_area_stub_nosum_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) stub no-summary",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Configure OSPF area as stub\n"
+ "Do not inject inter-area routes into area\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_cmd_vtysh,
+ "clear bgp ipv6 (A.B.C.D|X:X::X:X)",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "BGP neighbor address to clear\n"
+ "BGP IPv6 neighbor to clear\n")
+
+DEFSH (VTYSH_OSPFD, area_shortcut_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) shortcut (default|enable|disable)",
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Configure the area's shortcutting mode\n"
+ "Set default shortcutting behavior\n"
+ "Enable shortcutting through the area\n"
+ "Disable shortcutting through the area\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_kernel_cmd_vtysh,
+ "redistribute kernel",
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_ge_le_cmd_vtysh,
+ "ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32> le <0-32>",
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_default_local_preference_cmd_vtysh,
+ "no bgp default local-preference",
+ "Negate a command or set its defaults\n"
+ "BGP specific commands\n"
+ "Configure BGP defaults\n"
+ "local preference (higher=more preferred)\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_ipv4_soft_in_cmd_vtysh,
+ "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv6_rmap_cmd_vtysh,
+ "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPFv3)\n"
+ "Routing Information Protocol (RIPng)\n"
+ "Static routes\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_route_cmd_vtysh,
+ "show ipv6 ospf6 route",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Routing table\n"
+ )
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_any_mask_cmd_vtysh,
+ "access-list (<100-199>|<2000-2699>) (deny|permit) ip any A.B.C.D A.B.C.D",
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Any source host\n"
+ "Destination address\n"
+ "Destination Wildcard bits\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPF6D, router_zebra_cmd_vtysh,
+ "router zebra",
+ "Enable a routing process\n"
+ "Make connection to zebra daemon\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_cmd_vtysh,
+ "clear ip bgp view WORD *",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP view\n"
+ "view name\n"
+ "Clear all peers\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_default_originate_rmap_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X) " "default-originate route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Originate default route to this neighbor\n"
+ "Route-map to specify criteria to originate default\n"
+ "route-map name\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_cmd_vtysh,
+ "no ipv6 prefix-list WORD",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_authtype_args_authkey_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+ "(authentication|) (message-digest|null) "
+ "(authentication-key|) AUTH_KEY",
+ "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+ "Enable authentication on this virtual link\n" "dummy string \n" "Use null authentication\n" "Use message-digest authentication\n"
+ "Authentication password (key)\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_static_routemap_cmd_vtysh,
+ "redistribute static route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "Static routes\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_RIPD, accept_lifetime_day_month_month_day_cmd_vtysh,
+ "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>",
+ "Set accept lifetime of the key\n"
+ "Time to start\n"
+ "Day of th month to start\n"
+ "Month of the year to start\n"
+ "Year to start\n"
+ "Time to expire\n"
+ "Month of the year to expire\n"
+ "Day of th month to expire\n"
+ "Year to expire\n")
+
+DEFSH (VTYSH_OSPF6D, no_debug_ospf6_all_cmd_vtysh,
+ "no debug ospf6 all",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Turn off ALL OSPFv3 debugging\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_type_metric_cmd_vtysh,
+ "default-information originate always metric-type (1|2) metric <0-16777214>",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "Always advertise default route\n"
+ "OSPF metric type for default routes\n"
+ "Set OSPF External Type 1 metrics\n"
+ "Set OSPF External Type 2 metrics\n"
+ "OSPF default metric\n"
+ "OSPF metric\n")
+
+DEFSH (VTYSH_BGPD, neighbor_route_server_client_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "route-server-client",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Configure a neighbor as Route Server client\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community2_exact_cmd_vtysh,
+ "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, show_bgp_prefix_longer_cmd_vtysh,
+ "show bgp X:X::X:X/M longer-prefixes",
+ "Show running system information\n"
+ "BGP information\n"
+ "IPv6 prefix <network>/<length>\n"
+ "Display route and more specific routes\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_type_cmd_vtysh,
+ "default-information originate metric-type (1|2)",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "OSPF metric type for default routes\n"
+ "Set OSPF External Type 1 metrics\n"
+ "Set OSPF External Type 2 metrics\n")
+
+DEFSH (VTYSH_OSPFD, no_neighbor_priority_cmd_vtysh,
+ "no neighbor A.B.C.D priority <0-255>",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor IP address\n"
+ "Neighbor Priority\n"
+ "Priority\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_distance_source_access_list_cmd_vtysh,
+ "no distance <1-255> A.B.C.D/M WORD",
+ "Negate a command or set its defaults\n"
+ "Define an administrative distance\n"
+ "Administrative distance\n"
+ "IP source prefix\n"
+ "Access list name\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_seq_le_ge_cmd_vtysh,
+ "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32> ge <0-32>",
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "sequence number of an entry\n"
+ "Sequence number\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, neighbor_remote_as_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "remote-as <1-65535>",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Specify a BGP neighbor\n"
+ "AS number\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_lsa_sub_cmd_vtysh,
+ "no debug ospf lsa (generate|flooding|install|refresh)",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n"
+ "OSPF Link State Advertisement\n"
+ "LSA Generation\n"
+ "LSA Flooding\n"
+ "LSA Install/Delete\n"
+ "LSA Refres\n")
+
+DEFSH (VTYSH_BGPD, no_match_origin_cmd_vtysh,
+ "no match origin",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "BGP origin code\n")
+
+DEFSH (VTYSH_BGPD, neighbor_remove_private_as_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "remove-private-AS",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Remove private AS number from outbound updates\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_detail_name_cmd_vtysh,
+ "show ipv6 prefix-list detail WORD",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Detail of prefix lists\n"
+ "Name of a prefix list\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_flap_address_cmd_vtysh,
+ "show ip bgp flap-statistics A.B.C.D",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display flap statistics of routes\n"
+ "Network in the BGP routing table to display\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv4_rmap_cmd_vtysh,
+ "no redistribute (connected|kernel|ospf|rip|static) route-map WORD",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPF)\n"
+ "Routing Information Protocol (RIP)\n"
+ "Static routes\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_group_cmd_vtysh,
+ "clear bgp peer-group WORD",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n")
+
+DEFSH (VTYSH_BGPD, neighbor_interface_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X) " "interface WORD",
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Interface\n"
+ "Interface name\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_soft_in_cmd_vtysh,
+ "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft in",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "BGP neighbor address to clear\n"
+ "BGP IPv6 neighbor to clear\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_all_soft_cmd_vtysh,
+ "clear bgp * soft",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community3_exact_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_neighbor_received_routes_cmd_vtysh,
+ "show ip bgp neighbors (A.B.C.D|X:X::X:X) received-routes",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display the received routes from neighbor\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_mask_summary_as_set_cmd_vtysh,
+ "aggregate-address A.B.C.D A.B.C.D summary-only as-set",
+ "Configure BGP aggregate entries\n"
+ "Aggregate address\n"
+ "Aggregate mask\n"
+ "Filter more specific routes from updates\n"
+ "Generate AS set path information\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_neighbor_routerid_cmd_vtysh,
+ "show ipv6 ospf6 neighbor A.B.C.D",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Neighbor list\n"
+ "OSPF6 neighbor Router ID in IP address format\n"
+ )
+
+DEFSH (VTYSH_BGPD, bgp_cluster_id32_cmd_vtysh,
+ "bgp cluster-id <1-4294967295>",
+ "BGP information\n"
+ "Configure Route-Reflector Cluster-id\n"
+ "Route-Reflector Cluster-id as 32 bit quantity\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_cmd_vtysh,
+ "clear bgp ipv6 <1-65535>",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear peers with the AS number\n")
+
+DEFSH (VTYSH_OSPFD|VTYSH_OSPFD, show_ip_ospf_neighbor_id_cmd_vtysh,
+ "show ip ospf neighbor A.B.C.D",
+ "Show running system information\n"
+ "IP information\n"
+ "OSPF information\n"
+ "Neighbor list\n"
+ "Neighbor ID\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_hello_interval_addr_cmd_vtysh,
+ "no ip ospf hello-interval A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Time between HELLO packets\n"
+ "Address of interface")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_kernel_metric_val_cmd_vtysh,
+ "no redistribute kernel metric <0-16>",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Metric\n"
+ "Metric value\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_rmap_onmatch_goto_cmd_vtysh,
+ "no on-match goto",
+ "Negate a command or set its defaults\n"
+ "Exit policy on matches\n"
+ "Next clause\n")
+
+DEFSH (VTYSH_OSPF6D, ospf6_redistribute_routemap_cmd_vtysh,
+ "redistribute (static|kernel|connected|ripng|bgp) route-map WORD",
+ "Redistribute\n"
+ "Static routes\n"
+ "Kernel route\n"
+ "Connected route\n"
+ "RIPng route\n"
+ "BGP route\n"
+ "Route map reference\n"
+ "Route map name\n"
+ )
+
+DEFSH (VTYSH_BGPD, neighbor_local_as_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as <1-65535>",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Specify a local-as number\n"
+ "AS number used as local AS\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd_vtysh,
+ "clear ip bgp view WORD * ipv4 (unicast|multicast) in prefix-filter",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig inbound update\n"
+ "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_address_prefix_list_val_cmd_vtysh,
+ "no match ip address prefix-list WORD",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "IP information\n"
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged9_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med next-hop as-path",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "Med attribute\n"
+ "Nexthop attribute\n"
+ "As-path attribute\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_nd_ra_interval_cmd_vtysh,
+ "ipv6 nd ra-interval SECONDS",
+ "IP information\n"
+ "Neighbor discovery\n"
+ "Router Advertisement interval\n"
+ "Router Advertisement interval in seconds\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_ospf6_metric_cmd_vtysh,
+ "no redistribute ospf6 metric",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "IPv6 Open Shortest Path First (OSPFv3)\n"
+ "Metric\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community3_cmd_vtysh,
+ "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_timers_connect_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X) " "timers connect",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "BGP per neighbor timers\n"
+ "BGP connect timer\n")
+
+DEFSH (VTYSH_BGPD, set_community_cmd_vtysh,
+ "set community .AA:NN",
+ "Set values in destination routing protocol\n"
+ "BGP community attribute\n"
+ "Community number in aa:nn format or local-AS|no-advertise|no-export|internet or additive\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community_list_exact_cmd_vtysh,
+ "show ip bgp community-list WORD exact-match",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display routes matching the community-list\n"
+ "community-list name\n"
+ "Exact match of the communities\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_cmd_vtysh,
+ "network A.B.C.D/M",
+ "Specify a network to announce via BGP\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_summary_cmd_vtysh,
+ "show ip bgp summary",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_BGPD, no_vpnv4_network_cmd_vtysh,
+ "no network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD",
+ "Negate a command or set its defaults\n"
+ "Specify a network to announce via BGP\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Specify Route Distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "BGP tag\n"
+ "tag value\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_backdoor_cmd_vtysh,
+ "network A.B.C.D/M backdoor",
+ "Specify a network to announce via BGP\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Specify a BGP backdoor route\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_send_community_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Send Community attribute to this neighbor\n")
+
+DEFSH (VTYSH_ZEBRA, debug_zebra_packet_detail_cmd_vtysh,
+ "debug zebra packet (recv|send) detail",
+ "Debugging functions (see also 'undebug')\n"
+ "Zebra configuration\n"
+ "Debug option set for zebra packet\n"
+ "Debug option set for receive packet\n"
+ "Debug option set for send packet\n"
+ "Debug option set detaied information\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_cmd_vtysh,
+ "show ip ospf",
+ "Show running system information\n"
+ "IP information\n"
+ "OSPF information\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_filter_list_cmd_vtysh,
+ "show bgp ipv6 filter-list WORD",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Display routes conforming to the filter-list\n"
+ "Regular expression access list name\n")
+
+DEFSH (VTYSH_RIPD, ip_rip_receive_version_2_cmd_vtysh,
+ "ip rip receive version 2 1",
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Advertisement reception\n"
+ "Version control\n"
+ "RIP version 2\n"
+ "RIP version 1\n")
+
+DEFSH (VTYSH_ZEBRA, ip_irdp_maxadvertinterval_cmd_vtysh,
+ "ip irdp maxadvertinterval (0|<4-1800>)",
+ "IP information\n"
+ "ICMP Router discovery on this interface\n"
+ "Set maximum time between advertisement\n"
+ "Maximum advertisement interval in seconds\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_prefix_longer_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Display route and more specific routes\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_all_soft_in_cmd_vtysh,
+ "clear bgp * soft in",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_default_ipv4_unicast_cmd_vtysh,
+ "no bgp default ipv4-unicast",
+ "Negate a command or set its defaults\n"
+ "BGP specific commands\n"
+ "Configure BGP defaults\n"
+ "Activate ipv4-unicast for a peer by default\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_area_topology_router_lsid_cmd_vtysh,
+ "show ipv6 ospf6 area A.B.C.D topology (A.B.C.D|<0-4294967295>) (A.B.C.D|<0-4294967295>)",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Area information\n"
+ "Area ID (as an IPv4 notation)\n"
+ "Shortest Path First tree information\n"
+ "Displays SPF topology table\n"
+ "Specify Router-ID\n"
+ "Specify Router-ID\n"
+ "Specify Link State ID\n"
+ "Specify Link State ID\n"
+ )
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_nd_managed_config_flag_cmd_vtysh,
+ "no ipv6 nd managed-config-flag",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Neighbor discovery\n"
+ "Managed address configuration flag\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_message_digest_key_cmd_vtysh,
+ "no ospf message-digest-key <1-255>",
+ "Negate a command or set its defaults\n"
+ "OSPF interface commands\n"
+ "Message digest authentication password (key)\n"
+ "Key ID\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_le_cmd_vtysh,
+ "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128>",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_prefix_first_match_cmd_vtysh,
+ "show ip prefix-list WORD A.B.C.D/M first-match",
+ "Show running system information\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "First matched prefix\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_zebra_cmd_vtysh,
+ "debug ospf zebra",
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n"
+ "OSPF Zebra information\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_database_type_id_self_cmd_vtysh,
+ "show ip ospf database (" "asbr-summary|external|network|router|summary" "" "" ") A.B.C.D (self-originate|)",
+ "Show running system information\n"
+ "IP information\n"
+ "OSPF information\n"
+ "Database summary\n"
+ "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "" "" "" ""
+ "Link State ID (as an IP address)\n"
+ "Self-originated link states\n"
+ "\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_neighbor_flap_cmd_vtysh,
+ "show ip bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display flap statistics of the routes learned from neighbor\n")
+
+DEFSH (VTYSH_BGPD, no_ip_as_path_all_cmd_vtysh,
+ "no ip as-path access-list WORD",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "BGP autonomous system path filter\n"
+ "Specify an access list name\n"
+ "Regular expression access list name\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_ipv4_in_cmd_vtysh,
+ "clear ip bgp * ipv4 (unicast|multicast) in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_out_cmd_vtysh,
+ "clear ip bgp A.B.C.D out",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_database_cmd_vtysh,
+ "show ip ospf database",
+ "Show running system information\n"
+ "IP information\n"
+ "OSPF information\n"
+ "Database summary\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_interface_ifname_cmd_vtysh,
+ "show ipv6 ospf6 interface IFNAME",
+ "Show running system information\n"
+ "IPv6 Information\n"
+ "Open Shortest Path First (OSPF) for IPv6\n"
+ "Interface infomation\n"
+ "Interface name(e.g. ep0)\n"
+ )
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_cmd_vtysh,
+ "clear ip bgp peer-group WORD",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all members of peer-group\n"
+ "BGP peer-group name\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_maximum_prefix_val2_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X) " "maximum-prefix <1-4294967295> warning-only",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Maximum number of prefix accept from this peer\n"
+ "maximum no. of prefix limit\n"
+ "Only give warning message when limit is exceeded\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_flap_regexp_cmd_vtysh,
+ "show ip bgp flap-statistics regexp .LINE",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display flap statistics of routes\n"
+ "Display routes matching the AS path regular expression\n"
+ "A regular-expression to match the BGP AS paths\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_as_soft_in_cmd_vtysh,
+ "clear bgp <1-65535> soft in",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd_vtysh,
+ "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received prefix-filter",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display information received from a BGP neighbor\n"
+ "Display the prefixlist filter\n")
+
+DEFSH (VTYSH_RIPD, rip_version_cmd_vtysh,
+ "version <1-2>",
+ "Set routing protocol version\n"
+ "version\n")
+
+DEFSH (VTYSH_RIPD, ip_rip_send_version_1_cmd_vtysh,
+ "ip rip send version 1 2",
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Advertisement transmission\n"
+ "Version control\n"
+ "RIP version 1\n"
+ "RIP version 2\n")
+
+DEFSH (VTYSH_RIPD, no_debug_rip_zebra_cmd_vtysh,
+ "no debug rip zebra",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "RIP information\n"
+ "RIP and ZEBRA communication\n")
+
+DEFSH (VTYSH_BGPD, set_aspath_prepend_cmd_vtysh,
+ "set as-path prepend .<1-65535>",
+ "Set values in destination routing protocol\n"
+ "Prepend string for a BGP AS-path attribute\n"
+ "Prepend to the as-path\n"
+ "AS number\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_neighbor_received_routes_cmd_vtysh,
+ "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Display the received routes from neighbor\n")
+
+DEFSH (VTYSH_RIPNGD, debug_ripng_packet_detail_cmd_vtysh,
+ "debug ripng packet (recv|send) detail",
+ "Debugging functions (see also 'undebug')\n"
+ "RIPng configuration\n"
+ "Debug option set for ripng packet\n"
+ "Debug option set for receive packet\n"
+ "Debug option set for send packet\n"
+ "Debug option set detaied information\n")
+
+DEFSH (VTYSH_ZEBRA, ip_irdp_minadvertinterval_cmd_vtysh,
+ "ip irdp minadvertinterval <3-1800>",
+ "IP information\n"
+ "ICMP Router discovery on this interface\n"
+ "Set minimum time between advertisement\n"
+ "Minimum advertisement interval in seconds\n")
+
+DEFSH (VTYSH_OSPF6D, no_passive_interface_cmd_vtysh,
+ "no passive-interface IFNAME",
+ "Negate a command or set its defaults\n"
+ "Suppress routing updates on an interface\n"
+ "Interface name(e.g. ep0)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD, no_match_interface_val_cmd_vtysh,
+ "no match interface WORD",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "Match first hop interface of route\n"
+ "Interface name\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_mask_natural_route_map_cmd_vtysh,
+ "network A.B.C.D route-map WORD",
+ "Specify a network to announce via BGP\n"
+ "Network number\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged9_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med next-hop as-path",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "Med attribute\n"
+ "Nexthop attribute\n"
+ "As-path attribute\n")
+
+DEFSH (VTYSH_BGPD, ip_extcommunity_list_name_standard2_cmd_vtysh,
+ "ip extcommunity-list standard WORD (deny|permit)",
+ "IP information\n"
+ "Add a extended community list entry\n"
+ "Specify standard extcommunity-list\n"
+ "Extended Community list name\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_soft_out_cmd_vtysh,
+ "clear bgp ipv6 <1-65535> soft out",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear peers with the AS number\n"
+ "Soft reconfig\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, no_ip_community_list_standard_cmd_vtysh,
+ "no ip community-list <1-99> (deny|permit) .AA:NN",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Add a community list entry\n"
+ "Community list number (standard)\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n"
+ "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n")
+
+DEFSH (VTYSH_BGPD, debug_bgp_update_direct_cmd_vtysh,
+ "debug bgp updates (in|out)",
+ "Debugging functions (see also 'undebug')\n"
+ "BGP information\n"
+ "BGP updates\n"
+ "Inbound updates\n"
+ "Outbound updates\n")
+
+DEFSH (VTYSH_OSPFD, show_debugging_ospf_cmd_vtysh,
+ "show debugging ospf",
+ "Show running system information\n"
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_cmd_vtysh,
+ "default-information originate",
+ "Control distribution of default information\n"
+ "Distribute a default route\n")
+
+DEFSH (VTYSH_OSPF6D, ospf6_redistribute_cmd_vtysh,
+ "redistribute (static|kernel|connected|ripng|bgp)",
+ "Redistribute\n"
+ "Static route\n"
+ "Kernel route\n"
+ "Connected route\n"
+ "RIPng route\n"
+ "BGP route\n"
+ )
+
+DEFSH (VTYSH_OSPFD, ip_ospf_transmit_delay_addr_cmd_vtysh,
+ "ip ospf transmit-delay <1-65535> A.B.C.D",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Link state transmit delay\n"
+ "Seconds\n"
+ "Address of interface")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community2_exact_cmd_vtysh,
+ "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "MBGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_OSPFD, area_export_list_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) export-list NAME",
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Set the filter for networks announced to other areas\n"
+ "Name of the access-list\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_detail_name_cmd_vtysh,
+ "show ip prefix-list detail WORD",
+ "Show running system information\n"
+ "IP information\n"
+ "Build a prefix list\n"
+ "Detail of prefix lists\n"
+ "Name of a prefix list\n")
+
+DEFSH (VTYSH_BGPD, bgp_damp_set3_cmd_vtysh,
+ "bgp dampening",
+ "BGP Specific commands\n"
+ "Enable route-flap dampening\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_packet_send_recv_detail_cmd_vtysh,
+ "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) (detail|)",
+ "Debugging functions\n"
+ "OSPF information\n"
+ "OSPF packets\n"
+ "OSPF Hello\n"
+ "OSPF Database Description\n"
+ "OSPF Link State Request\n"
+ "OSPF Link State Update\n"
+ "OSPF Link State Acknowledgment\n"
+ "OSPF all packets\n"
+ "Packet sent\n"
+ "Packet received\n"
+ "Detail Information\n")
+
+DEFSH (VTYSH_BGPD, bgp_default_ipv4_unicast_cmd_vtysh,
+ "bgp default ipv4-unicast",
+ "BGP specific commands\n"
+ "Configure BGP defaults\n"
+ "Activate ipv4-unicast for a peer by default\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_prefix_list_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "prefix-list WORD (in|out)",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Filter updates to/from this neighbor\n"
+ "Name of a prefix list\n"
+ "Filter incoming updates\n"
+ "Filter outgoing updates\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv4_rmap_metric_cmd_vtysh,
+ "no redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>",
+ "Negate a command or set its defaults\n"
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Kernel routes\n"
+ "Open Shurtest Path First (OSPF)\n"
+ "Routing Information Protocol (RIP)\n"
+ "Static routes\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n"
+ "Metric for redistributed routes\n"
+ "Default metric\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_ipv4_soft_cmd_vtysh,
+ "clear ip bgp view WORD * ipv4 (unicast|multicast) soft",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP view\n"
+ "view name\n"
+ "Clear all peers\n"
+ "Address family\n"
+ "Address Family Modifier\n"
+ "Address Family Modifier\n"
+ "Soft reconfig\n")
+
+DEFSH (VTYSH_OSPFD, area_range_cost_cmd_vtysh,
+ "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M cost <0-16777215>",
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Configure OSPF area range for route summarization\n"
+ "area range prefix\n"
+ "User specified metric for this range\n"
+ "Advertised metric for this range\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_cmd_vtysh,
+ "clear ip bgp *",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_cmd_vtysh,
+ "clear ip bgp <1-65535>",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n")
+
+DEFSH (VTYSH_BGPD, no_ip_community_list_expanded_cmd_vtysh,
+ "no ip community-list <100-199> (deny|permit) .LINE",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Add a community list entry\n"
+ "Community list number (expanded)\n"
+ "Specify community to reject\n"
+ "Specify community to accept\n"
+ "An ordered list as a regular-expression\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_tags_cmd_vtysh,
+ "show ip bgp vpnv4 all tags",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display VPNv4 NLRI specific information\n"
+ "Display information about all VPNv4 NLRIs\n"
+ "Display BGP tags for prefixes\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged3_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop (as-path|med)",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "Nexthop attribute\n"
+ "As-path attribute\n"
+ "Med attribute\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_prefix_cmd_vtysh,
+ "show ip bgp vpnv4 all A.B.C.D/M",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display VPNv4 NLRI specific information\n"
+ "Display information about all VPNv4 NLRIs\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_as_in_prefix_filter_cmd_vtysh,
+ "clear bgp <1-65535> in prefix-filter",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Soft reconfig inbound update\n"
+ "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, match_origin_cmd_vtysh,
+ "match origin (egp|igp|incomplete)",
+ "Match values from routing table\n"
+ "BGP origin code\n"
+ "remote EGP\n"
+ "local IGP\n"
+ "unknown heritage\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_ism_cmd_vtysh,
+ "no debug ospf ism",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "OSPF information\n"
+ "OSPF Interface State Machine")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_vpnv4_in_cmd_vtysh,
+ "clear ip bgp A.B.C.D vpnv4 unicast in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP neighbor address to clear\n"
+ "Address family\n"
+ "Address Family Modifier\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_ipv4_in_prefix_filter_cmd_vtysh,
+ "clear ip bgp * ipv4 (unicast|multicast) in prefix-filter",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Soft reconfig inbound update\n"
+ "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_network_cmd_vtysh,
+ "no ospf network",
+ "Negate a command or set its defaults\n"
+ "OSPF interface commands\n"
+ "Network type\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_le_ge_cmd_vtysh,
+ "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128> ge <0-128>",
+ "Negate a command or set its defaults\n"
+ "IPv6 information\n"
+ "Build a prefix list\n"
+ "Name of a prefix list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Maximum prefix length to be matched\n"
+ "Maximum prefix length\n"
+ "Minimum prefix length to be matched\n"
+ "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_remote_as_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X) " "remote-as <1-65535>",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Specify a BGP neighbor\n"
+ "AS number\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_neighbor_cmd_vtysh,
+ "show ip ospf neighbor",
+ "Show running system information\n"
+ "IP information\n"
+ "OSPF information\n"
+ "Neighbor list\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_soft_in_cmd_vtysh,
+ "clear ip bgp <1-65535> soft in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, neighbor_capability_orf_prefix_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "capability orf prefix-list (both|send|receive)",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Advertise capability to the peer\n"
+ "Advertise ORF capability to the peer\n"
+ "Advertise prefixlist ORF capability to this neighbor\n"
+ "Capability to SEND and RECEIVE the ORF to/from this neighbor\n"
+ "Capability to RECEIVE the ORF from this neighbor\n"
+ "Capability to SEND the ORF to this neighbor\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_as_out_cmd_vtysh,
+ "clear bgp <1-65535> out",
+ "Reset functions\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_neighbor_detail_cmd_vtysh,
+ "show ip ospf neighbor detail",
+ "Show running system information\n"
+ "IP information\n"
+ "OSPF information\n"
+ "Neighbor list\n"
+ "detail of all neighbors\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, match_ip_next_hop_prefix_list_cmd_vtysh,
+ "match ip next-hop prefix-list WORD",
+ "Match values from routing table\n"
+ "IP information\n"
+ "Match next-hop address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_distance_cmd_vtysh,
+ "no distance <1-255>",
+ "Negate a command or set its defaults\n"
+ "Define an administrative distance\n"
+ "OSPF Administrative distance\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_interface_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X) " "interface WORD",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Interface\n"
+ "Interface name\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_type_cmd_vtysh,
+ "default-information originate always metric-type (1|2)",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "Always advertise default route\n"
+ "OSPF metric type for default routes\n"
+ "Set OSPF External Type 1 metrics\n"
+ "Set OSPF External Type 2 metrics\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_default_metric_val_cmd_vtysh,
+ "no default-metric <1-16>",
+ "Negate a command or set its defaults\n"
+ "Set a metric of redistribute routes\n"
+ "Default metric\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_route_map_cmd_vtysh,
+ "show ip bgp route-map WORD",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display routes matching the route-map\n"
+ "A route-map to match on\n")
+
+DEFSH (VTYSH_BGPD, set_originator_id_cmd_vtysh,
+ "set originator-id A.B.C.D",
+ "Set values in destination routing protocol\n"
+ "BGP originator ID attribute\n"
+ "IP address of originator\n")
+
+DEFSH (VTYSH_RIPD, debug_rip_packet_direct_cmd_vtysh,
+ "debug rip packet (recv|send)",
+ "Debugging functions (see also 'undebug')\n"
+ "RIP information\n"
+ "RIP packet\n"
+ "RIP receive packet\n"
+ "RIP send packet\n")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_summary_only_cmd_vtysh,
+ "no aggregate-address A.B.C.D/M summary-only",
+ "Negate a command or set its defaults\n"
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_view_route_cmd_vtysh,
+ "show ip bgp view WORD A.B.C.D",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "BGP view\n"
+ "BGP view name\n"
+ "Network in the BGP routing table to display\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_receive_version_num_cmd_vtysh,
+ "no ip rip receive version (1|2)",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Routing Information Protocol\n"
+ "Advertisement reception\n"
+ "Version control\n"
+ "Version 1\n"
+ "Version 2\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_vpnv4_soft_in_cmd_vtysh,
+ "clear ip bgp * vpnv4 unicast soft in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear all peers\n"
+ "Address family\n"
+ "Address Family Modifier\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD, accept_lifetime_duration_day_month_cmd_vtysh,
+ "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> duration <1-2147483646>",
+ "Set accept lifetime of the key\n"
+ "Time to start\n"
+ "Day of th month to start\n"
+ "Month of the year to start\n"
+ "Year to start\n"
+ "Duration of the key\n"
+ "Duration seconds\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_address_cmd_vtysh,
+ "no match ip address",
+ "Negate a command or set its defaults\n"
+ "Match values from routing table\n"
+ "IP information\n"
+ "Match address of route\n")
+
+DEFSH (VTYSH_ZEBRA, show_ipv6_route_protocol_cmd_vtysh,
+ "show ipv6 route (bgp|connected|kernel|ospf6|ripng|static)",
+ "Show running system information\n"
+ "IP information\n"
+ "IP routing table\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Connected\n"
+ "Kernel\n"
+ "Open Shortest Path First (OSPFv3)\n"
+ "Routing Information Protocol (RIPng)\n"
+ "Static routes\n")
+
+DEFSH (VTYSH_ZEBRA, ip_address_label_cmd_vtysh,
+ "ip address A.B.C.D/M label LINE",
+ "Interface Internet Protocol config commands\n"
+ "Set the IP address of an interface\n"
+ "IP address (e.g. 10.0.0.1/8)\n"
+ "Label of this address\n"
+ "Label\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community4_exact_cmd_vtysh,
+ "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_priority_addr_cmd_vtysh,
+ "no ip ospf priority A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Router priority\n"
+ "Address of interface")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_neighbors_peer_cmd_vtysh,
+ "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X)",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n")
+
+DEFSH (VTYSH_OSPFD, auto_cost_reference_bandwidth_cmd_vtysh,
+ "auto-cost reference-bandwidth <1-4294967>",
+ "Calculate OSPF interface cost according to bandwidth\n"
+ "Use reference bandwidth method to assign OSPF cost\n"
+ "The reference bandwidth in terms of Mbits per second\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_out_cmd_vtysh,
+ "clear bgp ipv6 * out",
+ "Reset functions\n"
+ "BGP information\n"
+ "Address family\n"
+ "Clear all peers\n"
+ "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_cmd_vtysh,
+ "aggregate-address A.B.C.D/M",
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community_exact_cmd_vtysh,
+ "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Display routes matching the communities\n"
+ "community number\n"
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, no_set_ipv6_nexthop_local_cmd_vtysh,
+ "no set ipv6 next-hop local",
+ "Negate a command or set its defaults\n"
+ "Set values in destination routing protocol\n"
+ "IPv6 information\n"
+ "IPv6 next-hop address\n"
+ "IPv6 local address\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_instance_all_soft_in_cmd_vtysh,
+ "clear bgp view WORD * soft in",
+ "Reset functions\n"
+ "BGP information\n"
+ "BGP view\n"
+ "view name\n"
+ "Clear all peers\n"
+ "Soft reconfig\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_prefix_list_cmd_vtysh,
+ "show ip bgp prefix-list WORD",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display routes conforming to the prefix-list\n"
+ "IP prefix-list name\n")
+
+DEFSH (VTYSH_BGPD, neighbor_set_peer_group_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X) " "peer-group WORD",
+ "Specify neighbor router\n"
+ "Neighbor address\nIPv6 address\n"
+ "Member of the peer-group\n"
+ "peer-group name\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_standard_any_cmd_vtysh,
+ "no access-list (<1-99>|<1300-1999>) (deny|permit) any",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP standard access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any source host\n")
+
+DEFSH (VTYSH_BGPD, no_auto_summary_cmd_vtysh,
+ "no auto-summary",
+ "Negate a command or set its defaults\n"
+ "Enable automatic network number summarization\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_network_cmd_vtysh,
+ "no ip ospf network",
+ "Negate a command or set its defaults\n"
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Network type\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged3_cmd_vtysh,
+ "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop (as-path|med)",
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "BGP attribute is propagated unchanged to this neighbor\n"
+ "Nexthop attribute\n"
+ "As-path attribute\n"
+ "Med attribute\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_mask_any_cmd_vtysh,
+ "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D any",
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Source address\n"
+ "Source wildcard bits\n"
+ "Any destination host\n")
+
+DEFSH (VTYSH_BGPD, no_ipv6_aggregate_address_summary_only_cmd_vtysh,
+ "no aggregate-address X:X::X:X/M summary-only",
+ "Negate a command or set its defaults\n"
+ "Configure BGP aggregate entries\n"
+ "Aggregate prefix\n"
+ "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_standard_nomask_cmd_vtysh,
+ "no access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP standard access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Address to match\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community_list_exact_cmd_vtysh,
+ "show bgp ipv6 community-list WORD exact-match",
+ "Show running system information\n"
+ "BGP information\n"
+ "Address family\n"
+ "Display routes matching the community-list\n"
+ "community-list name\n"
+ "Exact match of the communities\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_vpnv4_in_cmd_vtysh,
+ "clear ip bgp <1-65535> vpnv4 unicast in",
+ "Reset functions\n"
+ "IP information\n"
+ "BGP information\n"
+ "Clear peers with the AS number\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_retransmit_interval_cmd_vtysh,
+ "ip ospf retransmit-interval <3-65535>",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Time between retransmitting lost link state advertisements\n"
+ "Seconds\n")
+
+DEFSH (VTYSH_ZEBRA, no_ip_route_cmd_vtysh,
+ "no ip route A.B.C.D/M (A.B.C.D|INTERFACE)",
+ "Negate a command or set its defaults\n"
+ "IP information\n"
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_cmd_vtysh,
+ "show ip bgp vpnv4 all",
+ "Show running system information\n"
+ "IP information\n"
+ "BGP information\n"
+ "Display VPNv4 NLRI specific information\n"
+ "Display information about all VPNv4 NLRIs\n")
+
+DEFSH (VTYSH_RIPD, no_key_string_cmd_vtysh,
+ "no key-string [LINE]",
+ "Negate a command or set its defaults\n"
+ "Unset key string\n"
+ "The key\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_soft_reconfiguration_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "soft-reconfiguration inbound",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Per neighbor soft reconfiguration\n"
+ "Allow inbound soft reconfiguration for this neighbor\n")
+
+DEFSH (VTYSH_BGPD, no_debug_bgp_events_cmd_vtysh,
+ "no debug bgp events",
+ "Negate a command or set its defaults\n"
+ "Debugging functions (see also 'undebug')\n"
+ "BGP information\n"
+ "BGP events\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) ",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n")
+
+DEFSH (VTYSH_ZEBRA, ip_irdp_holdtime_cmd_vtysh,
+ "ip irdp holdtime <0-9000>",
+ "IP information\n"
+ "ICMP Router discovery on this interface\n"
+ "Set holdtime value\n"
+ "Holdtime value in seconds. Default is 1800 seconds\n")
+
+DEFSH (VTYSH_BGPD, match_community_cmd_vtysh,
+ "match community (<1-99>|<100-199>|WORD)",
+ "Match values from routing table\n"
+ "Match BGP community list\n"
+ "Community-list number (standard)\n"
+ "Community-list number (expanded)\n"
+ "Community-list name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_extcommunity_list_cmd_vtysh,
+ "show ip extcommunity-list",
+ "Show running system information\n"
+ "IP information\n"
+ "List extended-community list\n")
+
+DEFSH (VTYSH_OSPF6D, no_interface_area_cmd_vtysh,
+ "no interface IFNAME area A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Disable routing on an IPv6 interface\n"
+ "Interface name(e.g. ep0)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_host_mask_cmd_vtysh,
+ "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D A.B.C.D A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "A single source host\n"
+ "Source address\n"
+ "Destination address\n"
+ "Destination Wildcard bits\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_cmd_vtysh,
+ "access-list WORD (deny|permit) A.B.C.D/M",
+ "Add an access list entry\n"
+ "IP zebra access-list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 10.0.0.0/8\n")
+
+DEFSH (VTYSH_OSPFD, no_area_range_cmd_vtysh,
+ "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M",
+ "Negate a command or set its defaults\n"
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Deconfigure OSPF area range for route summarization\n"
+ "area range prefix\n")
+
+DEFSH (VTYSH_BGPD, old_ipv6_bgp_network_cmd_vtysh,
+ "ipv6 bgp network X:X::X:X/M",
+ "IPv6 information\n"
+ "BGP information\n"
+ "Specify a network to announce via BGP\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_filter_list_cmd_vtysh,
+ "no neighbor (A.B.C.D|X:X::X:X|WORD) " "filter-list WORD (in|out)",
+ "Negate a command or set its defaults\n"
+ "Specify neighbor router\n"
+ "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+ "Establish BGP filters\n"
+ "AS path access-list name\n"
+ "Filter incoming routes\n"
+ "Filter outgoing routes\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community_list_exact_cmd_vtysh,
+ "show ipv6 bgp community-list WORD exact-match",
+ "Show running system information\n"
+ "IPv6 information\n"
+ "BGP information\n"
+ "Display routes matching the community-list\n"
+ "community-list name\n"
+ "Exact match of the communities\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_connected_routemap_cmd_vtysh,
+ "redistribute connected route-map WORD",
+ "Redistribute information from another routing protocol\n"
+ "Connected\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, undebug_bgp_events_cmd_vtysh,
+ "undebug bgp events",
+ "Disable debugging functions (see also 'debug')\n"
+ "BGP information\n"
+ "BGP events\n")
+
+void
+vtysh_init_cmd ()
+{
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_tags_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_detail_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_neighbors_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_all_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_instance_summary_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_peer_in_prefix_filter_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged1_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged9_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_ospf_nsm_sub_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_ospf_message_digest_key_addr_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_static_metric_routemap_cmd_vtysh);
+ install_element (OSPF_NODE, &no_network_area_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_version_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_prefix_list_name_seq_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_route_server_client_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_community_list_name_all_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_always_type_routemap_cmd_vtysh);
+ install_element (OSPF6_NODE, &interface_area_passive_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_ospf_packet_all_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_map_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_distance_ospf_external_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_ospf_ism_sub_cmd_vtysh);
+ install_element (CONFIG_NODE, &access_list_standard_nomask_cmd_vtysh);
+ install_element (RMAP_NODE, &match_aspath_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_peer_in_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_out_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_ospf_nsm_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_metric_type_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_connected_metric_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_community_list_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_ospf_lsa_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_activate_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_route_server_client_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_area_route_cmd_vtysh);
+ install_element (CONFIG_NODE, &access_list_extended_any_host_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_in_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_external_soft_in_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_prefix_list_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_rip_authentication_string_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_prefix_list_seq_ge_le_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_ospf_neighbor_int_detail_cmd_vtysh);
+ install_element (RMAP_NODE, &set_vpnv4_nexthop_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_summary_only_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_prefix_longer_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_ecommunity_rt_val_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_in_cmd_vtysh);
+ install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_timers_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_neighborlist_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_cmd_vtysh);
+ install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd_vtysh);
+ install_element (OSPF6_NODE, &interface_area_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_redistribute_source_metric_type_routemap_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_all_out_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_prefix_longer_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_zebra_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged9_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_regexp_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_all_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_origin_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_route_prefix_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_ospf_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_cmd_vtysh);
+ install_element (RMAP_NODE, &match_ip_address_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_paths_cmd_vtysh);
+ install_element (ZEBRA_NODE, &no_redistribute_ospf6_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_timers_connect_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_aspath_prepend_val_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_longer_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &aggregate_address_as_set_summary_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_static_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_rip_send_version_cmd_vtysh);
+ install_element (RIPNG_NODE, &default_information_originate_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged2_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_filter_list_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_metric_cmd_vtysh);
+ install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_ospf_database_type_id_self_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_as_path_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_bgp_normal_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_bgp_network_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_unsuppress_map_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_out_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_prefix_list_name_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_adv_router_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_cidr_only_cmd_vtysh);
+ install_element (RMAP_NODE, &match_metric_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_prefix_list_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_allowas_in_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_in_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_route_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_addr_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_community3_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_attr_info_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_in_cmd_vtysh);
+ install_element (KEYCHAIN_NODE, &no_key_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_view_prefix_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_cmd_vtysh);
+ install_element (CONFIG_NODE, &access_list_extended_host_mask_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_community_exact_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_community2_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_all_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_ripng_zebra_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_route_map_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_attr_unchanged1_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_ospf_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_prefix_list_name_seq_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_area_topology_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_peer_group_in_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ospf_cost_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_longer_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_atomic_aggregate_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_community_list_exact_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_as_out_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged_cmd_vtysh);
+ install_element (BGP_NODE, &no_aggregate_address_mask_as_set_cmd_vtysh);
+ install_element (CONFIG_NODE, &router_zebra_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_val2_cmd_vtysh);
+ install_element (RMAP_NODE, &match_ipv6_next_hop_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_router_zebra_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_summary_cmd_vtysh);
+ install_element (OSPF_NODE, &neighbor_pollinterval_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_route_pref_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_all_soft_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_prefix_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_community_exact_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_prefix_filter_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_community4_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_zebra_packet_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_local_as_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_as_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_list_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_prefix_list_detail_name_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged4_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_instance_all_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_send_community_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_vpnv4_nexthop_val_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_damp_set3_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh);
+ install_element (CONFIG_NODE, &access_list_extended_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_soft_reconfiguration_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_community_all_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_ospf_neighbor_id_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ospf_retransmit_interval_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_default_ipv4_unicast_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_ripng_packet_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_prefix_list_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_longer_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_always_compare_med_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_filter_list_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_list_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_summary_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_out_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_community3_exact_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_bgp_multiple_instance_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_external_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_nd_prefix_advertisement_no_val_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_out_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_out_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_attr_unchanged2_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_val2_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged3_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_community2_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged3_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_route_server_client_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_in_cmd_vtysh);
+ install_element (ENABLE_NODE, &undebug_bgp_events_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_type_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_access_list_all_cmd_vtysh);
+ install_element (OSPF_NODE, &no_ospf_distance_ospf_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &bgp_network_mask_cmd_vtysh);
+ install_element (RMAP_NODE, &match_community_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_metric_routemap_cmd_vtysh);
+ install_element (CONFIG_NODE, &bgp_config_type_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged3_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_extcommunity_list_all_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_as_set_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_remark_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_cidr_only_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_confederation_peers_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_distribute_list_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_cidr_only_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_name_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_ge_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_distance_ospf_inter_external_intra_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_exact_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_all_in_prefix_filter_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_prefix_filter_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_attr_unchanged_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_bestpath_med3_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_summary_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_in_prefix_filter_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_neighbor_advertised_route_cmd_vtysh);
+ install_element (OSPF_NODE, &area_authentication_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_redistribute_source_type_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_timers_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_address_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_ospf_event_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_external_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_zebra_packet_detail_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged7_cmd_vtysh);
+ install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_community_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_community2_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_ospf_database_type_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_standard_nomask_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_exact_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_route_map_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_community_val_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_topology_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_tree_cmd_vtysh);
+ install_element (OSPF6_NODE, &interface_area_plist_passive_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_community3_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_summary_cmd_vtysh);
+ install_element (OSPF_NODE, &neighbor_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_attr_unchanged4_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_distance_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_route_ifname_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_prefix_list_seq_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &bgp_network_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_network_mask_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_bgp_fsm_cmd_vtysh);
+ install_element (OSPF_NODE, &no_passive_interface_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_ospf_lsa_sub_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_irdp_maxadvertinterval_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_rip_receive_version_num_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_all_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_route_ifname_cmd_vtysh);
+ install_element (KEYCHAIN_NODE, &no_key_chain_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_filter_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_prefix_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_view_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_community4_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_community_all_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_client_to_client_reflection_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_maximum_prefix_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_router_lsid_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_redistribute_source_type_routemap_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ipv6_address_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_allowas_in_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_prefix_list_seq_ge_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_retransmitinterval_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_community_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_extcommunity_list_arg_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_filter_list_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_route_reflector_client_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_cluster_id_cmd_vtysh);
+ install_element (OSPF_NODE, &no_neighbor_priority_pollinterval_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_bgp_normal_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_routes_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_prefix_list_name_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_neighbors_peer_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_out_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_confederation_peers_cmd_vtysh);
+ install_element (RMAP_NODE, &set_local_pref_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_peer_group_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_ospf_message_digest_key_addr_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_bgp_update_direct_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_cmd_vtysh);
+ install_element (ENABLE_NODE, &undebug_bgp_fsm_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_neighbors_peer_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_import_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_peer_soft_out_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_ebgp_multihop_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_cmd_vtysh);
+ install_element (BGP_NODE, &aggregate_address_mask_cmd_vtysh);
+ install_element (BGP_NODE, &old_no_ipv6_aggregate_address_summary_only_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_forwarding_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_cmd_vtysh);
+ install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_local_as_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_name_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_redistribute_source_metric_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_distance_ospf_inter_intra_cmd_vtysh);
+ install_element (RMAP_NODE, &set_community_none_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_bgp_update_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_network_route_map_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_database_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_default_local_preference_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_transparent_nexthop_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_out_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_ospf_dead_interval_addr_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_distribute_list_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_all_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_nexthop_self_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_passive_interface_cmd_vtysh);
+ install_element (CONFIG_NODE, &access_list_extended_any_mask_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_in_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_extcommunity_list_name_expanded_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_le_ge_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_area_topology_router_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_all_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_external_out_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_infinite_day_month_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_as_set_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_ripng_zebra_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_bgp_events_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_ripng_packet_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_network_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_in_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_distribute_list_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_vlink_param4_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_nexthop_self_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_prefix_list_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_rip_authentication_string2_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_out_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_bgp_keepalive_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_interface_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_ospf_network_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_route_pref_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_prefix_filter_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_damp_set_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_route_mask_pref_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_prefix_list_summary_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_in_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_prefix_list_prefix_longer_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_bgp_events_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh);
+ install_element (RMAP_NODE, &set_origin_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_debug_ospf6_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_external_out_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_community2_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_prefix_list_ge_le_cmd_vtysh);
+ install_element (RMAP_NODE, &set_community_delete_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_as_in_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_capability_dynamic_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_rip_send_version_num_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_rip_zebra_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_fast_external_failover_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &no_key_chain_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_adv_router_dump_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_prefix_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_filter_list_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_routes_cmd_vtysh);
+ install_element (BGP_NODE, &aggregate_address_mask_as_set_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_prefix_list_description_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_route_pref_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_weight_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_type_metric_routemap_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_routemap_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_address_label_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_community2_exact_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_out_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_route_ospf6_external_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ospf_authentication_key_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_as_cmd_vtysh);
+ install_element (INTERFACE_NODE, &interface_ip_ospf_authentication_cmd_vtysh);
+ install_element (ZEBRA_NODE, &no_ripng_redistribute_ripng_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_exact_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_unsuppress_map_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_ospf_neighbor_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_summary_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged3_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_rip_packet_direct_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_ospf_priority_addr_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_update_source_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_attr_unchanged9_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_zebra_packet_direct_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_nexthop_self_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_set_peer_group_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_confederation_identifier_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_route_protocol_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_route_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_view_route_cmd_vtysh);
+ install_element (CONFIG_NODE, &access_list_extended_host_any_cmd_vtysh);
+ install_element (RIP_NODE, &rip_default_information_originate_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_distance_source_access_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_community_list_exact_cmd_vtysh);
+ install_element (OSPF6_NODE, &ospf6_redistribute_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh);
+ install_element (RMAP_NODE, &match_ipv6_address_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_irdp_holdtime_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_community3_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_neighbor_routes_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_route_map_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_debugging_bgp_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_ipv6_next_hop_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_ospf_nsm_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_first_match_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_community_list_standard_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_out_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_community2_exact_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_send_community_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_network_mask_natural_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_prefix_filter_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_exact_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_summary_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_ospf_zebra_sub_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &bgp_network_route_map_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_peer_soft_in_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_community_list_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_ip_nexthop_cmd_vtysh);
+ install_element (OSPF_NODE, &network_area_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_version_val_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_regexp_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ipv6_nd_send_ra_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_damp_set2_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_node_cmd_vtysh);
+ install_element (VIEW_NODE, &ipv6_bgp_neighbor_received_routes_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_route_prefix_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd_vtysh);
+ install_element (BGP_NODE, &aggregate_address_mask_as_set_summary_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_summary_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_prefix_list_le_cmd_vtysh);
+ install_element (OSPF_NODE, &area_vlink_param3_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_rip_zebra_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_enforce_first_as_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_export_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_community_list_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_router_id_val_cmd_vtysh);
+ install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_routes_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &aggregate_address_mask_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_bgp_filter_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_route_mask_pref_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_route_prefix_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh);
+ install_element (RMAP_NODE, &ospf6_routemap_set_metric_type_cmd_vtysh);
+ install_element (ENABLE_NODE, &undebug_bgp_update_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_only_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ripng_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_capability_route_refresh_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_route_reflector_client_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_route_addr_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_network_import_check_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &send_lifetime_infinite_month_day_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_external_soft_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_prefix_filter_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_nexthop_self_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_community_all_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_redistribute_source_type_metric_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_ebgp_multihop_ttl_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_redistribute_source_routemap_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_prefix_list_seq_le_cmd_vtysh);
+ install_element (RIP_NODE, &rip_network_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_community2_exact_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_attr_unchanged3_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_cmd_vtysh);
+ install_element (OSPF_NODE, &no_ospf_router_id_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_default_metric_val_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_route_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &bgp_network_mask_route_map_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_router_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_redistribute_source_metric_type_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_community2_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &aggregate_address_as_set_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged_cmd_vtysh);
+ install_element (OSPF6_NODE, &interface_area_plist_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_route_prefix_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_community_list_arg_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_routes_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ipv6_prefix_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_as_out_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_filter_list_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_default_originate_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ospf_hello_interval_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_maximum_prefix_val2_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd_vtysh);
+ install_element (RIP_NODE, &rip_timers_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_distance_ospf_intra_external_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_bgp_update_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_out_cmd_vtysh);
+ install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_ospf_database_type_adv_router_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_community3_exact_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_prefix_list_name_seq_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged7_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_activate_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_standard_host_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_force_prefix_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_ospf_cost_addr_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_community3_exact_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh);
+ install_element (INTERFACE_NODE, &multicast_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_prefix_longer_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_deterministic_med_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_ospf_neighbor_all_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_rmap_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ospf_message_digest_key_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_redistribute_source_type_metric_routemap_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_aggregate_address_cmd_vtysh);
+ install_element (RMAP_NODE, &set_community_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged5_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_ospf_nsm_sub_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_ospf_interface_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_community4_exact_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_default_local_preference_val_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_activate_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ospf_priority_cmd_vtysh);
+ install_element (CONFIG_NODE, &dump_bgp_routes_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_community3_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_metric_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_distribute_list_out_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_cluster_id_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_ospf_packet_all_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_summary_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_ospf_ism_sub_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_bgp_metric_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_rip_packet_direct_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh);
+ install_element (OSPF_NODE, &no_auto_cost_reference_bandwidth_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_timers_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_neighbors_peer_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_ospf_neighbor_int_detail_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_bgp_keepalive_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_cmd_vtysh);
+ install_element (RIP_NODE, &rip_offset_list_ifname_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_bgp_metric_routemap_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh);
+ install_element (RMAP_NODE, &rmap_onmatch_next_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_metric_routemap_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged7_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_access_list_name_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_capability_orf_prefix_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_filter_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_in_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged10_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_route_addr_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_distance_source_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_metric_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_access_list_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_access_list_any_cmd_vtysh);
+ install_element (BGP_NODE, &no_aggregate_address_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_neighbor_received_routes_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_extcommunity_list_standard_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_community_exact_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_allowas_in_arg_cmd_vtysh);
+ install_element (BGP_NODE, &no_aggregate_address_as_set_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_zebra_interface_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_as_set_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_ospf_database_type_self_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_external_in_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_send_community_type_cmd_vtysh);
+ install_element (VIEW_NODE, &ipv6_mbgp_neighbor_routes_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_vlink_authtype_md5_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_filter_list_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_route_protocol_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_origin_val_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_ospf_database_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_unsuppress_map_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_ospf_event_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_out_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_community2_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_peer_group_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_static_metric_routemap_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_out_cmd_vtysh);
+ install_element (INTERFACE_NODE, &bandwidth_if_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_distance_ospf_intra_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_as_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_community2_exact_cmd_vtysh);
+ install_element (OSPF_NODE, &area_vlink_authtype_authkey_cmd_vtysh);
+ install_element (OSPF_NODE, &area_range_advertise_cost_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh);
+ install_element (OSPF_NODE, &no_neighbor_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_rip_packet_detail_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_aspath_prepend_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_prefix_list_seq_ge_le_cmd_vtysh);
+ install_element (BGP_NODE, &no_aggregate_address_summary_only_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_prefix_list_summary_name_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd_vtysh);
+ install_element (OSPF_NODE, &area_stub_cmd_vtysh);
+ install_element (OSPF_NODE, &area_authentication_message_digest_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_name_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_cost_cmd_vtysh);
+ install_element (ENABLE_NODE, &undebug_bgp_filter_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_ospf_ism_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_passive_interface_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_set_peer_group_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_prefix_filter_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_remove_private_as_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ospf_cost_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &send_lifetime_day_month_month_day_cmd_vtysh);
+ install_element (RMAP_NODE, &set_ip_nexthop_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_ospf_event_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_activate_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_metric_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_bgp_fsm_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_override_capability_cmd_vtysh);
+ install_element (VIEW_NODE, &show_table_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_always_metric_routemap_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_set_peer_group_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_ospf_cost_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_all_soft_out_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &bgp_damp_set_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_metric_val_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_community2_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_community3_exact_cmd_vtysh);
+ install_element (CONFIG_NODE, &dump_bgp_all_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_ripng_packet_detail_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ospf_transmit_delay_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_ospf_database_type_cmd_vtysh);
+ install_element (BGP_NODE, &aggregate_address_as_set_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_distance2_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_vlink_param2_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_filter_list_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_community_exact_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_in_cmd_vtysh);
+ install_element (OSPF_NODE, &auto_cost_reference_bandwidth_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_route_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_priority_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_prefix_list_description_arg_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_address_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_neighbor_routes_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_bgp_filter_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_prefix_list_le_ge_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_route_map_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_debugging_ripng_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &aggregate_address_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_community4_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_community_list_exact_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_filter_list_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_ospf_message_digest_key_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_prefix_list_sequence_number_cmd_vtysh);
+ install_element (VIEW_NODE, &ipv6_mbgp_neighbor_received_routes_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_prefix_list_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_scan_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_cmd_vtysh);
+ install_element (OSPF_NODE, &no_refresh_timer_val_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_instance_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_local_pref_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_distance_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_extended_any_host_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_month_day_month_day_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_weight_val_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_always_metric_type_routemap_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_debugging_zebra_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_network_backdoor_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &send_lifetime_month_day_day_month_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_distribute_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_out_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_redistribute_source_cmd_vtysh);
+ install_element (OSPF_NODE, &area_range_cost_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_routerid_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_exact_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_remove_private_as_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_ospf_zebra_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_ospf_authentication_key_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_ospf_ism_cmd_vtysh);
+ install_element (RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_bgp_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_route_server_client_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ospf_priority_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_ospf_lsa_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_rip_packet_direct_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_extended_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_rip_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_regexp_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_remove_private_as_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_standard_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_static_metric_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd_vtysh);
+ install_element (ZEBRA_NODE, &rip_redistribute_rip_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_send_community_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_cmd_vtysh);
+ install_element (OSPF_NODE, &area_vlink_authkey_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_cmd_vtysh);
+ install_element (CONFIG_NODE, &access_list_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_router_bgp_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_timers_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_as_in_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ospf_dead_interval_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_self_cmd_vtysh);
+ install_element (OSPF_NODE, &area_shortcut_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_rip_authentication_key_chain_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_prefix_list_sequence_number_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_bgp_config_type_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_network_mask_route_map_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_neighborlist_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_route_map_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_summary_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_instance_summary_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_peer_out_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_regexp_cmd_vtysh);
+ install_element (RMAP_NODE, &match_origin_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_filter_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cidr_only_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_as_out_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged6_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_table_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_nexthop_self_cmd_vtysh);
+ install_element (RIP_NODE, &rip_default_metric_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_vlink_param3_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_regexp_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_regexp_cmd_vtysh);
+ install_element (OSPF_NODE, &area_vlink_md5_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_ospf_priority_addr_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_regexp_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_set_peer_group_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_community_list_exact_cmd_vtysh);
+ install_element (BGP_NODE, &old_ipv6_bgp_network_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_default_originate_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_prefix_list_seq_ge_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_summary_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_local_pref_val_cmd_vtysh);
+ install_element (OSPF_NODE, &no_neighbor_pollinterval_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_area_route_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_filter_list_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_bgp_keepalive_cmd_vtysh);
+ install_element (RIP_NODE, &rip_distance_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_weight_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_rip_events_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_ospf_lsa_cmd_vtysh);
+ install_element (BGP_NODE, &old_no_ipv6_aggregate_address_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_access_list_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_connected_metric_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_community2_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_bestpath_aspath_ignore_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_vlink_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_as_in_prefix_filter_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_ospf_authentication_key_addr_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_network_cmd_vtysh);
+ install_element (OSPF_NODE, &no_router_id_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_local_as_no_prepend_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_neighbor_advertised_route_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_set_peer_group_cmd_vtysh);
+ install_element (BGP_NODE, &no_synchronization_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_update_source_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_address_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_community_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_extcommunity_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_all_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_bgp_network_route_map_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_prefix_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_rip_cmd_vtysh);
+ install_element (CONFIG_NODE, &access_list_standard_host_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_prefix_list_sequence_number_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_longer_cmd_vtysh);
+ install_element (BGP_NODE, &no_aggregate_address_as_set_summary_cmd_vtysh);
+ install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_range_advertise_cost_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_community_exact_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_prefix_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_prefix_list_le_ge_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_addr_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_community_exact_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_access_list_remark_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ospf_dead_interval_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_irdp_preference_cmd_vtysh);
+ install_element (BGP_NODE, &aggregate_address_as_set_summary_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_regexp_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_route_prefix_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_ospf6_metric_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_detail_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_passive_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_community4_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged5_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_area_route_prefix_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_originator_id_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_static_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_capability_route_refresh_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_ospf6_metric_routemap_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_send_community_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_forwarding_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_prefix_longer_cmd_vtysh);
+ install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_routemap_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_connected_metric_val_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_rip_receive_version_1_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_scan_time_val_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_ripng_packet_direct_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_metric_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_distance_ospf_external_inter_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_prefix_list_le_ge_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_community_exact_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_route_ospf6_external_prefix_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &vpnv4_network_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_rfc1583_flag_cmd_vtysh);
+ install_element (OSPF_NODE, &area_vlink_param2_cmd_vtysh);
+ install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_received_routes_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_extcommunity_list_standard2_cmd_vtysh);
+ install_element (BGP_NODE, &aggregate_address_summary_only_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_prefix_list_summary_name_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd_vtysh);
+ install_element (RMAP_NODE, &set_originator_id_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_ripng_packet_direct_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_prefix_list_name_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_out_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_cluster_id32_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_redistribute_type_routemap_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_client_to_client_reflection_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_ip_address_val_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_prefix_list_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_distance_ospf_inter_intra_external_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_filter_list_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_access_list_any_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_range_cost_cmd_vtysh);
+ install_element (OSPF_NODE, &area_vlink_param4_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged10_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_forwarding_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_community_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_send_community_type_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_community_cmd_vtysh);
+ install_element (RMAP_NODE, &set_ecommunity_rt_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_cidr_only_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_all_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_rip_authentication_string_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_cmd_vtysh);
+ install_element (OSPF_NODE, &timers_spf_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_prefix_list_seq_le_ge_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_port_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_community_val_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_out_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_zebra_events_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_ospf6_all_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_attr_unchanged7_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_bgp_network_mask_route_map_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_in_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_prefix_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_zebra_kernel_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_ospf_neighbor_all_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_irdp_multicast_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_metric_cmd_vtysh);
+ install_element (CONFIG_NODE, &dump_bgp_updates_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_ospf6_routemap_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_always_compare_med_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_address_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_kernel_cmd_vtysh);
+ install_element (VIEW_NODE, &show_debug_ospf6_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_ripng_events_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_vlink_authtype_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_route_reflector_client_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_remote_as_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_community_exact_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_set_peer_group_cmd_vtysh);
+ install_element (ENABLE_NODE, &reload_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_route_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_extended_host_host_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_route_ospf6_external_prefix_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_dont_capability_negotiate_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_rip_receive_version_2_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_area_topology_router_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_prefix_list_seq_ge_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_advertisement_cmd_vtysh);
+ install_element (RMAP_NODE, &set_metric_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_always_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_bestpath_compare_router_id_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_route_map_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_ripng_packet_direct_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_ospf_authentication_key_addr_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_route_reflector_client_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_distance_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &aggregate_address_summary_as_set_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_route_mask_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_filter_list_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_irdp_minadvertinterval_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_addr_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_routerid_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_community2_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_route_reflector_client_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_default_originate_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_distance_source_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_prefix_filter_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_filter_list_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_route_map_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard2_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_prefix_list_ge_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_kernel_routemap_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged8_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_prefix_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_out_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_protocols_rip_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_neighbor_received_prefix_filter_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_out_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_prefix_list_description_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_standard_any_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_instance_ipv6_summary_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_ospf_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_ospf_cost_addr_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_bgp_fsm_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_out_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_default_originate_rmap_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_community4_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_prefix_list_detail_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_rip_zebra_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_longer_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_ecommunity_soo_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_always_type_metric_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_prefix_list_seq_cmd_vtysh);
+ install_element (BGP_NODE, &old_ipv6_aggregate_address_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_route_pref_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_prefix_list_sequence_number_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_prefix_longer_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_advertise_interval_val_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_extended_any_mask_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_community_all_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_ospf_neighbor_id_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_day_month_day_month_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_in_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_rip_authentication_mode_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_le_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_zebra_packet_detail_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_as_path_all_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_community2_exact_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_always_metric_type_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_interface_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_out_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_regexp_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_adv_router_dump_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_redistribute_source_metric_routemap_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_all_in_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_access_list_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_route_server_client_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_filter_list_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_in_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_scan_time_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_community_all_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_route_reflector_client_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_send_community_type_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_community3_exact_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_route_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_ge_le_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_ospf_priority_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_vlink_authkey_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_community_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_distance_source_access_list_cmd_vtysh);
+ install_element (OSPF_NODE, &area_vlink_param1_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_debugging_rip_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_route_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_tree_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_static_routemap_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_extended_mask_host_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_default_metric_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_bandwidth_if_cmd_vtysh);
+ install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_bgp_fsm_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_prefix_list_seq_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_interface_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_default_metric_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_ospf_lsa_sub_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_all_in_prefix_filter_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_exact_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_list_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_in_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_network_mask_natural_backdoor_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain2_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_timers_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_out_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_ospf_database_type_id_adv_router_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_extended_host_any_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_distance_ospf_inter_external_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_community_list_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_connected_metric_routemap_cmd_vtysh);
+ install_element (RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd_vtysh);
+ install_element (RMAP_NODE, &set_ipv6_nexthop_global_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_prefix_list_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_bestpath_compare_router_id_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged6_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_maximum_prefix_cmd_vtysh);
+ install_element (INTERFACE_NODE, &shutdown_if_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_connected_metric_routemap_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_address_secondary_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_neighbors_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_ospf_zebra_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_out_cmd_vtysh);
+ install_element (RIP_NODE, &rip_distance_source_cmd_vtysh);
+ install_element (OSPF_NODE, &router_id_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_bgp_all_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_community_delete_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_route_map_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_list_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_route_reflector_client_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh);
+ install_element (INTERFACE_NODE, &interface_ip_ospf_authentication_addr_cmd_vtysh);
+ install_element (BGP_NODE, &no_aggregate_address_mask_as_set_summary_cmd_vtysh);
+ install_element (RMAP_NODE, &match_ip_address_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_as_set_cmd_vtysh);
+ install_element (CONFIG_NODE, &access_list_standard_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_ospf_database_type_adv_router_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_set_peer_group_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_community_list_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_rip_send_version_1_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_peer_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_distance_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_out_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &no_key_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_access_list_remark_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_topology_router_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_prefix_list_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_ospf_nsm_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_community_list_name_expanded_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_view_prefix_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_exact_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_route_map_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_prefix_list_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &aggregate_address_summary_as_set_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_metric_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_key_chain_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_cmd_vtysh);
+ install_element (ENABLE_NODE, &undebug_bgp_all_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_community_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_aggregator_as_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_in_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_as_soft_in_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_only_cmd_vtysh);
+ install_element (OSPF_NODE, &no_refresh_timer_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_prefix_list_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_network_mask_natural_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_neighbor_received_prefix_filter_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_route_ospf6_external_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_unsuppress_map_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_forwarding_cmd_vtysh);
+ install_element (RIP_NODE, &rip_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_rip_packet_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh);
+ install_element (OSPF_NODE, &neighbor_priority_pollinterval_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_port_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged5_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_prefix_list_detail_name_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_static_routemap_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_paths_cmd_vtysh);
+ install_element (BGP_NODE, &no_aggregate_address_mask_summary_only_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_ripng_zebra_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_map_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_exact_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_damp_unset_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_external_soft_out_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_static_metric_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_bgp_network_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_prefix_cmd_vtysh);
+ install_element (BGP_NODE, &no_auto_summary_cmd_vtysh);
+ install_element (ENABLE_NODE, &ipv6_bgp_neighbor_routes_cmd_vtysh);
+ install_element (RMAP_NODE, &match_ipv6_address_prefix_list_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_send_community_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_filter_list_cmd_vtysh);
+ install_element (OSPF_NODE, &area_range_advertise_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_always_metric_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_in_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_addr_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_out_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_out_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_community_list_expanded_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_prefix_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_rip_events_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_prefix_list_summary_cmd_vtysh);
+ install_element (INTERFACE_NODE, &interface_ip_ospf_authentication_args_addr_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_metric_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_prefix_list_summary_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_longer_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_nd_send_ra_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_rip_send_version_2_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_exact_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_community_info_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_always_type_metric_routemap_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_regexp_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_ospf_nsm_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_confederation_identifier_arg_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_community2_exact_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_version_ospf6_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged10_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_route_map_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_all_in_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_community_list_exact_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_rip_packet_direct_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_prefix_list_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_metric_routemap_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_route_map_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_prefix_longer_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_passive_interface_cmd_vtysh);
+ install_element (CONFIG_NODE, &access_list_extended_mask_any_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_tags_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged5_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_as_in_prefix_filter_cmd_vtysh);
+ install_element (OSPF_NODE, &no_ospf_distribute_list_out_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_interface_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &ipv6_bgp_neighbor_advertised_route_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_default_originate_cmd_vtysh);
+ install_element (OSPF_NODE, &area_vlink_authtype_args_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_summary_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_instance_summary_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_prefix_list_prefix_cmd_vtysh);
+ install_element (OSPF_NODE, &area_vlink_authtype_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_in_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_in_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_community_list_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_community4_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_addr_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_prefix_list_description_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_rip_receive_version_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_ebgp_multihop_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd_vtysh);
+ install_element (OSPF_NODE, &area_filter_list_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_timers_connect_val_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_adv_router_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_unsuppress_map_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd_vtysh);
+ install_element (VIEW_NODE, &show_interface_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_distance_ospf_external_intra_inter_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_description_cmd_vtysh);
+ install_element (CONFIG_NODE, &access_list_remark_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_hellointerval_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh);
+ install_element (CONFIG_NODE, &dump_bgp_all_interval_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_route_map_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_range_subst_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged10_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_ospf_network_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_zebra_events_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_origin_val_cmd_vtysh);
+ install_element (OSPF_NODE, &area_default_cost_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &key_string_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_community4_exact_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_capability_orf_prefix_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_route_server_client_cmd_vtysh);
+ install_element (BGP_NODE, &old_ipv6_aggregate_address_summary_only_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_node_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_enforce_multihop_cmd_vtysh);
+ install_element (RMAP_NODE, &set_weight_cmd_vtysh);
+ install_element (VIEW_NODE, &show_debugging_ripng_cmd_vtysh);
+ install_element (OSPF_NODE, &area_import_list_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_default_information_originate_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_stub_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_send_community_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_bgp_routemap_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_nexthop_self_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_network_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_ripng_events_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_network_mask_natural_route_map_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_prefix_list_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_default_local_preference_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_cmd_vtysh);
+ install_element (RMAP_NODE, &match_ip_next_hop_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_peer_soft_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_community_list_cmd_vtysh);
+ install_element (VIEW_NODE, &show_debugging_zebra_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_community4_exact_cmd_vtysh);
+ install_element (BGP_NODE, &aggregate_address_mask_summary_only_cmd_vtysh);
+ install_element (OSPF_NODE, &area_vlink_authtype_args_md5_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_default_originate_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_community3_exact_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_cidr_only_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_access_list_name_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_route_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged8_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_ripng_packet_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_range_not_advertise_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_routemap_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_area_topology_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_community3_exact_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_prefix_list_prefix_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_default_ipv4_unicast_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_summary_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_summary_cmd_vtysh);
+ install_element (CONFIG_NODE, &bgp_multiple_instance_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_summary_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_route_map_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_router_rip_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_metric_val_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_originator_id_val_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_bestpath_med_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_distance_ospf_intra_external_inter_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_neighbor_received_routes_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &aggregate_address_summary_only_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_prefix_list_seq_le_ge_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_vlink_md5_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_arg_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_prefix_list_le_cmd_vtysh);
+ install_element (CONFIG_NODE, &dump_bgp_updates_interval_cmd_vtysh);
+ install_element (OSPF_NODE, &passive_interface_addr_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_as_set_cmd_vtysh);
+ install_element (OSPF_NODE, &no_ospf_default_metric_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_external_in_prefix_filter_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &bgp_network_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_community_list_arg_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_as_path_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_prefix_list_ge_le_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_prefix_list_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_bestpath_med_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_view_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_community_all_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_allowas_in_arg_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_arg_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_community_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_summary_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_offset_list_ifname_cmd_vtysh);
+ install_element (BGP_NODE, &aggregate_address_mask_summary_as_set_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_ospf_nsm_sub_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_community3_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_extended_host_mask_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_vlink_authtype_authkey_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_route_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_allowas_in_cmd_vtysh);
+ install_element (ENABLE_NODE, &undebug_bgp_normal_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_abr_type_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_filter_list_cmd_vtysh);
+ install_element (RIP_NODE, &rip_redistribute_type_metric_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ospf_network_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_prefix_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_ospf_ism_sub_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_route_map_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_transparent_as_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_network_route_map_cmd_vtysh);
+ install_element (CONFIG_NODE, &access_list_any_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_bgp_update_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_rip_send_version_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_attr_unchanged_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_dont_capability_negotiate_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_community_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_default_originate_rmap_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_route_map_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_unsuppress_map_cmd_vtysh);
+ install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &no_key_string_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_ip_address_val_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_metric_val_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_community2_exact_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ospf_authentication_key_cmd_vtysh);
+ install_element (RMAP_NODE, &set_aggregator_as_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_remove_private_as_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_out_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_prefix_list_le_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_ospf_priority_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_out_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &send_lifetime_infinite_day_month_cmd_vtysh);
+ install_element (RIP_NODE, &rip_version_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_remote_as_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_debugging_ospf_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged6_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_exact_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged9_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_unsuppress_map_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_route_addr_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_capability_orf_prefix_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_nexthop_self_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_in_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_prefix_list_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_prefix_list_name_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_route_map_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_distribute_list_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_access_list_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_strict_capability_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ripng_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &send_lifetime_duration_month_day_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_peer_cmd_vtysh);
+ install_element (VIEW_NODE, &ipv6_bgp_neighbor_routes_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_default_metric_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_detail_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_protocols_rip_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_community3_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_peer_group_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_infinite_month_day_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_as_soft_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_rip_split_horizon_cmd_vtysh);
+ install_element (OSPF_NODE, &area_vlink_authtype_md5_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_default_originate_rmap_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_in_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_filter_list_cmd_vtysh);
+ install_element (OSPF_NODE, &passive_interface_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_route_reflector_client_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_summary_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_longer_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_advertise_interval_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_dump_bgp_all_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_in_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_prefix_list_prefix_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_community_list_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_prefix_list_summary_name_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_community_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged6_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_only_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_ospf_cost_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_route_protocol_cmd_vtysh);
+ install_element (OSPF_NODE, &area_export_list_cmd_vtysh);
+ install_element (OSPF6_NODE, &router_id_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_access_list_exact_cmd_vtysh);
+ install_element (OSPF_NODE, &no_ospf_abr_type_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_aspath_val_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_route_map_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_peer_group_remote_as_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_rmap_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_shortcut_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_route_map_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_ospf_hello_interval_addr_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_redistribute_type_metric_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_all_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_zebra_kernel_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_ospf_nsm_sub_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_distance_source_cmd_vtysh);
+ install_element (CONFIG_NODE, &access_list_extended_host_host_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_ospf6_all_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_neighbors_peer_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_interface_ip_ospf_authentication_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_paths_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_summary_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_ripng_packet_detail_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_ospf_database_type_self_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_summary_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_ospf_ism_sub_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_out_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_community_list_name_standard2_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_route_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_bestpath_med2_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_default_originate_rmap_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_summary_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_cmd_vtysh);
+ install_element (ZEBRA_NODE, &redistribute_ospf6_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_ospf_neighbor_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_forwarding_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_deterministic_med_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_neighbor_routes_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_prefix_list_ge_le_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_zebra_packet_direct_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_network_mask_route_map_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_rip_packet_detail_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_cluster_id_arg_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_description_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_ospf_zebra_cmd_vtysh);
+ install_element (RMAP_NODE, &match_community_exact_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_fast_external_failover_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_prefix_list_description_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_network_mask_natural_route_map_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ospf_retransmit_interval_cmd_vtysh);
+ install_element (BGP_NODE, &no_aggregate_address_mask_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_community_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_exact_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_longer_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_cmd_vtysh);
+ install_element (OSPF_NODE, &no_ospf_distance_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_nd_prefix_advertisement_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_database_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_out_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_community2_exact_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_val2_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_route_supernets_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_route_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_router_id_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_community_delete_val_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_rmap_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_vlink_param1_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_connected_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_summary_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_send_community_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_all_out_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_distance_ospf_intra_inter_external_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_cmd_vtysh);
+ install_element (OSPF_NODE, &refresh_timer_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_capability_orf_prefix_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_list_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &send_lifetime_month_day_month_day_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_ospf_zebra_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_exact_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_bgp_filter_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_ospf_message_digest_key_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_rip_zebra_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_rip_packet_cmd_vtysh);
+ install_element (VIEW_NODE, &show_version_ospf6_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_unsuppress_map_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_route_supernets_cmd_vtysh);
+ install_element (RIP_NODE, &rip_redistribute_type_routemap_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd_vtysh);
+ install_element (RMAP_NODE, &rmap_onmatch_goto_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_type_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_summary_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_view_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_adv_router_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_connected_routemap_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_ospf_ism_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_bgp_events_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_route_map_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_range_advertise_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_ripng_zebra_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_attr_unchanged5_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_allowas_in_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_community3_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_prefix_list_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_community4_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_type_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &aggregate_address_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_send_community_type_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_duration_month_day_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_route_server_client_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_prefix_list_seq_ge_le_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_route_prefix_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_val_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_range_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_local_as_val_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_route_map_all_cmd_vtysh);
+ install_element (OSPF_NODE, &no_passive_interface_addr_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_as_soft_out_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_send_community_type_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_neighbors_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_peer_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_external_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_activate_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_enforce_first_as_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_rip_events_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_kernel_metric_routemap_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_passive_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_community4_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_static_metric_val_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_send_community_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_remove_private_as_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_network_backdoor_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_enforce_multihop_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_prefix_list_name_prefix_cmd_vtysh);
+ install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_send_community_type_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &bgp_network_mask_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ospf_message_digest_key_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_exact_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_soft_reconfiguration_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_attr_unchanged10_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_network_mask_backdoor_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_irdp_cmd_vtysh);
+ install_element (CONFIG_NODE, &config_table_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged8_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_area_topology_router_lsid_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_filter_list_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_prefix_list_ge_le_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_in_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_zebra_packet_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_only_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_always_type_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_metric_val_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_route_map_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_prefix_list_cmd_vtysh);
+ install_element (OSPF6_NODE, &area_range_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_rip_events_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_prefix_list_seq_le_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_community_cmd_vtysh);
+ install_element (RMAP_NODE, &match_interface_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_community_exact_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_version_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_prefix_filter_cmd_vtysh);
+ install_element (CONFIG_NODE, &access_list_standard_any_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_ospf_lsa_sub_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_distance_ospf_intra_inter_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_bgp_keepalive_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_peer_cmd_vtysh);
+ install_element (CONFIG_NODE, &access_list_extended_any_any_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_ripng_packet_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh);
+ install_element (RIP_NODE, &rip_offset_list_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_network_import_check_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_in_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_prefix_list_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_default_cost_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_prefix_list_ge_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_paths_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_offset_list_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_access_list_remark_arg_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_ospf_lsa_cmd_vtysh);
+ install_element (OSPF_NODE, &no_ospf_default_metric_val_cmd_vtysh);
+ install_element (OSPF_NODE, &area_range_not_advertise_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_type_metric_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_zebra_client_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged8_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_prefix_list_le_ge_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_only_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_in_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_vpnv4_nexthop_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_out_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_self_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_peer_group_out_cmd_vtysh);
+ install_element (OSPF_NODE, &area_range_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_exact_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_metric_type_cmd_vtysh);
+ install_element (RIP_NODE, &rip_distance_source_access_list_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_router_bgp_view_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_all_soft_in_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_shutdown_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_distance_ospf_inter_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_community_list_name_standard_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_redistribute_type_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd_vtysh);
+ install_element (OSPF_NODE, &no_neighbor_priority_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_route_mask_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_prefix_filter_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_community4_exact_cmd_vtysh);
+ install_element (BGP_NODE, &aggregate_address_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_rip_receive_version_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_compatible_rfc1583_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_out_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_passive_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_soft_reconfiguration_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_metric_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_extended_any_any_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_shutdown_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_regexp_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_as_set_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_route_prefix_longer_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_community4_exact_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_distribute_list_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_route_map_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_origin_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_community_all_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_dump_bgp_updates_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_network_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_weight_val_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_multicast_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_community3_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_community_list_standard_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_prefix_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_area_route_prefix_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_ospf_lsa_sub_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_bandwidth_if_val_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_prefix_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_ospf_database_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_distribute_list_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged9_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_cmd_vtysh);
+ install_element (OSPF_NODE, &area_vlink_authtype_args_authkey_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_filter_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_community4_exact_cmd_vtysh);
+ install_element (OSPF_NODE, &neighbor_priority_cmd_vtysh);
+ install_element (BGP_NODE, &old_no_ipv6_bgp_network_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_prefix_filter_cmd_vtysh);
+ install_element (CONFIG_NODE, &access_list_exact_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_summary_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_filter_list_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_weight_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_route_reflector_client_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_timers_connect_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_address_secondary_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_distribute_list_cmd_vtysh);
+ install_element (BGP_NODE, &no_aggregate_address_summary_as_set_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_community_none_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_version_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_exact_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_ospf_dead_interval_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_interface_ip_ospf_authentication_addr_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_ospf_route_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_local_as_val2_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_aspath_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_bgp_normal_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_bestpath_med2_cmd_vtysh);
+ install_element (OSPF_NODE, &no_ospf_redistribute_source_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_shutdown_if_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_address_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_ospf_zebra_sub_cmd_vtysh);
+ install_element (RMAP_NODE, &set_metric_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_filter_list_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &bgp_damp_set3_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_bgp_update_direct_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_always_routemap_cmd_vtysh);
+ install_element (BGP_NODE, &aggregate_address_summary_as_set_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_external_in_prefix_filter_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_access_list_exact_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_list_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_route_map_cmd_vtysh);
+ install_element (RMAP_NODE, &set_atomic_aggregate_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_peer_group_in_prefix_filter_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_scan_time_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_interface_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_bgp_update_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_route_prefix_longer_cmd_vtysh);
+ install_element (CONFIG_NODE, &ipv6_route_ifname_pref_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_allowas_in_arg_cmd_vtysh);
+ install_element (RIP_NODE, &rip_passive_interface_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_filter_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_neighbor_advertised_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_seq_cmd_vtysh);
+ install_element (RMAP_NODE, &set_aspath_prepend_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_ospf_database_type_id_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_topology_router_lsid_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_community_list_all_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_routes_cmd_vtysh);
+ install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_route_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_activate_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_timers_arg_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_peer_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_advertise_interval_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_activate_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_in_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_connected_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_type_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &aggregate_address_mask_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_community4_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_address_label_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_routemap_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_community_list_name_standard_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_prefix_list_ge_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_filter_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_zebra_events_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_attr_unchanged6_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_route_addr_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged1_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_prefix_list_detail_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_only_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_ospf_interface_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_community_list_standard2_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged1_cmd_vtysh);
+ install_element (OSPF6_NODE, &no_interface_area_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_prefix_list_cmd_vtysh);
+ install_element (OSPF_NODE, &no_ospf_rfc1583_flag_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_route_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_community3_exact_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_route_server_client_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_allowas_in_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_network_mask_backdoor_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_community4_exact_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged1_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_prefix_list_seq_le_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_prefix_list_le_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_ospf6_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_capability_dynamic_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_regexp_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_connected_routemap_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ospf_transmit_delay_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_redistribute_type_metric_routemap_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_ripng_events_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd_vtysh);
+ install_element (ZEBRA_NODE, &ripng_redistribute_ripng_cmd_vtysh);
+ install_element (CONFIG_NODE, &access_list_extended_mask_host_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_summary_only_cmd_vtysh);
+ install_element (ZEBRA_NODE, &no_rip_redistribute_rip_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_default_information_originate_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_out_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_ospf_packet_all_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_community4_exact_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_allowas_in_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_summary_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ospf_hello_interval_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_community_all_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_timers_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_override_capability_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_val2_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_redistribute_kernel_metric_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_network_mask_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_route_server_client_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_bgp_network_route_map_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_neighbor_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_route_protocol_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_day_month_month_day_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_external_in_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &aggregate_address_summary_only_cmd_vtysh);
+ install_element (OSPF_NODE, &area_vlink_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_distance_ospf_external_intra_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_prefix_list_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &send_lifetime_day_month_day_month_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_ospf_event_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &send_lifetime_duration_day_month_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_ospf_hello_interval_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_prefix_list_description_arg_cmd_vtysh);
+ install_element (ENABLE_NODE, &ipv6_bgp_neighbor_received_routes_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ipv6_ospf6_passive_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_prefix_list_ge_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_type_routemap_cmd_vtysh);
+ install_element (OSPF_NODE, &no_ospf_default_information_originate_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_prefix_list_prefix_first_match_cmd_vtysh);
+ install_element (RMAP_NODE, &match_ip_next_hop_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_community_exact_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged2_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_out_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged2_cmd_vtysh);
+ install_element (ENABLE_NODE, &undebug_bgp_keepalive_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_ospf_zebra_sub_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_ipv6_address_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged2_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_route_prefix_longer_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_routemap_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_router_id_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_ospf_packet_all_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_confederation_identifier_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_soft_reconfiguration_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_ripng_packet_direct_cmd_vtysh);
+ install_element (INTERFACE_NODE, &interface_ip_ospf_authentication_args_cmd_vtysh);
+ install_element (OSPF6_NODE, &passive_interface_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_route_server_client_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_any_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_send_community_type_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh);
+ install_element (RIPNG_NODE, &ripng_aggregate_address_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_port_val_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_vpnv4_network_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_ip_address_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_prefix_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_redistribute_ipv4_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_ecommunity_soo_val_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_description_val_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_bestpath_aspath_ignore_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_month_day_day_month_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_community_exact_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_damp_unset2_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_metric_type_routemap_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_extcommunity_list_expanded_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_send_community_type_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ospf_network_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_redistribute_ipv4_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_community2_exact_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_instance_summary_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_extended_mask_any_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_neighbors_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_stub_nosum_cmd_vtysh);
+ install_element (RMAP_NODE, &no_set_aggregator_as_val_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_mbgp_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged7_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_community3_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_distance_ospf_external_inter_intra_cmd_vtysh);
+ install_element (OSPF_NODE, &area_range_subst_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged4_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_prefix_cmd_vtysh);
+ install_element (ENABLE_NODE, &debug_bgp_filter_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged4_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_route_map_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &bgp_damp_set2_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &ipv6_bgp_network_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_detail_cmd_vtysh);
+ install_element (RIP_NODE, &rip_neighbor_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_extcommunity_list_standard_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged4_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_community_list_expanded_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_debug_rip_packet_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_bgp_events_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_activate_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_allowas_in_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_ospf_authentication_key_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_access_list_remark_arg_cmd_vtysh);
+ install_element (OSPF_NODE, &ospf_default_information_originate_metric_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_external_out_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_activate_cmd_vtysh);
+ install_element (VIEW_NODE, &show_zebra_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_community_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd_vtysh);
+ install_element (RIP_NODE, &no_rip_network_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_prefix_list_cmd_vtysh);
+ install_element (OSPF_NODE, &no_ospf_compatible_rfc1583_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_ospf_ism_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_area_topology_router_lsid_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_community4_exact_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_activate_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_bgp_normal_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_bestpath_med3_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_route_map_cmd_vtysh);
+ install_element (OSPF6_NODE, &no_passive_interface_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_community_all_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_zebra_events_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_route_reflector_client_cmd_vtysh);
+ install_element (RMAP_NODE, &set_ecommunity_soo_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_ip_bgp_all_out_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_transmitdelay_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_route_cmd_vtysh);
+ install_element (RIP_NODE, &rip_redistribute_type_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_rip_packet_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_instance_ipv6_summary_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ip_irdp_address_preference_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_exact_cmd_vtysh);
+ install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_force_prefix_cmd_vtysh);
+ install_element (BGP_IPV6_NODE, &no_neighbor_allowas_in_cmd_vtysh);
+ install_element (BGP_NODE, &no_bgp_router_id_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ipv6_forwarding_cmd_vtysh);
+ install_element (OSPF_NODE, &no_area_authentication_cmd_vtysh);
+ install_element (CONFIG_NODE, &ip_community_list_name_expanded_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_strict_capability_cmd_vtysh);
+ install_element (BGP_NODE, &no_neighbor_ebgp_multihop_ttl_cmd_vtysh);
+ install_element (BGP_IPV4M_NODE, &neighbor_set_peer_group_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_router_ospf_cmd_vtysh);
+ install_element (VIEW_NODE, &show_bgp_ipv6_community_all_cmd_vtysh);
+ install_element (ENABLE_NODE, &no_debug_ripng_events_cmd_vtysh);
+ install_element (OSPF_NODE, &no_timers_spf_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &no_aggregate_address_cmd_vtysh);
+ install_element (VIEW_NODE, &show_ipv6_bgp_regexp_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_prefix_list_seq_le_ge_cmd_vtysh);
+ install_element (INTERFACE_NODE, &rip_split_horizon_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_bgp_community3_exact_cmd_vtysh);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_val_cmd_vtysh);
+ install_element (RMAP_NODE, &no_match_interface_val_cmd_vtysh);
+ install_element (BGP_VPNV4_NODE, &neighbor_distribute_list_cmd_vtysh);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_route_cmd_vtysh);
+ install_element (BGP_NODE, &neighbor_attr_unchanged8_cmd_vtysh);
+ install_element (CONFIG_NODE, &debug_ospf_zebra_sub_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_rmap_cmd_vtysh);
+ install_element (BGP_NODE, &bgp_timers_cmd_vtysh);
+ install_element (BGP_NODE, &no_aggregate_address_mask_summary_as_set_cmd_vtysh);
+ install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_out_cmd_vtysh);
+ install_element (BGP_IPV4_NODE, &neighbor_remove_private_as_cmd_vtysh);
+ install_element (OSPF_NODE, &area_stub_nosum_cmd_vtysh);
+ install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_standard_cmd_vtysh);
+ install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_duration_day_month_cmd_vtysh);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_deadinterval_cmd_vtysh);
+}
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
new file mode 100644
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 <zebra.h>
+
+#include "command.h"
+#include "linklist.h"
+#include "memory.h"
+
+#include "vtysh/vtysh.h"
+
+vector configvec;
+
+struct config
+{
+ /* Configuration node name. */
+ char *name;
+
+ /* Configuration string line. */
+ struct list *line;
+
+ /* Configuration can be nest. */
+ struct config *config;
+
+ /* Index of this config. */
+ u_int32_t index;
+};
+
+struct list *config_top;
+
+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 <zebra.h>
+
+#include <sys/un.h>
+#include <setjmp.h>
+#include <sys/wait.h>
+#include <pwd.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "version.h"
+#include "getopt.h"
+#include "command.h"
+
+#include "vtysh/vtysh.h"
+#include "vtysh/vtysh_user.h"
+
+/* 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 <zebra.h>
+
+#include <pwd.h>
+
+#ifdef USE_PAM
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
+#endif /* USE_PAM */
+
+#include "memory.h"
+#include "linklist.h"
+#include "command.h"
+
+#ifdef USE_PAM
+static struct pam_conv conv =
+{
+ misc_conv,
+ NULL
+};
+
+int
+vtysh_pam (char *user)
+{
+ int ret;
+ pam_handle_t *pamh = NULL;
+
+ /* Start PAM. */
+ ret = pam_start("zebra", user, &conv, &pamh);
+ /* printf ("ret %d\n", ret); */
+
+ /* Is user really user? */
+ if (ret == PAM_SUCCESS)
+ ret = pam_authenticate (pamh, 0);
+ /* printf ("ret %d\n", ret); */
+
+#if 0
+ /* Permitted access? */
+ if (ret == PAM_SUCCESS)
+ ret = pam_acct_mgmt (pamh, 0);
+ printf ("ret %d\n", ret);
+
+ if (ret == PAM_AUTHINFO_UNAVAIL)
+ ret = PAM_SUCCESS;
+#endif /* 0 */
+
+ /* This is where we have been authorized or not. */
+#ifdef DEBUG
+ if (ret == PAM_SUCCESS)
+ printf("Authenticated\n");
+ else
+ printf("Not Authenticated\n");
+#endif /* DEBUG */
+
+ /* close Linux-PAM */
+ if (pam_end (pamh, ret) != PAM_SUCCESS)
+ {
+ pamh = NULL;
+ fprintf(stderr, "vtysh_pam: failed to release authenticator\n");
+ exit(1);
+ }
+
+ return ret == PAM_SUCCESS ? 0 : 1;
+}
+#endif /* USE_PAM */
+
+struct user
+{
+ char *name;
+ u_char nopassword;
+};
+
+struct list *userlist;
+
+struct user *
+user_new ()
+{
+ struct user *user;
+ user = XMALLOC (0, sizeof (struct user));
+ memset (user, 0, sizeof (struct user));
+ return user;
+}
+
+void
+user_free (struct user *user)
+{
+ XFREE (0, user);
+}
+
+struct user *
+user_lookup (char *name)
+{
+ struct listnode *nn;
+ struct user *user;
+
+ LIST_LOOP (userlist, user, nn)
+ {
+ if (strcmp (user->name, name) == 0)
+ return user;
+ }
+ return NULL;
+}
+
+void
+user_config_write ()
+{
+ struct listnode *nn;
+ struct user *user;
+
+ LIST_LOOP (userlist, user, nn)
+ {
+ if (user->nopassword)
+ printf (" username %s nopassword\n", user->name);
+ }
+}
+
+struct user *
+user_get (char *name)
+{
+ struct user *user;
+ user = user_lookup (name);
+ if (user)
+ return user;
+
+ user = user_new ();
+ user->name = strdup (name);
+ listnode_add (userlist, user);
+
+ return user;
+}
+
+DEFUN (username_nopassword,
+ username_nopassword_cmd,
+ "username WORD nopassword",
+ "\n"
+ "\n"
+ "\n")
+{
+ struct user *user;
+ user = user_get (argv[0]);
+ user->nopassword = 1;
+ return CMD_SUCCESS;
+}
+
+int
+vtysh_auth ()
+{
+ struct user *user;
+ struct passwd *passwd;
+
+ passwd = getpwuid (geteuid ());
+
+ user = user_lookup (passwd->pw_name);
+ if (user && user->nopassword)
+ /* Pass through */;
+ else
+ {
+#ifdef USE_PAM
+ if (vtysh_pam (passwd->pw_name))
+ exit (0);
+#endif /* USE_PAM */
+ }
+ return 0;
+}
+
+void
+vtysh_user_init ()
+{
+ userlist = list_new ();
+ install_element (CONFIG_NODE, &username_nopassword_cmd);
+}
diff --git a/vtysh/vtysh_user.h b/vtysh/vtysh_user.h
new file mode 100644
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 <mizutani@net-chef.net>
+
+ * zebra_rib.c (static_add_ipv4): Null0 static route is added.
+
+2002-09-10 Jochen Friedrich <chris+zebra@scram.de>
+
+ * rt_netlink.c: Add check for EAGAIN.
+ * kernel_socket.c: Likewise
+
+2002-06-12 Israel Keys <ikeys@oz.agile.tv>
+
+ * rt_netlink.c: Setting the NLM_F_ACK flag on the netlink command
+ message so that we get an ACK for successful netlink commands.
+ Change the netlink socket to BLOCKING while we wait for a
+ response; be it an ACK or an NLMSG_ERROR. Change
+ netlink_parse_info to deal with ACK messages.
+
+2001-11-01 Jun-ichiro itojun Hagino <itojun@iijlab.net>
+
+ * rtadv.c (rtadv_make_socket): setsockopt(IPV6_CHECKSUM) does not
+ work for ICMPv6 socket.
+
+2001-10-24 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * rib.c (rib_process): Select connected route any case.
+
+2001-10-23 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * interface.c (no_ip_address_secondary): Add "no" to command.
+
+2001-10-18 NOGUCHI Kay <kay@v6.access.co.jp>
+
+ * ioctl.c (if_prefix_add_ipv6): Set the prefered and valid lifetime
+ to infinity as the freebsd4.4 workaroud.
+
+2001-08-26 mihail.balikov@interbgc.com
+
+ * zebra_snmp.c: Fix snmpwalk problem such as IPv4 address
+ A.B.C.255.
+
+2001-08-22 NOGUCHI Kay <kay@v6.access.co.jp>
+
+ * rtadv.c: Do not send RA to loopback interface.
+
+2001-08-20 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * ioctl.c (if_set_prefix): Remove Linux 2.0 specific connected
+ route treatment.
+
+2001-08-19 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92a released.
+
+2001-08-17 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * rib.c: Kernel route is treated as EGP routes in nexthop active
+ check.
+
+2001-08-15 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92 released.
+
+2001-08-08 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * rib.c (show_ip_route_prefix_longer): Add longer-prefix option to
+ show route commands.
+
+2001-07-29 Yon Uriarte <havanna_moon@gmx.net>
+
+ * zserv.c (zsend_ipv4_add_multipath): Add
+ NEXTHOP_TYPE_IPV4_IFINDEX check.
+
+2001-07-29 NOGUCHI Kay <kay@v6.access.co.jp>
+
+ * rtadv.c: Apply valid lifetime, preferred lifetime, onilnk flag,
+ autonomous address-configuration flag patch.
+ (no_ipv6_nd_suppress_ra): Change "ipv6 nd send-ra" to "no ipv6 nd
+ suppress-ra".
+
+2001-07-24 NOGUCHI Kay <kay@v6.access.co.jp>
+
+ * rtadv.c (ipv6_nd_ra_interval): Add "ipv6 nd ra-interval SECONDS"
+ command.
+
+2001-07-24 Jun-ichiro itojun Hagino <itojun@iijlab.net>
+
+ * rt_socket.c (kernel_rtm_ipv4): Add KAME/NetBSD151 equal cost
+ multicast FIB support both IPv4 and IPv6.
+
+2001-07-24 Hal Snyder <hal@vailsys.com>
+
+ * if_ioctl.c (interface_list_ioctl): Fix bug of failing to get the
+ full list of interfaces on some configurations of OpenBSD.
+
+2001-07-23 NOGUCHI Kay <kay@v6.access.co.jp>
+
+ * rtadv.c (ipv6_nd_send_ra): Apply [zebra 9320] to fix "ipv6 nd
+ send-ra" bug.
+ (ipv6_nd_ra_lifetime): "ipv6 nd ra-lifetime 0" for default router
+ availability.
+ (ipv6_nd_managed_config_flag): "ipv6 nd managed-config-flag" is
+ added.
+ (ipv6_nd_other_config_flag): "ipv6 nd other-config-flag" is added.
+
+2001-07-23 Jun-ichiro itojun Hagino <itojun@iijlab.net>
+
+ * ioctl.c (if_ioctl): Change ioctl argument from int to u_long.
+
+ * rt_ioctl.c: Likewise.
+
+2001-07-23 Jun-ichiro itojun Hagino <itojun@iijlab.net>
+
+ * kernel_socket.c (rtm_write): Only set RTF_CLONING when the
+ interface is not p2p.
+
+2001-04-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ioctl.c (if_prefix_add_ipv6): Fix argument type.
+
+2001-04-06 Toshiaki Takada <takada@zebra.org>
+
+ * zserv.c (zsend_interface_delete): Use client->obuf instead of
+ allocating new stream.
+
+2001-03-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_netlink.c: Revert RTPROT_BOOT change.
+
+2001-03-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_netlink.c (netlink_route_change): Skip RTPROT_BOOT route.
+ (netlink_routing_table): Likewise.
+
+2001-03-07 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * zserv.c (zsend_ipv4_add_multipath): Send metric value to
+ protocol daemons.
+
+2001-02-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_netlink.c (netlink_routing_table): Do not return
+ tb[RTA_GATEWAY] is NULL. Reported by: "Michael O'Keefe"
+ <mokeefe@qualcomm.com>.
+
+2001-02-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if_ioctl.c (interface_list_ioctl): Call if_add_update().
+ Suggested by: Chris Dunlop <chris@onthe.net.au>.
+
+2001-02-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (nexthop_active_ipv4): When nexthop type is
+ NEXTHOP_TYPE_IPV4_IFINDEX, propery set the ifindex to rifindex.
+
+ * zserv.c: Initialize rtm_table_default with 0.
+
+ * zebra-0.91 is released.
+
+2001-01-31 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * kernel_socket.c (rtm_read): Filter cloned route. Suggested by:
+ Jun-ichiro itojun Hagino <itojun@iijlab.net>
+
+2001-01-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * connected.c (connected_up_ipv6): When point-to-point destination
+ address is ::, use local address for connected network.
+ (connected_down_ipv6): Likewise.
+
+2001-01-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zserv.c (zebra_serv): Add missing close() call. Reported by:
+ David Waitzman <djw@vineyard.net>.
+
+2001-01-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (rib_lookup_ipv4): New function for checking exact match
+ IGP route.
+
+2001-01-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (show_ipv6_route_protocol): Fix bug of "show ip route
+ route-type".
+
+2001-01-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * interface.c (zebra_interface): Do not call
+ zebra_interface_add_update for inactive interface.
+
+ * zserv.c (zsend_interface_address_add): Send interface address
+ flag.
+ (zsend_interface_address_delete): Likewise.
+
+2001-01-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * interface.c (if_addr_add): Add flags.
+
+ * connected.c (ifa_add_ipv4): Add new function for interface
+ address handling.
+ (ifa_delete_ipv4): Likewise.
+
+2001-01-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (rib_update): Update IPv6 RIB.
+
+ * kernel_socket.c (ifam_read): Call if_refresh() for update
+ interface flag status. This is for implicit interface up on *BSD.
+
+ * interface.c (if_refresh): Add interface flag refresh function.
+
+ * kernel_socket.c (rtm_read): Fetch link-local address interface
+ index.
+ (ifan_read): We need to fetch interface information. Suggested
+ by: Yasuhiro Ohara <yasu@sfc.wide.ad.jp>.
+
+ * rib.c (static_ipv6_nexthop_same): Add check for
+ NEXTHOP_TYPE_IPV6_IFNAME.
+
+2001-01-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.h (NEW_RIB): Turn on NEW_RIB flag. IPv6 new RIB code are
+ taken into place.
+
+2001-01-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (static_ipv6_write): Display STATIC_IPV6_GATEWAY_IFNAME
+ configuration.
+ (rib_delete_ipv6): Handle same route conter for IPv6 connected
+ route.
+ (show_ipv6_route_protocol): New command.
+ (show_ipv6_route_addr): Likewise.
+ (show_ipv6_route_prefix): Likewise.
+ (rib_update): Sweep kernel route when it is cleaned up.
+
+ * rt_socket.c (kernel_add_ipv6): Add NEXTHOP_IPV6_IFNAME
+ treatmenet.
+
+ * rt_netlink.c (kernel_init): Likewise.
+
+ * rt_ioctl.c (kernel_ioctl_ipv6_multipath): Likewise.
+
+ * rib.c (rib_add_ipv4): Cope with same connected route on a
+ interface. Suggested by: Matthew Grant <grantma@anathoth.gen.nz>.
+ (nexthop_ipv6_ifname_add): Add NEXTHOP_IPV6_IFNAME treatmenet.
+
+ * rib.h (struct new_rib): Add refcnt to keep track on the
+ reference of same connected route.
+
+ * ioctl.c (if_set_prefix): Add check for GNU_LINUX.
+
+2001-01-13 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * kernel_socket.c (ifan_read, rtm_type_str): Add RTM_OIFINFO check.
+ (rtm_type_str): Add RTM_IFANNOUNCE check.
+ (ifan_read): New function.
+ (kernel_read): Add case for RTM_IFANNOUNCE.
+
+2001-01-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_ioctl.c (kernel_ioctl_ipv6_multipath): New function.
+
+ * rt_netlink.c (netlink_route_multipath): IPv6 address ifindex
+ treatment.
+
+ * connected.c (connected_up_ipv6): Add dest value check.
+
+ * rib.c (nexthop_active_ipv6): Do not touch IPv6 nexthop's
+ ifindex.
+ (rib_add_ipv4): Import rib_add_ipv6() same route check code.
+ (nexthop_active_check): NEXTHOP_TYPE_IPV6_IFINDEX activity is only
+ checked by ifindex.
+
+ * rt_socket.c (kernel_rtm_ipv6_multipath): New function.
+
+ * redistribute.c (redistribute_add): Use
+ zsend_ipv6_add_multipath().
+ (redistribute_delete_multipath): Use
+ zsend_ipv6_delete_multipath().
+
+ * interface.c (ip_address): Check current IP address to avoid
+ duplicate.
+
+ * rib.c (rib_delete_ipv4): When deleted route is connected route,
+ check ifindex.
+ (rib_add_ipv4): When connected route is added do not perform
+ implicit withdraw.
+ (rib_delete_ipv4): Check ifindex for connected route.
+
+ * kernel_socket.c (rtm_read): When route has RTF_STATIC, set
+ ZEBRA_FLAG_STATIC for indicate as persistent route.
+ (ifam_read): Unset interface index from link-local address when
+ IPv6 stack is KAME.
+
+ * rib.c (rib_update): Do not delete persistent kernel route.
+
+ * rib.h (struct new_rib): Integrate RIB_FLAG_* to ZEBRA_FLAG_*.
+
+ * rt_socket.c (kernel_add_ipv6_multipath): Add placeholder.
+ (kernel_delete_ipv6_multipath): Likewise.
+
+ * rt_netlink.c (netlink_talk): Give struct nlsock to netlink_talk.
+
+2001-01-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (rib_update): Revert Matthew Grant's patch
+ zebra_cvs_newribfix.patch. Use struct rib->ifindex for kernel
+ interface index. Introduce NEXTHOP_TYPE_IPV4_IFINDEX to support
+ that. Add support for address deletion situation.
+
+2001-01-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * interface.c: Remove HAVE_IF_PSEUDO part.
+
+ * rib.h: Likewise.
+
+ * rt_netlink.c (netlink_link_change): Likewise.
+
+2001-01-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zserv.c: Remove OLD_RIB codes.
+
+2001-01-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.90 is released.
+
+2001-01-09 Matthew Grant <grantma@anathoth.gen.nz>
+
+ * interface.c (if_new_intern_ifindex): Allocate a new internal
+ interface index.
+ (if_addr_refresh): Fix up ip addresses configured via zebra.
+ (if_add_update): Handle an interface addition.
+ (if_delete_update): Handle an interface delete event.
+
+ * rib.c (nexthop_ipv4_add): Add kernel route deletion process when
+ interface goes down.
+
+2001-01-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * interface.c (if_dump_vty): When HAVE_NET_RT_IFLIST is defined,
+ NetBSD also use this function. Suggested by Jasper Wallace
+ <jasper@ivision.co.uk>.
+
+2001-01-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (nexthop_active_ipv4): Move back to set methodo to old
+ one.
+
+2001-01-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (rib_add_ipv4): EBGP multihop set ZEBRA_FLAG_INTERNAL
+ flag, so treat it.
+
+2001-01-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_netlink.c (netlink_talk_ipv6): When IPv6 route message is
+ sent from netlink_cmd, the same message comes from netlink. To
+ avoid confusion, temporary netlink_talk_ipv6 use netlink.sock
+ instead of netlink_cmd.sock.
+
+2001-01-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zserv.h (ZEBRA_SERV_PATH): Change "/tmp/zebra" to "/tmp/.zebra".
+ Change "/tmp/zserv" to "/tmp/.zserv".
+
+2000-12-29 Frank van Maarseveen <F.vanMaarseveen@inter.NL.net>
+
+ * rt_netlink.c (struct nlsock): Divide kernel message into listen
+ socket and command socket.
+ (netlink_talk): Remove socket listen code. Use netlink_parse_info
+ for read kernel response.
+
+2000-12-29 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (vty_show_ip_route): Show uptime of the RIP,OSPF,BGP
+ routes.
+
+2000-12-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_netlink.c (netlink_route_multipath): Metric value is
+ reflected to kernel routing table.
+
+ * rt_ioctl.c (kernel_ioctl_ipv4_multipath): Likewise.
+
+ * kernel_socket.c (rtm_write): Likewise.
+
+ * rib.c (nexthop_active_ipv4): Only iBGP route perform recursive
+ nexthop lookup.
+
+ * rt_ioctl.c (kernel_ioctl_ipv4_multipath): Add ioctl version of
+ new RIB implementation.
+
+2000-12-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.h: Remove MULTIPATH_NUM. It is defined by configure script.
+
+2000-12-25 Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+ * rib.c (rib_if_up): Call rib_fib_set instead of RIB_FIB_SET for
+ proper redistribution.
+
+2000-12-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (nexthop_active_ipv4): Add self lookup nexthop check.
+ (show_ip_route_protocol): Support new RIB.
+
+ * rt_netlink.c (netlink_route_change): Do not return when gate is
+ NULL.
+
+2000-12-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (rib_lookup_ipv4_nexthop): IBGP nexthop check function is
+ updated.
+ (rib_add_ipv4): Free implicit withdraw route's RIB.
+
+2000-12-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (nexthop_active_ipv4): Check indirect nexthop.
+
+ * redistribute.c (redistribute_add_multipath): Redistribution
+ works with new rib code.
+
+2000-12-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_netlink.c (netlink_route_multipath): Check useful nexthop
+ number.
+ (netlink_route_multipath): Clear rtnh_flags and rtnh_hops.
+
+ * rib.c (nexthop_active_update): Set flag for the rib's nexthop
+ activity is changed.
+ (nexthop_active_check): Before checking interface is up, make it
+ sure the interface exist.
+
+2000-11-20 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (ip_route): New RIB prototype.
+
+2000-11-16 Yon Uriarte <ukl2@rz.uni-karlsruhe.de>
+
+ * zserv.c (zsend_interface_add): Send hardware address when
+ hw_addr_len is greater than 0.
+
+2000-11-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * connected.c (connected_up_ipv4): Fix ptop bug. The destination
+ network should be installed into routing table.
+ (connected_down_ipv4): Likewise.
+ (connected_add_ipv4): Change to use connected_up_ipv4.
+ (connected_delete_ipv4): Likewise.
+
+2000-11-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_netlink.c (netlink_interface_addr): Revert Harald Welte
+ <laforge@gnumonks.org>'s ptop patch then back to original code to
+ avoid duplicated connected route problem. Suggested by Frank van
+ Maarseveen <F.vanMaarseveen@inter.NL.net>.
+
+ * kernel_socket.c (rtm_read): Make behavior consistent even #ifdef
+ DEBUG is defined. Reported by Jun-ichiro itojun Hagino
+ <itojun@iijlab.net>.
+
+2000-10-23 Jochen Friedrich <jochen@scram.de>
+
+ * main.c (main): Call zebra_snmp_init() when it is enabled.
+
+2000-10-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zserv.c (zebra_serv_un): UNIX domain socket server of zebra
+ protocol.
+
+2000-10-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (rib_add_ipv4): Same check bug is fixed.
+
+2000-10-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (rib_if_down): Remove kernel route when the interface goes
+ down.
+
+ * debug.c: New command "debug zebra kernel" is added.
+
+2000-10-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.89 is released.
+
+2000-09-24 Harald Welte <laforge@gnumonks.org>
+
+ * rt_netlink.c (netlink_interface_addr): Fix point-to-point address
+ treatment in netlink interface.
+
+2000-09-21 David Lipovkov <dlipovkov@OpticalAccess.com>
+
+ * rib.c (rib_if_down): Pull static route only. Protocol daemon
+ must withdraw routes when interface goes down.
+ (rib_add_ipv4): Check nexthop when replace route.
+
+2000-09-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if_ioctl.c (if_getaddrs): New function for looking up
+ interface's address by getifaddrs().
+
+2000-09-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * connected.c (connected_delete_ipv4): Add check for connected
+ address is found or not.
+ (connected_add_ipv6): Reflect IPv6 connected address change to
+ protocol daemons.
+ (connected_delete_ipv6): Likewise.
+
+2000-09-07 David Lipovkov <davidl@nbase.co.il>
+
+ * rib.c (rib_delete_ipv4): Reverted the change from pseudo
+ interface patch to original. Because ospfd deletes routes using
+ zero ifindex.
+
+2000-08-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.88 is released.
+
+2000-08-15 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * rib.c (show_ip_route_protocol): Help string correction.
+ (show_ip_route_prefix): Check prefix mask.
+ (show_ip_route_vty_detail): Display distance and metric.
+
+2000-08-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zserv.c (zsend_interface_add): Change ifindex store size from
+ two octet to four.
+ (zsend_interface_delete): Likewise.
+ (zsend_interface_address_add): Likewise.
+ (zsend_interface_address_delete): Likewise.
+ (zsend_interface_up): Likewise.
+ (zsend_interface_down): Likewise.
+
+2000-08-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (rib_add_ipv4): Do not install distance 255 route.
+
+2000-08-10 Toshiaki Takada <takada@zebra.org>
+
+ * interface.c (bandwidth_if), (no_bandwidth_if): Call
+ zebra_interface_up_update () instead of using if_up() and if_down().
+
+2000-08-07 "Akihiro Mizutani" <mizutani@dml.com>
+
+ * interface.c (bandwidth_if): Fix help string.
+
+2000-08-07 Matthew Grant <grantma@anathoth.gen.nz>
+
+ * interface.c (if_dump_vty): Display bandwidth value.
+ (bandwidth_if): New command "bandwidth <1-10000000>" is added.
+ When interface is up, force protocol daemons to recalculate routes
+ due to cost change.
+ (no_bandwidth_if): Likewise.
+ (if_config_write): Output bandwidth configuration.
+
+ * zserv.c (zsend_interface_add): Send bandwidth value.
+ (zsend_interface_up): Likewise.
+ (zsend_interface_down): Likewise.
+
+
+2000-08-07 Michael Rozhavsky <mike@nbase.co.il>
+
+ * rib.c (show_ip_route_protocol): "show ip route
+ (bgp|connected|kernel|ospf|rip|static)" is added.
+
+2000-08-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (rib_lookup_ipv4_nexthop): Check parent node until IGP
+ nexthop is found.
+ (rib_add_ipv4_internal): Set fib ifindex to rib ifindex.
+
+2000-08-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * redistribute.c (redistribute_delete): Fix bug of default route
+ redistribute treatment.
+
+2000-08-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (rib_init): Install ip_node in rib.c instead of zserv.c.
+ Change default distance value.
+
+ Old New
+ ------------------------------------------
+ system 10 0
+ kernel 20 0
+ connected 30 0
+ static 40 1
+ rip 50 120
+ ripng 50 120
+ ospf 60 110
+ ospf6 49 110
+ bgp 70 200(iBGP) 20(eBGP)
+ ------------------------------------------
+
+ * zserv.c (client_lookup): Function removed.
+ (zsend_interface_add): Use client's output buffer. Check ifinfo
+ flag.
+ (zsend_interface_delete): Likewise.
+ Delete ipv4_static_radix and ipv6_static_radix.
+
+2000-08-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zserv.h (struct zebra_client): When client request interface
+ information, ifinfo is set.
+
+ * rib.c: Temporary Revert changes for pseudo interface.
+
+ * rib.h: Likewise.
+
+ * zserv.c: Likewise.
+
+ * interface.c: Likewise.
+
+2000-08-02 David Lipovkov <davidl@nbase.co.il>
+
+ * interface.c (zebra_if_init): Install interface "pseudo"
+ commands.
+
+ * rib.c (rib_create): ifname argument is added.
+ (rib_add_ipv4_pseudo): New function is added.
+ (rib_delete_ipv4_pseudo): Likewise.
+
+ * rib.h : Delete INTERFACE_UNKNOWN definition. Add prototype for
+ pseudo interface functions.
+
+ * rt_netlink.c (netlink_link_change): Check for pseudo interface.
+
+ * zserv.c (ip_route): When destination is pseudo interface, call
+ rib_add_ipv4_pseudo().
+
+ * zserv.c (no_ip_route): Trim "unknown" argument.
+
+2000-07-26 kunitake@dti.ad.jp
+
+ * if_ioctl.c (if_get_hwaddr): Fix hardware address length from 8
+ to 6.
+
+ * rtadv.c (rtadv_send_packet): Fix shift bug for hardware address.
+
+2000-07-24 Akihiro Mizutani <mizutani@dml.com>
+
+ * interface.c: Use install_default() for common VTY commands.
+
+2000-07-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if_ioctl.c (interface_list_ioctl): A interface list size is
+ calculated from ifreq->if_addr.sa_len. This is for OpenBSD.
+
+ * ioctl.c (if_get_mtu): Remove codes for SIOCGIFDATA.
+
+2000-07-09 Chris Dunlop <chris@onthe.net.au>
+
+ * if_ioctl.c (if_get_index): Add check for HAVE_BROKEN_ALIASES.
+
+2000-07-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zserv.c (zebra_client_read): Add ZEBRA_REDISTRIBUTE_{ADD,DELETE}
+ message handling.
+
+2000-07-02 David Lipovkov <davidl@nbase.co.il>
+
+ * zserv.c: "ip route A.B.C.D/M unknown" command is added.
+
+2000-06-28 Michael Rozhavsky <mike@nbase.co.il>
+
+ * rib.c: Remove old kernel route when new route comes in.
+
+2000-06-13 David Lipovkov <davidl@nbase.co.il>
+
+ * rib.c (rib_if_up): Add check for unknown interface.
+
+2000-06-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.h: Define INTERFACE_UNKNOWN.
+
+2000-06-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am (EXTRA_DIST): Move irdp.c until implementation is
+ finished.
+
+2000-06-05 David Lipovkov <davidl@nbase.co.il>
+
+ * interface.c (if_zebra_delete_hook): Call rib_if_delete().
+
+ * redistribute.c (zebra_interface_delete_update): New function.
+
+ * redistribute.h (zebra_interface_delete_update): New function
+ prototype.
+
+ * rib.c (rib_if_delete): New function. Walk down all routes and
+ delete all on the interface.
+
+ * rib.h: New function prototype.
+
+ * rt_netlink.c (netlink_link_change): Call
+ zebra_interface_delete_update ().
+
+2000-05-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if_ioctl.c (interface_info_ioctl): Check interface's flag before
+ checking interface's address.
+
+2000-04-26 Jochen Friedrich <jochen@nwe.de>
+
+ * GNOME-PRODUCT-ZEBRA-MIB: New file.
+
+ * GNOME-SMI: New file.
+
+2000-04-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * irdp.c: New file from 1997 development code.
+ * irdp.h: Likewise.
+
+2000-04-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rtadv.c (rtadv_send_packet): Enclose router advertisement
+ logging with IS_ZEBRA_DEBUG_PACKET.
+
+2000-04-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zserv.c (zebra_client_close): Remove client structure from
+ client_list when connection is terminated.
+
+2000-03-21 David Lipovkov <davidl@nbase.co.il>
+
+ * connected.c (connected_add_ipv4): Allows all necessary structure
+ updates for connected route, but doesn't insert it into rib if
+ it's interface is down.
+
+2000-01-21 Hideto Yamakawa <hideto.yamakawa@soliton.co.jp>
+
+ * rtread_getmsg.c: Set some definition for Solaris 2.5 and Solaris
+ 2.5.1.
+
+2000-01-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (no_ipv6_route_ifname): Fix buf of cheking return value
+ from str2prefix_ipv6().
+
+2000-01-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_socket.c: Revert to use RTF_HOST for IPv4 with /32 route and
+ IPv6 with /128 routes.
+ (kernel_rtm_ipv4): In case of /32 route's gateway is interface. It
+ should have mask for cloning.
+
+1999-12-26 Jochen.Friedrich@genorz.de
+
+ * interface.c (if_dump_vty): Fix a bug of missing VTY_NEWLINE.
+
+1999-12-23 Alex Zinin <zinin@amt.ru>
+ * interface.*: dynamic int up/down support
+
+1999-12-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ipforward_proc.c (dropline): Move dropline() from lib/dropline.c
+
+ * rtread_proc.c (proc_route_read): Don't use dropline().
+
+1999-12-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * kernel_socket.c (rtm_read): When message is RTM_GET, it has own
+ process's pid.
+
+1999-12-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * main.c (main): Change to default log output to ZLOG_STDOUT.
+
+ * zserv.c (zebra_serv): More detailed error print.
+
+1999-11-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * kernel_socket.c (rtm_read): Check old pid for static route
+ insertion check.
+
+1999-11-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * interface.c (if_dump_vty): BSDI/OS uses 64bit for interface
+ statistics counter.
+
+ * mtu_kvm.c: New file added.
+
+1999-11-27 Vladimir B. Grebenschikov <vova@express.ru>
+
+ * kernel_socket.c (rtm_write): Set RTF_CLONING flag for
+ route to the directly connected interface.
+
+1999-11-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_socket.c: Delete USE_HOST_BIT definition.
+
+1999-11-21 Michael Handler <handler@sub-rosa.com>
+
+ * rtread_getmsg.c: Undef some definition to resolve conflict.
+
+1999-11-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * kernel_socket.c (rtm_write): Change to use pre stored struct_dl
+ value for gateway specification.
+
+1999-11-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_socket.c (kernel_rtm_ipv4): Even mask is 32 under IPv4 or
+ 128 under IPv6, don't use RTF_HOST.
+
+1999-11-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am (EXTRA_DIST): Add rtread_getmsg.c.
+
+1999-11-21 Michael Handler <handler@sub-rosa.com>
+
+ * rtread_getmsg.c: Added for Solaris 2.6 support.
+
+1999-11-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rtread_sysctl.c (rtm_read_route): RTM_DELETE handling added.
+
+ * rt_socket.c (kernel_read): Better BSD routing socket support.
+
+1999-10-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * client_main.c: Disable making obsolete zebra test `client'
+ command.
+
+1999-10-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra.c: Renamed to zserv.c.
+
+ * zebra.h: Global definitions are moved to lib/zebra.h. Then
+ renamed to zserv.h.
+
+1999-10-15 Jordan Mendelson <jordy@wserv.com>
+
+ * if_ioctl.c: Add Linux 2.2.X's alias support and dynamic
+ interface. Remove ugly MAX_INTERFACE handling codes.
+
+1999-09-17 Satosi KOBAYASI <kobayasi@north.ad.jp>
+
+ * Fix serious bug of IPv6 route deletion.
+
+1999-09-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ioctl.c (if_set_prefix): Properly set broadcast address.
+
+1999-09-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * rib.c (rib_add_ipv6, rib_delete_ipv6): now protocol daemons
+ can install connected route to kernel via zebra
+
+1999-08-24 VOP <vop@unity.net>
+
+ * rib.c: Include "sockunion.h"
+
+1999-08-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ipforward.h: New file.
+
+ * zebra.h: Obsolete message ZEBRA_GET_ALL_INTERFACE,
+ ZEBRA_GET_ONE_INTERFACE, ZEBRA_GET_HOSTINFO are deleted.
+
+1999-08-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra.h (ZEBRA_INTERFACE_ADDRESS_ADD):
+ ZEBRA_INTERFACE_{ADD,DELETE} added.
+
+1999-08-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c: show ip route A.B.C.D works.
+
+ * zebra.c (zebra_read_ipv4): Add ifindex to zebra messages.
+
+1999-08-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra.h: New Zebra message ZEBRA_INTERFACE_{ADD,DELETE} added.
+
+1999-08-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * interface.h: New file.
+ * Makefile.am: Add interface.h
+
+1999-08-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * redistribute.c (zebra_redistribute): give ifindex to client.
+
+1999-08-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * main.c (longopts): -k, --keep_kernel option added.
+
+1999-07-18 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * rt_socket.c (rtm_write): forgot closing socket bug fixed.
+
+1999-07-17 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * rib.c (show_ipv6_cmd): if rib is link show interface name.
+
+1999-07-17 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * rt_socket.c (rtm_write): use sockaddr_dl when null gateway.
+
+1999-07-16 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * rt_socket.c (rtm_write): ipv6 route table bug fixed.
+
+1999-07-15 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * zebra.c (zebra_read_ipv6): read link prefix from ospf6 support
+
+1999-07-15 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * rt_socket.c (kernel_rtm_ipv6): gate treatment bug fixed.
+
+1999-07-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if_sysctl.c (ifm_read): Clear sockunion argument before fetching
+ data. Suggested by "Chris P. Ross" <cross@eng.us.uu.net>
+
+1999-07-08 HEO SeonMeyong <seirios@Matrix.IRI.Co.Jp>
+
+ * interface.c (if_tun_add): Add KAME's gif tunnel setting codes.
+
+1999-06-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra.c (zebra_serv): Only accept loopback address connection.
+
+1999-06-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra.h (ZEBRA_ROUTE_EXTERNAL): Add zebra messages flags
+
+1999-06-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ipforward_proc.c: ipforward_on () and ipforward_off () added.
+
+1999-06-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ipforward_proc.c (ipforward_ipv6): Check for IPv6 forwarding
+ using /proc file system is added.
+
+1999-06-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if_ioctl.c (if_get_index): Interface index set bug is fixed by
+ adding #else at the middle of function. Suggested by David Luyer
+ <luyer@ucs.uwa.edu.au>.
+
+1999-05-29 <kunihiro@zebra.org>
+
+ * rt_ioctl.c: Comment out #include <linux/ipv6_route.h>.
+
+1999-05-26 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra.h (ZEBRA_ROUTE_MAX): Add new define for the max value of
+ the sort of routes.
+
+1999-05-25 Patrick Koppen <koppen@rhrk.uni-kl.de>
+
+ * rt_netlink.c (netlink_socket): Make netlink socket non-blocking.
+ (netlink_parse_info): If errno is EWOULDBLOCK then continue to
+ parse the message.
+ (netlink_talk): Likewise
+
+1999-05-17 <kunihiro@zebra.org>
+
+ * redistribute.c (zebra_check_addr): Added for loopback address
+ check.
+
+1999-05-15 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_netlink.c (netlink_route_change): Tempolary bypass ipv6 route
+ change treatment.
+
+ * Makefile.am (noinst_HEADERS): redistribute.h added.
+
+ * redistribute.h: New file.
+
+1999-05-14 Stephen R. van den Berg <srb@cuci.nl>
+
+ * zebra.c (show_table): Show all table configuration DEFUN.
+ (config_table): Config table number DEFUN.
+
+ * rt_netlink.c: Add support for multiple routing table.
+
+ * rib.c (rib_weed_table): New function added for delete all
+ routes from specified routing table.
+
+ * main.c (signal_init): SIGTERM call sigint.
+ (sigint): Loggging more better message.
+
+1999-05-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_netlink.c: Change log () to zlog ().
+
+1999-05-07 <kunihiro@zebra.org>
+
+ * zebra.h (ZEBRA_ROUTE_OSPF6): Added for ospf6d route.
+
+1999-04-20 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * interface.c: Add `no ip address' command.
+
+1999-04-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_netlink.c (kernel_read): Function added for asynchronous
+ zebra between kernel communication.
+
+1999-03-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rtread_sysctl.c (rtm_read): Fix address memcopy overrun bug.
+ Reported by Achim Patzner <ap@bnc.net>.
+
+1999-03-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am: Install configuration sample with 600 permission.
+
+1999-03-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am: Add -I.. to INCLUDES.
+
+1999-02-18 Peter Galbavy <Peter.Galbavy@knowledge.com>
+
+ * syslog support added
+
+1999-02-17 Peter Galbavy <Peter.Galbavy@knowledge.com>
+
+ * if_sysctl.c (interface_list): allocated memory free when unknown
+ ifm_type is returned.
+
+ * ioctl.c (if_get_mtu): added SIOCGIFDATA treatment.
+
+1998-12-15 Magnus Ahltorp <map@stacken.kth.se>
+
+ * interface.c: Header include added.
+
+1998-12-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt.h (kernel_delete_ipv6): change int index to unsigned int index.
+
+1998-12-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if_ioctl.c (interface_list_ioctl): interface flag must be
+ checked before check addresses of the interface.
+
+1998-12-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am (INCLUDES): add @INCLUDES@ for Linux IPv6.
+
+1998-10-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ioctl.c: Linux version before 2.1.0 need interface route setup.
+
+1998-09-15 HEO SeonMeyong <seirios@matrix.iri.co.jp>
+
+ * change HYDRANGEA to KAME
+
+1998-09-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if_ioctl.c (if_addr_ioctl): set address family for getting
+ interface's address.
+ (if_get_index): silently return when can't get interface's index.
+
+1998-08-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * main.c (main): batch mode option '-b' added.
+
+1998-08-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ioctl.c (if_set_prefix): add `ip address IPV4ADDR' command.
+ * interface.c (shutdown_if): add interface shutdown and no
+ shutdown command.
+
+1998-08-12 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rib.c (rib_add_ipv6): delete rib_add_in6.
+
+1998-07-27 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * main.c: retain flag is added.
+
+1998-07-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rtable.[ch]: merged with rib.[ch]
+
+1998-07-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * connected.h: renamed from ifa.h.
+
+1998-06-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rename if.c to interface.c
+ * rename ifa.c to connected.c
+
+ * Porting to Debian GNU/Linux 2.0 (hamm).
+
+1998-06-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_netlink.c: renamed from krt_netlink.c
+
+ * fib.c: deleted.
+ * rt_kvm.c: deleted.
+ * rtread_getmsg.c: deleted.
+
+1998-06-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if.c (multicast): add multicast flag [un]set fucntion.
+
+1998-05-19 Yamshita TAKAO <jargon@lares.dti.ne.jp>
+
+ * rt_socket.c: Modify for compile on Solaris, but dont't work it.
+ rt_socket.c have some undefined function, so add directive "IMPLEMENT"
+
+1998-05-18 Yamshita TAKAO <jargon@lares.dti.ne.jp>
+
+ * zebra.c: Modify for compile on Solaris.
+
+1998-05-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * main.c: change CONFDIR to SYSCONFDIR.
+
+1998-05-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * .cvsignore: added.
+
+1998-04-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * client.c: moves to ../lib.
+
+1998-03-30 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if_ioctl.c (if_get_addr): Change address copy from memcopy() to
+ structure assignment.
+
+1998-03-30 URA Hiroshi <ura@yamato.ibm.co.jp>
+
+ * if_sysctl.c (ifm_interface_add): sdl->sdl_data copy bug fixed.
+
+1998-02-23 "Hannes R. Boehm" <hannes@boehm.org>
+
+ * if.c (if_init): add config_exit_cmd and config_help_cmd.
+
+1998-01-24 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_ioctl.c (route_ioctl): EPERM treatment added.
+
+1998-01-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_socket.c (kernel_read): communication port zebra between
+ kernel is now handled by kernel_read.
+
+1998-01-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * main.c (main): zebra [-P port] can specify vty port number.
+
+1997-12-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra.c: change select will be block.
+
+1997-12-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * add static route treatment.
+
+1997-11-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_netlink.c: add netlink support over GNU/Linux system.
+
+1997-11-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * all inet_addr is changed to inet_aton.
+
+ * zebra.c (ip_route): add ip route command for static routes.
+
+1997-11-20 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if.c (if_flag_dump): Linux port of if_flag_dump and _vty.
+
+1997-11-19 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if.c: add interface command.
+
+1997-11-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ipforward_proc.c : Now works on Linux.
+
+1997-10-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * command.c : add completion feature.
+
+1997-10-18 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vty.c (vty_command): add vty interface.
+
+1997-10-13 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra.c: add verbose mode.
+
+1997-10-12 SonMyong Ho <s-ho@Matrix.IRI.Co.Jp>
+
+ * Hydrangea for FreeBSD supported
+ * in.h: add some prototype.
+
+1997-10-11 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_socket.c and rtread.c completely rewritten.
+
+1997-10-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * rt_socket.c: rename kernel_sock to routing_socket
+
+1997-10-04 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * if.c (if_new): interface structure change from linklist to vector.
+
+1997-10-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * vector.c (vector_init): create vector related function
+
+1997-09-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.in: add tags target
+
+ * start IPv6 support for INRIA FreeBSD.
+
diff --git a/zebra/GNOME-PRODUCT-ZEBRA-MIB b/zebra/GNOME-PRODUCT-ZEBRA-MIB
new file mode 100644
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 <zebra.h>
+
+#include "prefix.h"
+#include "stream.h"
+#include "zclient.h"
+#include "thread.h"
+#include "table.h"
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+
+struct thread *master;
+
+/* Zebra client structure. */
+struct zclient *zclient = NULL;
+
+/* Zebra socket. */
+int sock;
+
+/* IPv4 route add and delete test. */
+void
+zebra_test_ipv4 (int command, int type, char *prefix, char *gateway,
+ u_char distance)
+{
+ struct zapi_ipv4 api;
+ struct prefix_ipv4 p;
+ struct in_addr gate;
+ struct in_addr *gpnt;
+
+ str2prefix_ipv4 (prefix, &p);
+ inet_aton (gateway, &gate);
+ gpnt = &gate;
+
+ api.type = type;
+ api.flags = 0;
+
+ api.message = 0;
+ SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+ api.nexthop_num = 1;
+ api.nexthop = &gpnt;
+ api.ifindex_num = 0;
+ if (distance)
+ {
+ SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE);
+ api.distance = distance;
+ }
+
+
+ switch (command)
+ {
+ case ZEBRA_IPV4_ROUTE_ADD:
+ zapi_ipv4_add (zclient, &p, &api);
+ break;
+ case ZEBRA_IPV4_ROUTE_DELETE:
+ zapi_ipv4_delete (zclient, &p, &api);
+ break;
+ }
+}
+
+#ifdef HAVE_IPV6
+/* IPv6 route add and delete test. */
+void
+zebra_test_v6 (int sock)
+{
+ struct prefix_ipv6 p;
+ struct in6_addr nexthop;
+
+ str2prefix_ipv6 ("3ffe:506::2/128", &p);
+ inet_pton (AF_INET6, "::1", &nexthop);
+
+ /* zebra_ipv6_add (sock, ZEBRA_ROUTE_STATIC, 0, &p, &nexthop, 1); */
+
+ sleep (5);
+ /* zebra_ipv6_delete (sock, ZEBRA_ROUTE_STATIC, 0, &p, &nexthop, 1); */
+}
+#endif /* HAVE_IPV6 */
+
+/* Print out usage and exit. */
+void
+usage_exit ()
+{
+ fprintf (stderr, "Usage: client filename\n");
+ exit (1);
+}
+
+struct zebra_info
+{
+ char *str;
+ int type;
+} zebra_type[] =
+{
+ { "static", ZEBRA_ROUTE_STATIC },
+ { "rip", ZEBRA_ROUTE_RIP },
+ { "ripng", ZEBRA_ROUTE_RIPNG },
+ { "ospf", ZEBRA_ROUTE_OSPF },
+ { "ospf6", ZEBRA_ROUTE_OSPF6 },
+ { "bgp", ZEBRA_ROUTE_BGP },
+ { NULL, 0 }
+};
+
+/* Zebra route simulator. */
+void
+zebra_sim (FILE *fp)
+{
+ char buf[BUFSIZ];
+ char distance_str[BUFSIZ];
+ u_char distance;
+
+ while (fgets (buf, sizeof buf, fp))
+ {
+ int i;
+ int ret;
+ int type;
+ char str[BUFSIZ], command[BUFSIZ], prefix[BUFSIZ], gateway[BUFSIZ];
+
+ distance = 0;
+
+ if (*buf == '#')
+ continue;
+
+ type = ZEBRA_ROUTE_STATIC;
+
+ ret = sscanf (buf, "%s %s %s %s %s\n", command, str, prefix, gateway,
+ distance_str);
+
+ if (ret == 5)
+ {
+ distance = atoi (distance_str);
+ }
+ else
+ {
+ ret = sscanf (buf, "%s %s %s %s\n", command, str, prefix, gateway);
+
+ if (ret != 4)
+ continue;
+ }
+
+ for (i = 0; i < 10; i++)
+ {
+ if (!zebra_type[i].str)
+ break;
+ if (strcmp (zebra_type[i].str, str) == 0)
+ {
+ type = zebra_type[i].type;
+ break;
+ }
+ }
+
+ if (strcmp (command, "add") == 0)
+ {
+ zebra_test_ipv4 (ZEBRA_IPV4_ROUTE_ADD, type, prefix, gateway,
+ distance);
+ printf ("%s", buf);
+ continue;
+ }
+
+ if (strcmp (command, "del") == 0)
+ {
+ zebra_test_ipv4 (ZEBRA_IPV4_ROUTE_DELETE, type, prefix, gateway,
+ distance);
+ printf ("%s", buf);
+ continue;
+ }
+ }
+}
+
+/* Test zebra client main routine. */
+int
+main (int argc, char **argv)
+{
+ FILE *fp;
+
+ if (argc == 1)
+ usage_exit ();
+
+ /* Establish connection to zebra. */
+ zclient = zclient_new ();
+ zclient->enable = 1;
+#ifdef HAVE_TCP_ZEBRA
+ zclient->sock = zclient_socket ();
+#else
+ zclient->sock = zclient_socket_un (ZEBRA_SERV_PATH);
+#endif /* HAVE_TCP_ZEBRA */
+
+ /* Open simulation file. */
+ fp = fopen (argv[1], "r");
+ if (fp == NULL)
+ {
+ fprintf (stderr, "can't open %s\n", argv[1]);
+ exit (1);
+ }
+
+ /* Do main work. */
+ zebra_sim (fp);
+
+ sleep (100);
+
+ fclose (fp);
+ close (sock);
+
+ return 0;
+}
diff --git a/zebra/connected.c b/zebra/connected.c
new file mode 100644
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 <zebra.h>
+
+#include "prefix.h"
+#include "linklist.h"
+#include "if.h"
+#include "table.h"
+#include "rib.h"
+#include "table.h"
+#include "log.h"
+
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+
+/* 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 <zebra.h>
+#include "command.h"
+#include "debug.h"
+
+/* For debug statement. */
+unsigned long zebra_debug_event;
+unsigned long zebra_debug_packet;
+unsigned long zebra_debug_kernel;
+
+DEFUN (show_debugging_zebra,
+ show_debugging_zebra_cmd,
+ "show debugging zebra",
+ SHOW_STR
+ "Zebra configuration\n"
+ "Debugging information\n")
+{
+ vty_out (vty, "Zebra debugging status:%s", VTY_NEWLINE);
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ vty_out (vty, " Zebra event debugging is on%s", VTY_NEWLINE);
+
+ if (IS_ZEBRA_DEBUG_PACKET)
+ {
+ if (IS_ZEBRA_DEBUG_SEND && IS_ZEBRA_DEBUG_RECV)
+ {
+ vty_out (vty, " Zebra packet%s debugging is on%s",
+ IS_ZEBRA_DEBUG_DETAIL ? " detail" : "",
+ VTY_NEWLINE);
+ }
+ else
+ {
+ if (IS_ZEBRA_DEBUG_SEND)
+ vty_out (vty, " Zebra packet send%s debugging is on%s",
+ IS_ZEBRA_DEBUG_DETAIL ? " detail" : "",
+ VTY_NEWLINE);
+ else
+ vty_out (vty, " Zebra packet receive%s debugging is on%s",
+ IS_ZEBRA_DEBUG_DETAIL ? " detail" : "",
+ VTY_NEWLINE);
+ }
+ }
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ vty_out (vty, " Zebra kernel debugging is on%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_zebra_events,
+ debug_zebra_events_cmd,
+ "debug zebra events",
+ DEBUG_STR
+ "Zebra configuration\n"
+ "Debug option set for zebra events\n")
+{
+ zebra_debug_event = ZEBRA_DEBUG_EVENT;
+ return CMD_WARNING;
+}
+
+DEFUN (debug_zebra_packet,
+ debug_zebra_packet_cmd,
+ "debug zebra packet",
+ DEBUG_STR
+ "Zebra configuration\n"
+ "Debug option set for zebra packet\n")
+{
+ zebra_debug_packet = ZEBRA_DEBUG_PACKET;
+ zebra_debug_packet |= ZEBRA_DEBUG_SEND;
+ zebra_debug_packet |= ZEBRA_DEBUG_RECV;
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_zebra_packet_direct,
+ debug_zebra_packet_direct_cmd,
+ "debug zebra packet (recv|send)",
+ DEBUG_STR
+ "Zebra configuration\n"
+ "Debug option set for zebra packet\n"
+ "Debug option set for receive packet\n"
+ "Debug option set for send packet\n")
+{
+ zebra_debug_packet = ZEBRA_DEBUG_PACKET;
+ if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
+ zebra_debug_packet |= ZEBRA_DEBUG_SEND;
+ if (strncmp ("recv", argv[0], strlen (argv[0])) == 0)
+ zebra_debug_packet |= ZEBRA_DEBUG_RECV;
+ zebra_debug_packet &= ~ZEBRA_DEBUG_DETAIL;
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_zebra_packet_detail,
+ debug_zebra_packet_detail_cmd,
+ "debug zebra packet (recv|send) detail",
+ DEBUG_STR
+ "Zebra configuration\n"
+ "Debug option set for zebra packet\n"
+ "Debug option set for receive packet\n"
+ "Debug option set for send packet\n"
+ "Debug option set detaied information\n")
+{
+ zebra_debug_packet = ZEBRA_DEBUG_PACKET;
+ if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
+ zebra_debug_packet |= ZEBRA_DEBUG_SEND;
+ if (strncmp ("recv", argv[0], strlen (argv[0])) == 0)
+ zebra_debug_packet |= ZEBRA_DEBUG_RECV;
+ zebra_debug_packet |= ZEBRA_DEBUG_DETAIL;
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_zebra_kernel,
+ debug_zebra_kernel_cmd,
+ "debug zebra kernel",
+ DEBUG_STR
+ "Zebra configuration\n"
+ "Debug option set for zebra between kernel interface\n")
+{
+ zebra_debug_kernel = ZEBRA_DEBUG_KERNEL;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_zebra_events,
+ no_debug_zebra_events_cmd,
+ "no debug zebra events",
+ NO_STR
+ DEBUG_STR
+ "Zebra configuration\n"
+ "Debug option set for zebra events\n")
+{
+ zebra_debug_event = 0;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_zebra_packet,
+ no_debug_zebra_packet_cmd,
+ "no debug zebra packet",
+ NO_STR
+ DEBUG_STR
+ "Zebra configuration\n"
+ "Debug option set for zebra packet\n")
+{
+ zebra_debug_packet = 0;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_zebra_packet_direct,
+ no_debug_zebra_packet_direct_cmd,
+ "no debug zebra packet (recv|send)",
+ NO_STR
+ DEBUG_STR
+ "Zebra configuration\n"
+ "Debug option set for zebra packet\n"
+ "Debug option set for receive packet\n"
+ "Debug option set for send packet\n")
+{
+ if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
+ zebra_debug_packet &= ~ZEBRA_DEBUG_SEND;
+ if (strncmp ("recv", argv[0], strlen (argv[0])) == 0)
+ zebra_debug_packet &= ~ZEBRA_DEBUG_RECV;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_zebra_kernel,
+ no_debug_zebra_kernel_cmd,
+ "no debug zebra kernel",
+ NO_STR
+ DEBUG_STR
+ "Zebra configuration\n"
+ "Debug option set for zebra between kernel interface\n")
+{
+ zebra_debug_kernel = 0;
+ return CMD_SUCCESS;
+}
+
+/* Debug node. */
+struct cmd_node debug_node =
+{
+ DEBUG_NODE,
+ "", /* Debug node has no interface. */
+ 1
+};
+
+int
+config_write_debug (struct vty *vty)
+{
+ int write = 0;
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ {
+ vty_out (vty, "debug zebra events%s", VTY_NEWLINE);
+ write++;
+ }
+ if (IS_ZEBRA_DEBUG_PACKET)
+ {
+ if (IS_ZEBRA_DEBUG_SEND && IS_ZEBRA_DEBUG_RECV)
+ {
+ vty_out (vty, "debug zebra packet%s%s",
+ IS_ZEBRA_DEBUG_DETAIL ? " detail" : "",
+ VTY_NEWLINE);
+ write++;
+ }
+ else
+ {
+ if (IS_ZEBRA_DEBUG_SEND)
+ vty_out (vty, "debug zebra packet send%s%s",
+ IS_ZEBRA_DEBUG_DETAIL ? " detail" : "",
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "debug zebra packet recv%s%s",
+ IS_ZEBRA_DEBUG_DETAIL ? " detail" : "",
+ VTY_NEWLINE);
+ write++;
+ }
+ }
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ {
+ vty_out (vty, "debug zebra kernel%s", VTY_NEWLINE);
+ write++;
+ }
+ return write;
+}
+
+void
+zebra_debug_init ()
+{
+ zebra_debug_event = 0;
+ zebra_debug_packet = 0;
+
+ install_node (&debug_node, config_write_debug);
+
+ install_element (VIEW_NODE, &show_debugging_zebra_cmd);
+
+ install_element (ENABLE_NODE, &show_debugging_zebra_cmd);
+ install_element (ENABLE_NODE, &debug_zebra_events_cmd);
+ install_element (ENABLE_NODE, &debug_zebra_packet_cmd);
+ install_element (ENABLE_NODE, &debug_zebra_packet_direct_cmd);
+ install_element (ENABLE_NODE, &debug_zebra_packet_detail_cmd);
+ install_element (ENABLE_NODE, &debug_zebra_kernel_cmd);
+ install_element (ENABLE_NODE, &no_debug_zebra_events_cmd);
+ install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd);
+ install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd);
+
+ install_element (CONFIG_NODE, &debug_zebra_events_cmd);
+ install_element (CONFIG_NODE, &debug_zebra_packet_cmd);
+ install_element (CONFIG_NODE, &debug_zebra_packet_direct_cmd);
+ install_element (CONFIG_NODE, &debug_zebra_packet_detail_cmd);
+ install_element (CONFIG_NODE, &debug_zebra_kernel_cmd);
+ install_element (CONFIG_NODE, &no_debug_zebra_events_cmd);
+ install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd);
+ install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd);
+}
diff --git a/zebra/debug.h b/zebra/debug.h
new file mode 100644
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 <zebra.h>
+
+#include "if.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "ioctl.h"
+#include "connected.h"
+#include "memory.h"
+#include "log.h"
+
+#include "zebra/interface.h"
+
+/* Interface looking up using infamous SIOCGIFCONF. */
+int
+interface_list_ioctl ()
+{
+ int ret;
+ int sock;
+#define IFNUM_BASE 32
+ int ifnum;
+ struct ifreq *ifreq;
+ struct ifconf ifconf;
+ struct interface *ifp;
+ int n;
+ int lastlen;
+
+ /* Normally SIOCGIFCONF works with AF_INET socket. */
+ sock = socket (AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ {
+ zlog_warn ("Can't make AF_INET socket stream: %s", strerror (errno));
+ return -1;
+ }
+
+ /* Set initial ifreq count. This will be double when SIOCGIFCONF
+ fail. Solaris has SIOCGIFNUM. */
+#ifdef SIOCGIFNUM
+ ret = ioctl (sock, SIOCGIFNUM, &ifnum);
+ if (ret < 0)
+ ifnum = IFNUM_BASE;
+ else
+ ifnum++;
+#else
+ ifnum = IFNUM_BASE;
+#endif /* SIOCGIFNUM */
+
+ ifconf.ifc_buf = NULL;
+
+ lastlen = 0;
+ /* Loop until SIOCGIFCONF success. */
+ for (;;)
+ {
+ ifconf.ifc_len = sizeof (struct ifreq) * ifnum;
+ ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len);
+
+ ret = ioctl(sock, SIOCGIFCONF, &ifconf);
+
+ if (ret < 0)
+ {
+ zlog_warn ("SIOCGIFCONF: %s", strerror(errno));
+ goto end;
+ }
+ /* Repeatedly get info til buffer fails to grow. */
+ if (ifconf.ifc_len > lastlen)
+ {
+ lastlen = ifconf.ifc_len;
+ ifnum += 10;
+ continue;
+ }
+ /* Success. */
+ break;
+ }
+
+ /* Allocate interface. */
+ ifreq = ifconf.ifc_req;
+
+#ifdef OPEN_BSD
+ for (n = 0; n < ifconf.ifc_len; )
+ {
+ int size;
+
+ ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n);
+ ifp = if_get_by_name (ifreq->ifr_name);
+ if_add_update (ifp);
+ size = ifreq->ifr_addr.sa_len;
+ if (size < sizeof (ifreq->ifr_addr))
+ size = sizeof (ifreq->ifr_addr);
+ size += sizeof (ifreq->ifr_name);
+ n += size;
+ }
+#else
+ for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq))
+ {
+ ifp = if_get_by_name (ifreq->ifr_name);
+ if_add_update (ifp);
+ ifreq++;
+ }
+#endif /* OPEN_BSD */
+
+ end:
+ close (sock);
+ XFREE (MTYPE_TMP, ifconf.ifc_buf);
+
+ return ret;
+}
+
+/* Get interface's index by ioctl. */
+int
+if_get_index (struct interface *ifp)
+{
+ static int if_fake_index = 1;
+
+#ifdef HAVE_BROKEN_ALIASES
+ /* Linux 2.2.X does not provide individual interface index for aliases. */
+ ifp->ifindex = if_fake_index++;
+ return ifp->ifindex;
+#else
+#ifdef SIOCGIFINDEX
+ int ret;
+ struct ifreq ifreq;
+
+ ifreq_set_name (&ifreq, ifp);
+
+ ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq);
+ if (ret < 0)
+ {
+ /* Linux 2.0.X does not have interface index. */
+ ifp->ifindex = if_fake_index++;
+ return ifp->ifindex;
+ }
+
+ /* OK we got interface index. */
+#ifdef ifr_ifindex
+ ifp->ifindex = ifreq.ifr_ifindex;
+#else
+ ifp->ifindex = ifreq.ifr_index;
+#endif
+ return ifp->ifindex;
+
+#else
+ ifp->ifindex = if_fake_index++;
+ return ifp->ifindex;
+#endif /* SIOCGIFINDEX */
+#endif /* HAVE_BROKEN_ALIASES */
+}
+
+#ifdef SIOCGIFHWADDR
+int
+if_get_hwaddr (struct interface *ifp)
+{
+ int ret;
+ struct ifreq ifreq;
+ int i;
+
+ strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
+ ifreq.ifr_addr.sa_family = AF_INET;
+
+ /* Fetch Hardware address if available. */
+ ret = if_ioctl (SIOCGIFHWADDR, (caddr_t) &ifreq);
+ if (ret < 0)
+ ifp->hw_addr_len = 0;
+ else
+ {
+ memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6);
+
+ for (i = 0; i < 6; i++)
+ if (ifp->hw_addr[i] != 0)
+ break;
+
+ if (i == 6)
+ ifp->hw_addr_len = 0;
+ else
+ ifp->hw_addr_len = 6;
+ }
+ return 0;
+}
+#endif /* SIOCGIFHWADDR */
+
+#ifdef HAVE_GETIFADDRS
+#include <ifaddrs.h>
+
+int
+if_getaddrs ()
+{
+ int ret;
+ struct ifaddrs *ifap;
+ struct ifaddrs *ifapfree;
+ struct interface *ifp;
+ int prefixlen;
+
+ ret = getifaddrs (&ifap);
+ if (ret != 0)
+ {
+ zlog_err ("getifaddrs(): %s", strerror (errno));
+ return -1;
+ }
+
+ for (ifapfree = ifap; ifap; ifap = ifap->ifa_next)
+ {
+ ifp = if_lookup_by_name (ifap->ifa_name);
+ if (ifp == NULL)
+ {
+ zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
+ ifap->ifa_name);
+ continue;
+ }
+
+ if (ifap->ifa_addr->sa_family == AF_INET)
+ {
+ struct sockaddr_in *addr;
+ struct sockaddr_in *mask;
+ struct sockaddr_in *dest;
+ struct in_addr *dest_pnt;
+
+ addr = (struct sockaddr_in *) ifap->ifa_addr;
+ mask = (struct sockaddr_in *) ifap->ifa_netmask;
+ prefixlen = ip_masklen (mask->sin_addr);
+
+ dest_pnt = NULL;
+
+ if (ifap->ifa_flags & IFF_POINTOPOINT)
+ {
+ dest = (struct sockaddr_in *) ifap->ifa_dstaddr;
+ dest_pnt = &dest->sin_addr;
+ }
+
+ if (ifap->ifa_flags & IFF_BROADCAST)
+ {
+ dest = (struct sockaddr_in *) ifap->ifa_broadaddr;
+ dest_pnt = &dest->sin_addr;
+ }
+
+ connected_add_ipv4 (ifp, 0, &addr->sin_addr,
+ prefixlen, dest_pnt, NULL);
+ }
+#ifdef HAVE_IPV6
+ if (ifap->ifa_addr->sa_family == AF_INET6)
+ {
+ struct sockaddr_in6 *addr;
+ struct sockaddr_in6 *mask;
+ struct sockaddr_in6 *dest;
+ struct in6_addr *dest_pnt;
+
+ addr = (struct sockaddr_in6 *) ifap->ifa_addr;
+ mask = (struct sockaddr_in6 *) ifap->ifa_netmask;
+ prefixlen = ip6_masklen (mask->sin6_addr);
+
+ dest_pnt = NULL;
+
+ if (ifap->ifa_flags & IFF_POINTOPOINT)
+ {
+ if (ifap->ifa_dstaddr)
+ {
+ dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr;
+ dest_pnt = &dest->sin6_addr;
+ }
+ }
+
+ if (ifap->ifa_flags & IFF_BROADCAST)
+ {
+ if (ifap->ifa_broadaddr)
+ {
+ dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr;
+ dest_pnt = &dest->sin6_addr;
+ }
+ }
+
+ connected_add_ipv6 (ifp, &addr->sin6_addr, prefixlen, dest_pnt);
+ }
+#endif /* HAVE_IPV6 */
+ }
+
+ freeifaddrs (ifapfree);
+
+ return 0;
+}
+#else /* HAVE_GETIFADDRS */
+/* Interface address lookup by ioctl. This function only looks up
+ IPv4 address. */
+int
+if_get_addr (struct interface *ifp)
+{
+ int ret;
+ struct ifreq ifreq;
+ struct sockaddr_in addr;
+ struct sockaddr_in mask;
+ struct sockaddr_in dest;
+ struct in_addr *dest_pnt;
+ u_char prefixlen;
+
+ /* Interface's name and address family. */
+ strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
+ ifreq.ifr_addr.sa_family = AF_INET;
+
+ /* Interface's address. */
+ ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq);
+ if (ret < 0)
+ {
+ if (errno != EADDRNOTAVAIL)
+ {
+ zlog_warn ("SIOCGIFADDR fail: %s", strerror (errno));
+ return ret;
+ }
+ return 0;
+ }
+ memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
+
+ /* Interface's network mask. */
+ ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq);
+ if (ret < 0)
+ {
+ if (errno != EADDRNOTAVAIL)
+ {
+ zlog_warn ("SIOCGIFNETMASK fail: %s", strerror (errno));
+ return ret;
+ }
+ return 0;
+ }
+#ifdef ifr_netmask
+ memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in));
+#else
+ memcpy (&mask, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
+#endif /* ifr_netmask */
+ prefixlen = ip_masklen (mask.sin_addr);
+
+ /* Point to point or borad cast address pointer init. */
+ dest_pnt = NULL;
+
+ if (ifp->flags & IFF_POINTOPOINT)
+ {
+ ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq);
+ if (ret < 0)
+ {
+ if (errno != EADDRNOTAVAIL)
+ {
+ zlog_warn ("SIOCGIFDSTADDR fail: %s", strerror (errno));
+ return ret;
+ }
+ return 0;
+ }
+ memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in));
+ dest_pnt = &dest.sin_addr;
+ }
+ if (ifp->flags & IFF_BROADCAST)
+ {
+ ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq);
+ if (ret < 0)
+ {
+ if (errno != EADDRNOTAVAIL)
+ {
+ zlog_warn ("SIOCGIFBRDADDR fail: %s", strerror (errno));
+ return ret;
+ }
+ return 0;
+ }
+ memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in));
+ dest_pnt = &dest.sin_addr;
+ }
+
+
+ /* Set address to the interface. */
+ connected_add_ipv4 (ifp, 0, &addr.sin_addr, prefixlen, dest_pnt, NULL);
+
+ return 0;
+}
+#endif /* HAVE_GETIFADDRS */
+
+/* Fetch interface information via ioctl(). */
+static void
+interface_info_ioctl ()
+{
+ listnode node;
+ struct interface *ifp;
+
+ for (node = listhead (iflist); node; node = nextnode (node))
+ {
+ ifp = getdata (node);
+
+ if_get_index (ifp);
+#ifdef SIOCGIFHWADDR
+ if_get_hwaddr (ifp);
+#endif /* SIOCGIFHWADDR */
+ if_get_flags (ifp);
+#ifndef HAVE_GETIFADDRS
+ if_get_addr (ifp);
+#endif /* ! HAVE_GETIFADDRS */
+ if_get_mtu (ifp);
+ if_get_metric (ifp);
+ }
+}
+
+/* Lookup all interface information. */
+void
+interface_list ()
+{
+ /* Linux can do both proc & ioctl, ioctl is the only way to get
+ interface aliases in 2.2 series kernels. */
+#ifdef HAVE_PROC_NET_DEV
+ interface_list_proc ();
+#endif /* HAVE_PROC_NET_DEV */
+ interface_list_ioctl ();
+
+ /* After listing is done, get index, address, flags and other
+ interface's information. */
+ interface_info_ioctl ();
+
+#ifdef HAVE_GETIFADDRS
+ if_getaddrs ();
+#endif /* HAVE_GETIFADDRS */
+
+#if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
+ /* Linux provides interface's IPv6 address via
+ /proc/net/if_inet6. */
+ ifaddr_proc_ipv6 ();
+#endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */
+}
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
new file mode 100644
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 <zebra.h>
+
+/* Extern from rt_netlink.c */
+void interface_lookup_netlink ();
+
+/* Interface information read by netlink. */
+void
+interface_list ()
+{
+ interface_lookup_netlink ();
+}
diff --git a/zebra/if_proc.c b/zebra/if_proc.c
new file mode 100644
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 <zebra.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "log.h"
+
+#include "zebra/ioctl.h"
+#include "zebra/connected.h"
+#include "zebra/interface.h"
+
+/* Proc filesystem one line buffer. */
+#define PROCBUFSIZ 1024
+
+/* Path to device proc file system. */
+#ifndef _PATH_PROC_NET_DEV
+#define _PATH_PROC_NET_DEV "/proc/net/dev"
+#endif /* _PATH_PROC_NET_DEV */
+
+/* Return statistics data pointer. */
+static char *
+interface_name_cut (char *buf, char **name)
+{
+ char *stat;
+
+ /* Skip white space. Line will include header spaces. */
+ while (*buf == ' ')
+ buf++;
+ *name = buf;
+
+ /* Cut interface name. */
+ stat = strrchr (buf, ':');
+ *stat++ = '\0';
+
+ return stat;
+}
+
+/* Fetch each statistics field. */
+static int
+ifstat_dev_fields (int version, char *buf, struct interface *ifp)
+{
+ switch (version)
+ {
+ case 3:
+ sscanf(buf,
+ "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
+ &ifp->stats.rx_bytes,
+ &ifp->stats.rx_packets,
+ &ifp->stats.rx_errors,
+ &ifp->stats.rx_dropped,
+ &ifp->stats.rx_fifo_errors,
+ &ifp->stats.rx_frame_errors,
+ &ifp->stats.rx_compressed,
+ &ifp->stats.rx_multicast,
+
+ &ifp->stats.tx_bytes,
+ &ifp->stats.tx_packets,
+ &ifp->stats.tx_errors,
+ &ifp->stats.tx_dropped,
+ &ifp->stats.tx_fifo_errors,
+ &ifp->stats.collisions,
+ &ifp->stats.tx_carrier_errors,
+ &ifp->stats.tx_compressed);
+ break;
+ case 2:
+ sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
+ &ifp->stats.rx_bytes,
+ &ifp->stats.rx_packets,
+ &ifp->stats.rx_errors,
+ &ifp->stats.rx_dropped,
+ &ifp->stats.rx_fifo_errors,
+ &ifp->stats.rx_frame_errors,
+
+ &ifp->stats.tx_bytes,
+ &ifp->stats.tx_packets,
+ &ifp->stats.tx_errors,
+ &ifp->stats.tx_dropped,
+ &ifp->stats.tx_fifo_errors,
+ &ifp->stats.collisions,
+ &ifp->stats.tx_carrier_errors);
+ ifp->stats.rx_multicast = 0;
+ break;
+ case 1:
+ sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
+ &ifp->stats.rx_packets,
+ &ifp->stats.rx_errors,
+ &ifp->stats.rx_dropped,
+ &ifp->stats.rx_fifo_errors,
+ &ifp->stats.rx_frame_errors,
+
+ &ifp->stats.tx_packets,
+ &ifp->stats.tx_errors,
+ &ifp->stats.tx_dropped,
+ &ifp->stats.tx_fifo_errors,
+ &ifp->stats.collisions,
+ &ifp->stats.tx_carrier_errors);
+ ifp->stats.rx_bytes = 0;
+ ifp->stats.tx_bytes = 0;
+ ifp->stats.rx_multicast = 0;
+ break;
+ }
+ return 0;
+}
+
+/* Update interface's statistics. */
+int
+ifstat_update_proc ()
+{
+ FILE *fp;
+ char buf[PROCBUFSIZ];
+ int version;
+ struct interface *ifp;
+ char *stat;
+ char *name;
+
+ /* Open /proc/net/dev. */
+ fp = fopen (_PATH_PROC_NET_DEV, "r");
+ if (fp == NULL)
+ {
+ zlog_warn ("Can't open proc file %s: %s",
+ _PATH_PROC_NET_DEV, strerror (errno));
+ return -1;
+ }
+
+ /* Drop header lines. */
+ fgets (buf, PROCBUFSIZ, fp);
+ fgets (buf, PROCBUFSIZ, fp);
+
+ /* To detect proc format veresion, parse second line. */
+ if (strstr (buf, "compressed"))
+ version = 3;
+ else if (strstr (buf, "bytes"))
+ version = 2;
+ else
+ version = 1;
+
+ /* Update each interface's statistics. */
+ while (fgets (buf, PROCBUFSIZ, fp) != NULL)
+ {
+ stat = interface_name_cut (buf, &name);
+ ifp = if_get_by_name (name);
+ ifstat_dev_fields (version, stat, ifp);
+ }
+
+ return 0;
+}
+
+/* Interface structure allocation by proc filesystem. */
+int
+interface_list_proc ()
+{
+ FILE *fp;
+ char buf[PROCBUFSIZ];
+ struct interface *ifp;
+ char *name;
+
+ /* Open /proc/net/dev. */
+ fp = fopen (_PATH_PROC_NET_DEV, "r");
+ if (fp == NULL)
+ {
+ zlog_warn ("Can't open proc file %s: %s",
+ _PATH_PROC_NET_DEV, strerror (errno));
+ return -1;
+ }
+
+ /* Drop header lines. */
+ fgets (buf, PROCBUFSIZ, fp);
+ fgets (buf, PROCBUFSIZ, fp);
+
+ /* Only allocate interface structure. Other jobs will be done in
+ if_ioctl.c. */
+ while (fgets (buf, PROCBUFSIZ, fp) != NULL)
+ {
+ interface_name_cut (buf, &name);
+ ifp = if_get_by_name (name);
+ if_add_update (ifp);
+ }
+ return 0;
+}
+
+#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 <zebra.h>
+
+#include "if.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "connected.h"
+#include "memory.h"
+#include "ioctl.h"
+#include "log.h"
+
+int
+ifstat_update_sysctl ()
+{
+ caddr_t ref, buf, end;
+ size_t bufsiz;
+ struct if_msghdr *ifm;
+ struct interface *ifp;
+
+#define MIBSIZ 6
+ int mib[MIBSIZ] =
+ {
+ CTL_NET,
+ PF_ROUTE,
+ 0,
+ 0, /* AF_INET & AF_INET6 */
+ NET_RT_IFLIST,
+ 0
+ };
+
+ /* Query buffer size. */
+ if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0)
+ {
+ zlog_warn ("sysctl() error by %s", strerror (errno));
+ return -1;
+ }
+
+ /* We free this memory at the end of this function. */
+ ref = buf = XMALLOC (MTYPE_TMP, bufsiz);
+
+ /* Fetch interface informations into allocated buffer. */
+ if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0)
+ {
+ zlog (NULL, LOG_WARNING, "sysctl error by %s", strerror (errno));
+ return -1;
+ }
+
+ /* Parse both interfaces and addresses. */
+ for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen)
+ {
+ ifm = (struct if_msghdr *) buf;
+ if (ifm->ifm_type == RTM_IFINFO)
+ {
+ ifp = if_lookup_by_index (ifm->ifm_index);
+ if (ifp)
+ ifp->stats = ifm->ifm_data;
+ }
+ }
+
+ /* Free sysctl buffer. */
+ XFREE (MTYPE_TMP, ref);
+
+ return 0;
+}
+
+/* Interface listing up function using sysctl(). */
+void
+interface_list ()
+{
+ caddr_t ref, buf, end;
+ size_t bufsiz;
+ struct if_msghdr *ifm;
+ int ifm_read (struct if_msghdr *);
+ int ifam_read (struct ifa_msghdr *);
+
+#define MIBSIZ 6
+ int mib[MIBSIZ] =
+ {
+ CTL_NET,
+ PF_ROUTE,
+ 0,
+ 0, /* AF_INET & AF_INET6 */
+ NET_RT_IFLIST,
+ 0
+ };
+
+ /* Query buffer size. */
+ if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0)
+ {
+ zlog (NULL, LOG_WARNING, "sysctl() error by %s", strerror (errno));
+ return;
+ }
+
+ /* We free this memory at the end of this function. */
+ ref = buf = XMALLOC (MTYPE_TMP, bufsiz);
+
+ /* Fetch interface informations into allocated buffer. */
+ if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0)
+ {
+ zlog (NULL, LOG_WARNING, "sysctl error by %s", strerror (errno));
+ return;
+ }
+
+ /* Parse both interfaces and addresses. */
+ for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen)
+ {
+ ifm = (struct if_msghdr *) buf;
+
+ switch (ifm->ifm_type)
+ {
+ case RTM_IFINFO:
+ ifm_read (ifm);
+ break;
+ case RTM_NEWADDR:
+ ifam_read ((struct ifa_msghdr *) ifm);
+ break;
+ default:
+ zlog_info ("interfaces_list(): unexpected message type");
+ XFREE (MTYPE_TMP, ref);
+ return;
+ break;
+ }
+ }
+
+ /* Free sysctl buffer. */
+ XFREE (MTYPE_TMP, ref);
+}
diff --git a/zebra/interface.c b/zebra/interface.c
new file mode 100644
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 <zebra.h>
+
+#include "if.h"
+#include "vty.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "command.h"
+#include "memory.h"
+#include "ioctl.h"
+#include "connected.h"
+#include "log.h"
+#include "zclient.h"
+
+#include "zebra/interface.h"
+#include "zebra/rtadv.h"
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/debug.h"
+
+/* 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 <zebra.h>
+
+#include "linklist.h"
+#include "if.h"
+#include "prefix.h"
+#include "ioctl.h"
+#include "log.h"
+
+#include "zebra/rib.h"
+#include "zebra/rt.h"
+
+/* clear and set interface name string */
+void
+ifreq_set_name (struct ifreq *ifreq, struct interface *ifp)
+{
+ strncpy (ifreq->ifr_name, ifp->name, IFNAMSIZ);
+}
+
+/* call ioctl system call */
+int
+if_ioctl (u_long request, caddr_t buffer)
+{
+ int sock;
+ int ret = 0;
+ int err = 0;
+
+ sock = socket (AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ {
+ perror ("socket");
+ exit (1);
+ }
+
+ ret = ioctl (sock, request, buffer);
+ if (ret < 0)
+ {
+ err = errno;
+ }
+ close (sock);
+
+ if (ret < 0)
+ {
+ errno = err;
+ return ret;
+ }
+ return 0;
+}
+
+#ifdef HAVE_IPV6
+int
+if_ioctl_ipv6 (u_long request, caddr_t buffer)
+{
+ int sock;
+ int ret = 0;
+ int err = 0;
+
+ sock = socket (AF_INET6, SOCK_DGRAM, 0);
+ if (sock < 0)
+ {
+ perror ("socket");
+ exit (1);
+ }
+
+ ret = ioctl (sock, request, buffer);
+ if (ret < 0)
+ {
+ err = errno;
+ }
+ close (sock);
+
+ if (ret < 0)
+ {
+ errno = err;
+ return ret;
+ }
+ return 0;
+}
+#endif /* HAVE_IPV6 */
+
+/*
+ * get interface metric
+ * -- if value is not avaliable set -1
+ */
+void
+if_get_metric (struct interface *ifp)
+{
+#ifdef SIOCGIFMETRIC
+ struct ifreq ifreq;
+
+ ifreq_set_name (&ifreq, ifp);
+
+ if (if_ioctl (SIOCGIFMETRIC, (caddr_t) &ifreq) < 0)
+ return;
+ ifp->metric = ifreq.ifr_metric;
+ if (ifp->metric == 0)
+ ifp->metric = 1;
+#else /* SIOCGIFMETRIC */
+ ifp->metric = -1;
+#endif /* SIOCGIFMETRIC */
+}
+
+/* get interface MTU */
+void
+if_get_mtu (struct interface *ifp)
+{
+ struct ifreq ifreq;
+
+ ifreq_set_name (&ifreq, ifp);
+
+#if defined(SIOCGIFMTU)
+ if (if_ioctl (SIOCGIFMTU, (caddr_t) & ifreq) < 0)
+ {
+ zlog_info ("Can't lookup mtu by ioctl(SIOCGIFMTU)");
+ ifp->mtu = -1;
+ return;
+ }
+
+#ifdef SUNOS_5
+ ifp->mtu = ifreq.ifr_metric;
+#else
+ ifp->mtu = ifreq.ifr_mtu;
+#endif /* SUNOS_5 */
+
+#else
+ zlog (NULL, LOG_INFO, "Can't lookup mtu on this system");
+ ifp->mtu = -1;
+#endif
+}
+
+#ifdef HAVE_NETLINK
+/* Interface address setting via netlink interface. */
+int
+if_set_prefix (struct interface *ifp, struct connected *ifc)
+{
+ return kernel_address_add_ipv4 (ifp, ifc);
+}
+
+/* Interface address is removed using netlink interface. */
+int
+if_unset_prefix (struct interface *ifp, struct connected *ifc)
+{
+ return kernel_address_delete_ipv4 (ifp, ifc);
+}
+#else /* ! HAVE_NETLINK */
+#ifdef HAVE_IFALIASREQ
+/* Set up interface's IP address, netmask (and broadcas? ). *BSD may
+ has ifaliasreq structure. */
+int
+if_set_prefix (struct interface *ifp, struct connected *ifc)
+{
+ int ret;
+ struct ifaliasreq addreq;
+ struct sockaddr_in addr;
+ struct sockaddr_in mask;
+ struct prefix_ipv4 *p;
+
+ p = (struct prefix_ipv4 *) ifc->address;
+
+ memset (&addreq, 0, sizeof addreq);
+ strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
+
+ memset (&addr, 0, sizeof (struct sockaddr_in));
+ addr.sin_addr = p->prefix;
+ addr.sin_family = p->family;
+#ifdef HAVE_SIN_LEN
+ addr.sin_len = sizeof (struct sockaddr_in);
+#endif
+ memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in));
+
+ memset (&mask, 0, sizeof (struct sockaddr_in));
+ masklen2ip (p->prefixlen, &mask.sin_addr);
+ mask.sin_family = p->family;
+#ifdef HAVE_SIN_LEN
+ mask.sin_len = sizeof (struct sockaddr_in);
+#endif
+ memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in));
+
+ ret = if_ioctl (SIOCAIFADDR, (caddr_t) &addreq);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+/* Set up interface's IP address, netmask (and broadcas? ). *BSD may
+ has ifaliasreq structure. */
+int
+if_unset_prefix (struct interface *ifp, struct connected *ifc)
+{
+ int ret;
+ struct ifaliasreq addreq;
+ struct sockaddr_in addr;
+ struct sockaddr_in mask;
+ struct prefix_ipv4 *p;
+
+ p = (struct prefix_ipv4 *)ifc->address;
+
+ memset (&addreq, 0, sizeof addreq);
+ strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
+
+ memset (&addr, 0, sizeof (struct sockaddr_in));
+ addr.sin_addr = p->prefix;
+ addr.sin_family = p->family;
+#ifdef HAVE_SIN_LEN
+ addr.sin_len = sizeof (struct sockaddr_in);
+#endif
+ memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in));
+
+ memset (&mask, 0, sizeof (struct sockaddr_in));
+ masklen2ip (p->prefixlen, &mask.sin_addr);
+ mask.sin_family = p->family;
+#ifdef HAVE_SIN_LEN
+ mask.sin_len = sizeof (struct sockaddr_in);
+#endif
+ memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in));
+
+ ret = if_ioctl (SIOCDIFADDR, (caddr_t) &addreq);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+#else
+/* Set up interface's address, netmask (and broadcas? ). Linux or
+ Solaris uses ifname:number semantics to set IP address aliases. */
+int
+if_set_prefix (struct interface *ifp, struct connected *ifc)
+{
+ int ret;
+ struct ifreq ifreq;
+ struct sockaddr_in addr;
+ struct sockaddr_in broad;
+ struct sockaddr_in mask;
+ struct prefix_ipv4 ifaddr;
+ struct prefix_ipv4 *p;
+
+ p = (struct prefix_ipv4 *) ifc->address;
+
+ ifaddr = *p;
+
+ ifreq_set_name (&ifreq, ifp);
+
+ addr.sin_addr = p->prefix;
+ addr.sin_family = p->family;
+ memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in));
+ ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq);
+ if (ret < 0)
+ return ret;
+
+ /* We need mask for make broadcast addr. */
+ masklen2ip (p->prefixlen, &mask.sin_addr);
+
+ if (if_is_broadcast (ifp))
+ {
+ apply_mask_ipv4 (&ifaddr);
+ addr.sin_addr = ifaddr.prefix;
+
+ broad.sin_addr.s_addr = (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr);
+ broad.sin_family = p->family;
+
+ memcpy (&ifreq.ifr_broadaddr, &broad, sizeof (struct sockaddr_in));
+ ret = if_ioctl (SIOCSIFBRDADDR, (caddr_t) &ifreq);
+ if (ret < 0)
+ return ret;
+ }
+
+ mask.sin_family = p->family;
+#ifdef SUNOS_5
+ memcpy (&mask, &ifreq.ifr_addr, sizeof (mask));
+#else
+ memcpy (&ifreq.ifr_netmask, &mask, sizeof (struct sockaddr_in));
+#endif /* SUNOS5 */
+ ret = if_ioctl (SIOCSIFNETMASK, (caddr_t) &ifreq);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/* Set up interface's address, netmask (and broadcas? ). Linux or
+ Solaris uses ifname:number semantics to set IP address aliases. */
+int
+if_unset_prefix (struct interface *ifp, struct connected *ifc)
+{
+ int ret;
+ struct ifreq ifreq;
+ struct sockaddr_in addr;
+ struct prefix_ipv4 *p;
+
+ p = (struct prefix_ipv4 *) ifc->address;
+
+ ifreq_set_name (&ifreq, ifp);
+
+ memset (&addr, 0, sizeof (struct sockaddr_in));
+ addr.sin_family = p->family;
+ memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in));
+ ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+#endif /* HAVE_IFALIASREQ */
+#endif /* HAVE_NETLINK */
+
+/* get interface flags */
+void
+if_get_flags (struct interface *ifp)
+{
+ int ret;
+ struct ifreq ifreq;
+
+ ifreq_set_name (&ifreq, ifp);
+
+ ret = if_ioctl (SIOCGIFFLAGS, (caddr_t) &ifreq);
+ if (ret < 0)
+ {
+ perror ("ioctl");
+ return;
+ }
+
+ ifp->flags = ifreq.ifr_flags & 0x0000ffff;
+}
+
+/* Set interface flags */
+int
+if_set_flags (struct interface *ifp, unsigned long flags)
+{
+ int ret;
+ struct ifreq ifreq;
+
+ ifreq_set_name (&ifreq, ifp);
+
+ ifreq.ifr_flags = ifp->flags;
+ ifreq.ifr_flags |= flags;
+
+ ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq);
+
+ if (ret < 0)
+ {
+ zlog_info ("can't set interface flags");
+ return ret;
+ }
+ return 0;
+}
+
+/* Unset interface's flag. */
+int
+if_unset_flags (struct interface *ifp, unsigned long flags)
+{
+ int ret;
+ struct ifreq ifreq;
+
+ ifreq_set_name (&ifreq, ifp);
+
+ ifreq.ifr_flags = ifp->flags;
+ ifreq.ifr_flags &= ~flags;
+
+ ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq);
+
+ if (ret < 0)
+ {
+ zlog_info ("can't unset interface flags");
+ return ret;
+ }
+ return 0;
+}
+
+#ifdef HAVE_IPV6
+
+#ifdef LINUX_IPV6
+#ifndef _LINUX_IN6_H
+/* linux/include/net/ipv6.h */
+struct in6_ifreq
+{
+ struct in6_addr ifr6_addr;
+ u_int32_t ifr6_prefixlen;
+ int ifr6_ifindex;
+};
+#endif /* _LINUX_IN6_H */
+
+/* Interface's address add/delete functions. */
+int
+if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+ int ret;
+ struct prefix_ipv6 *p;
+ struct in6_ifreq ifreq;
+
+ p = (struct prefix_ipv6 *) ifc->address;
+
+ memset (&ifreq, 0, sizeof (struct in6_ifreq));
+
+ memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr));
+ ifreq.ifr6_ifindex = ifp->ifindex;
+ ifreq.ifr6_prefixlen = p->prefixlen;
+
+ ret = if_ioctl_ipv6 (SIOCSIFADDR, (caddr_t) &ifreq);
+
+ return ret;
+}
+
+int
+if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+ int ret;
+ struct prefix_ipv6 *p;
+ struct in6_ifreq ifreq;
+
+ p = (struct prefix_ipv6 *) ifc->address;
+
+ memset (&ifreq, 0, sizeof (struct in6_ifreq));
+
+ memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr));
+ ifreq.ifr6_ifindex = ifp->ifindex;
+ ifreq.ifr6_prefixlen = p->prefixlen;
+
+ ret = if_ioctl_ipv6 (SIOCDIFADDR, (caddr_t) &ifreq);
+
+ return ret;
+}
+#else /* LINUX_IPV6 */
+#ifdef HAVE_IN6_ALIASREQ
+#ifndef ND6_INFINITE_LIFETIME
+#define ND6_INFINITE_LIFETIME 0xffffffffL
+#endif /* ND6_INFINITE_LIFETIME */
+int
+if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+ int ret;
+ struct in6_aliasreq addreq;
+ struct sockaddr_in6 addr;
+ struct sockaddr_in6 mask;
+ struct prefix_ipv6 *p;
+
+ p = (struct prefix_ipv6 * ) ifc->address;
+
+ memset (&addreq, 0, sizeof addreq);
+ strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
+
+ memset (&addr, 0, sizeof (struct sockaddr_in6));
+ addr.sin6_addr = p->prefix;
+ addr.sin6_family = p->family;
+#ifdef HAVE_SIN_LEN
+ addr.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+ memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6));
+
+ memset (&mask, 0, sizeof (struct sockaddr_in6));
+ masklen2ip6 (p->prefixlen, &mask.sin6_addr);
+ mask.sin6_family = p->family;
+#ifdef HAVE_SIN_LEN
+ mask.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+ memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6));
+
+ addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
+ addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
+
+ ret = if_ioctl_ipv6 (SIOCAIFADDR_IN6, (caddr_t) &addreq);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+int
+if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+ int ret;
+ struct in6_aliasreq addreq;
+ struct sockaddr_in6 addr;
+ struct sockaddr_in6 mask;
+ struct prefix_ipv6 *p;
+
+ p = (struct prefix_ipv6 *) ifc->address;
+
+ memset (&addreq, 0, sizeof addreq);
+ strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
+
+ memset (&addr, 0, sizeof (struct sockaddr_in6));
+ addr.sin6_addr = p->prefix;
+ addr.sin6_family = p->family;
+#ifdef HAVE_SIN_LEN
+ addr.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+ memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6));
+
+ memset (&mask, 0, sizeof (struct sockaddr_in6));
+ masklen2ip6 (p->prefixlen, &mask.sin6_addr);
+ mask.sin6_family = p->family;
+#ifdef HAVE_SIN_LEN
+ mask.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+ memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6));
+
+ addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
+ addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
+
+ ret = if_ioctl_ipv6 (SIOCDIFADDR_IN6, (caddr_t) &addreq);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+#else
+int
+if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+ return 0;
+}
+
+int
+if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+ return 0;
+}
+#endif /* HAVE_IN6_ALIASREQ */
+
+#endif /* LINUX_IPV6 */
+
+#endif /* HAVE_IPV6 */
diff --git a/zebra/ioctl.h b/zebra/ioctl.h
new file mode 100644
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 <zebra.h>
+
+int
+ipforward ()
+{
+ int fd, ret;
+ int af = AF_INET;
+ char netopt[] = "ipforwarding";
+ struct optreq oq;
+
+ fd = socket(af, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ /* need logging here */
+ return -1;
+ }
+
+ strcpy (oq.name, netopt);
+ oq.getnext = 0;
+
+ ret = ioctl (fd, SIOCGNETOPT, (caddr_t)&oq);
+ close(fd);
+
+ if (ret < 0) {
+ /* need logging here */
+ return -1;
+ }
+
+ ret = atoi (oq.data);
+ return ret;
+}
+
+int
+ipforward_on ()
+{
+ ;
+}
+
+int
+ipforward_off ()
+{
+ ;
+}
diff --git a/zebra/ipforward_ews.c b/zebra/ipforward_ews.c
new file mode 100644
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 <zebra.h>
+
+int
+ipforward ()
+{
+ int fd;
+ char buf[BUFSIZ];
+ struct mioc_rksym rks;
+
+ fd = open ("/dev/kmem", O_RDWR);
+ if (fd < 0) {
+ /* need logging here */
+ return -1;
+ }
+
+ rks.mirk_symname = "ipforwarding";
+ rks.mirk_buf = buf;
+ rks.mirk_buflen = sizeof (int);
+
+ if (ioctl (fd, MIOC_READKSYM, &rks) < 0) {
+ /* need logging here */
+ return -1;
+ }
+ close (fd);
+ return *(int *)buf;
+}
+
+int
+ipforward_on ()
+{
+ ;
+}
+
+int
+ipforward_off ()
+{
+ ;
+}
diff --git a/zebra/ipforward_proc.c b/zebra/ipforward_proc.c
new file mode 100644
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 <zebra.h>
+
+char proc_net_snmp[] = "/proc/net/snmp";
+
+static void
+dropline (FILE *fp)
+{
+ int c;
+
+ while ((c = getc (fp)) != '\n')
+ ;
+}
+
+int
+ipforward ()
+{
+ FILE *fp;
+ int ipforwarding = 0;
+ char *pnt;
+ char buf[10];
+
+ fp = fopen (proc_net_snmp, "r");
+
+ if (fp == NULL)
+ return -1;
+
+ /* We don't care about the first line. */
+ dropline (fp);
+
+ /* Get ip_statistics.IpForwarding :
+ 1 => ip forwarding enabled
+ 2 => ip forwarding off. */
+ pnt = fgets (buf, 6, fp);
+ sscanf (buf, "Ip: %d", &ipforwarding);
+
+ if (ipforwarding == 1)
+ return 1;
+
+ return 0;
+}
+
+/* char proc_ipv4_forwarding[] = "/proc/sys/net/ipv4/conf/all/forwarding"; */
+char proc_ipv4_forwarding[] = "/proc/sys/net/ipv4/ip_forward";
+
+int
+ipforward_on ()
+{
+ FILE *fp;
+
+ fp = fopen (proc_ipv4_forwarding, "w");
+
+ if (fp == NULL)
+ return -1;
+
+ fprintf (fp, "1\n");
+
+ fclose (fp);
+
+ return ipforward ();
+}
+
+int
+ipforward_off ()
+{
+ FILE *fp;
+
+ fp = fopen (proc_ipv4_forwarding, "w");
+
+ if (fp == NULL)
+ return -1;
+
+ fprintf (fp, "0\n");
+
+ fclose (fp);
+
+ return ipforward ();
+}
+#ifdef HAVE_IPV6
+
+char proc_ipv6_forwarding[] = "/proc/sys/net/ipv6/conf/all/forwarding";
+
+int
+ipforward_ipv6 ()
+{
+ FILE *fp;
+ char buf[5];
+ int ipforwarding = 0;
+
+ fp = fopen (proc_ipv6_forwarding, "r");
+
+ if (fp == NULL)
+ return -1;
+
+ fgets (buf, 2, fp);
+ sscanf (buf, "%d", &ipforwarding);
+
+ return ipforwarding;
+}
+
+int
+ipforward_ipv6_on ()
+{
+ FILE *fp;
+
+ fp = fopen (proc_ipv6_forwarding, "w");
+
+ if (fp == NULL)
+ return -1;
+
+ fprintf (fp, "1\n");
+
+ fclose (fp);
+
+ return ipforward_ipv6 ();
+}
+
+int
+ipforward_ipv6_off ()
+{
+ FILE *fp;
+
+ fp = fopen (proc_ipv6_forwarding, "w");
+
+ if (fp == NULL)
+ return -1;
+
+ fprintf (fp, "0\n");
+
+ fclose (fp);
+
+ return ipforward_ipv6 ();
+}
+#endif /* HAVE_IPV6 */
diff --git a/zebra/ipforward_solaris.c b/zebra/ipforward_solaris.c
new file mode 100644
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 <zebra.h>
+
+#include "memory.h"
+
+int
+ipforward ()
+{
+ int fd, ret;
+ int ipforwarding = 0;
+ char forward[] = "ip_forwarding";
+ char *buf;
+ struct strioctl si;
+
+ buf = (char *) XMALLOC (MTYPE_TMP, sizeof forward + 1);
+ strcpy (buf, forward);
+
+ fd = open ("/dev/ip", O_RDWR);
+ if (fd < 0) {
+ free (buf);
+ /* need logging here */
+ /* "I can't get ipforwarding value because can't open /dev/ip" */
+ return -1;
+ }
+
+ si.ic_cmd = ND_GET;
+ si.ic_timout = 0;
+ si.ic_len = strlen (buf) + 1;
+ si.ic_dp = (caddr_t) buf;
+
+ ret = ioctl (fd, I_STR, &si);
+ close (fd);
+
+ if (ret < 0) {
+ free (buf);
+ /* need logging here */
+ /* can't get ipforwarding value : ioctl failed */
+ return -1;
+ }
+
+ ipforwarding = atoi (buf);
+ free (buf);
+ return ipforwarding;
+}
+
+int
+ipforward_on ()
+{
+ return 0;
+}
+
+int
+ipforward_off ()
+{
+ return 0;
+}
diff --git a/zebra/ipforward_sysctl.c b/zebra/ipforward_sysctl.c
new file mode 100644
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 <zebra.h>
+
+#ifdef NRL
+#include <netinet6/in6.h>
+#endif /* NRL */
+
+#include "log.h"
+
+#define MIB_SIZ 4
+
+/* IPv4 forwarding control MIB. */
+int mib[MIB_SIZ] =
+{
+ CTL_NET,
+ PF_INET,
+ IPPROTO_IP,
+ IPCTL_FORWARDING
+};
+
+int
+ipforward ()
+{
+ int len;
+ int ipforwarding = 0;
+
+ len = sizeof ipforwarding;
+ if (sysctl (mib, MIB_SIZ, &ipforwarding, &len, 0, 0) < 0)
+ {
+ zlog_warn ("Can't get ipforwarding value");
+ return -1;
+ }
+ return ipforwarding;
+}
+
+int
+ipforward_on ()
+{
+ int len;
+ int ipforwarding = 1;
+
+ len = sizeof ipforwarding;
+ if (sysctl (mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0)
+ {
+ zlog_warn ("Can't set ipforwarding on");
+ return -1;
+ }
+ return ipforwarding;
+}
+
+int
+ipforward_off ()
+{
+ int len;
+ int ipforwarding = 0;
+
+ len = sizeof ipforwarding;
+ if (sysctl (mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0)
+ {
+ zlog_warn ("Can't set ipforwarding on");
+ return -1;
+ }
+ return ipforwarding;
+}
+
+#ifdef HAVE_IPV6
+
+/* IPv6 forwarding control MIB. */
+int mib_ipv6[MIB_SIZ] =
+{
+ CTL_NET,
+ PF_INET6,
+#if defined(KAME) || (defined(__bsdi__) && _BSDI_VERSION >= 199802 ) || defined(NRL)
+ IPPROTO_IPV6,
+ IPV6CTL_FORWARDING
+#else /* NOT KAME */
+ IPPROTO_IP,
+ IP6CTL_FORWARDING
+#endif /* KAME */
+};
+
+int
+ipforward_ipv6 ()
+{
+ int len;
+ int ip6forwarding = 0;
+
+ len = sizeof ip6forwarding;
+ if (sysctl (mib_ipv6, MIB_SIZ, &ip6forwarding, &len, 0, 0) < 0)
+ {
+ zlog_warn ("can't get ip6forwarding value");
+ return -1;
+ }
+ return ip6forwarding;
+}
+
+int
+ipforward_ipv6_on ()
+{
+ int len;
+ int ip6forwarding = 1;
+
+ len = sizeof ip6forwarding;
+ if (sysctl (mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0)
+ {
+ zlog_warn ("can't get ip6forwarding value");
+ return -1;
+ }
+ return ip6forwarding;
+}
+
+int
+ipforward_ipv6_off ()
+{
+ int len;
+ int ip6forwarding = 0;
+
+ len = sizeof ip6forwarding;
+ if (sysctl (mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0)
+ {
+ zlog_warn ("can't get ip6forwarding value");
+ return -1;
+ }
+ return ip6forwarding;
+}
+#endif /* HAVE_IPV6 */
diff --git a/zebra/irdp.c b/zebra/irdp.c
new file mode 100644
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 <zebra.h>
+
+#include <netinet/ip_icmp.h>
+
+#include "if.h"
+#include "stream.h"
+#include "memory.h"
+#include "command.h"
+#include "log.h"
+#include "sockunion.h"
+#include "sockopt.h"
+
+#include "zebra/irdp.h"
+
+/* Default does nothing. */
+int irdp_mode = IRDP_NONE;
+
+/* Timer interval of irdp. */
+int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
+
+/* Max solicitations */
+int max_solicitations = MAX_SOLICITATIONS;
+
+#define IRDP_SOLICIT_PACKET_SIZE 8
+
+static struct irdp *irdp_head = NULL;
+
+extern int in_cksum (void *ptr, int nbytes);
+
+char *icmp_type_str[] =
+{
+ "Echo Reply",
+ "ICMP 1",
+ "ICMP 2",
+ "Dest Unreachable",
+ "Source Quench",
+ "Redirect",
+ "ICMP 6",
+ "ICMP 7",
+ "Echo",
+ "Router Advertise",
+ "Router Solicitation",
+ "Time Exceeded",
+ "Parameter Problem",
+ "Timestamp",
+ "Timestamp Reply",
+ "Info Request",
+ "Info Reply",
+ "Netmask Request",
+ "Netmask Reply",
+};
+
+char *
+icmp_type (int type)
+{
+ if (type < 0 || type >= (sizeof icmp_type_str / sizeof (char *))) {
+ return "OUT-OF-RANGE";
+ }
+ return icmp_type_str [type];
+}
+
+/* */
+void
+irdp_add_interface ()
+{
+ ;
+}
+
+/* */
+void
+irdp_delete_interface ()
+{
+
+}
+
+struct irdp *
+irdp_route_new ()
+{
+ struct irdp *new = XMALLOC (0, sizeof (struct irdp));
+ memset (new, 0, sizeof (struct irdp));
+ return new;
+}
+
+void
+irdp_route_free (struct irdp *route)
+{
+ XFREE (0, route);
+}
+
+void
+route_delete ()
+{
+
+}
+
+void
+route_init ()
+{
+
+}
+
+void
+route_add (struct in_addr addr, unsigned long pref)
+{
+ struct irdp *new = irdp_route_new();
+
+ new->prefix = addr;
+ new->pref = pref;
+
+ printf ("address %s\n", inet_ntoa (new->prefix));
+ printf ("pref %ld\n", new->pref);
+}
+
+void
+route_age (int time)
+{
+ struct irdp *p;
+
+ for (p = irdp_head; p != NULL; p = p->next) {
+ if (p->timer < time) {
+ /* fire */
+ } else {
+ p->timer -= time;
+ }
+ }
+}
+
+#define FLAG_TEST(a) ((ifp->flags & (a)) == (a))
+
+void
+send_multicast (struct interface *ifp, int sock, struct stream *s, int size)
+{
+ struct sockaddr_in sin;
+ struct in_addr addr;
+ int nbytes;
+ struct connected *connected;
+ listnode node;
+
+ for (node = listhead (ifp->connected); node; nextnode (node))
+ {
+ connected = getdata (node);
+ }
+
+ if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF,
+ addr, 0, ifp->ifindex) < 0)
+ {
+ perror ("setsockopt");
+ exit (1);
+ }
+
+ sin.sin_addr.s_addr = htonl (INADDR_ALLRTRS_GROUP);
+ sin.sin_family = AF_INET;
+
+ nbytes = sendto (sock, s->data, size, 0,
+ (struct sockaddr *) &sin, sizeof (struct sockaddr));
+
+ if (nbytes != size)
+ {
+ perror ("sendto");
+ exit (1);
+ }
+}
+
+void
+send_broadcast ()
+{
+ struct sockaddr_in sin;
+
+ printf ("broadcast\n");
+ inet_aton ("255.255.255.255", &sin.sin_addr);
+}
+
+void
+irdp_send_solicit (int sock, struct stream *s, int size)
+{
+ struct interface *ifp;
+ listnode node;
+
+ for (node = listhead (iflist); node; nextnode (node))
+ {
+ ifp = getdata (node);
+ if (FLAG_TEST (IFF_UP | IFF_MULTICAST))
+ {
+ send_multicast (ifp, sock, s, size);
+ }
+ else if (FLAG_TEST (IFF_UP | IFF_BROADCAST))
+ {
+ send_broadcast ();
+ }
+ }
+}
+
+int
+ipv4_multicast_join (int sock,
+ struct in_addr group,
+ struct in_addr ifa,
+ unsigned int ifindex)
+{
+ int ret;
+
+ ret = setsockopt_multicast_ipv4 (sock, IP_ADD_MEMBERSHIP,
+ ifa, group.saddr, ifindex);
+
+ if (ret < 0)
+ zlog (NULL, LOG_INFO, "can't setsockopt IP_ADD_MEMBERSHIP");
+
+ return ret;
+}
+
+/* multicast packet recieve socket */
+int
+irdp_multicast_socket (int sock, struct in_addr group)
+{
+ struct interface *ifp;
+ listnode node;
+ struct in_addr addr;
+
+ for (node = listhead (iflist); node; nextnode (node))
+ {
+ ifp = getdata (node);
+
+ if ((ifp->flags & IFF_UP) && (ifp->flags & IFF_MULTICAST))
+ {
+ ipv4_multicast_join (sock, group, addr, ifp->ifindex);
+ }
+ }
+ return 0;
+}
+
+struct
+{
+ u_char type;
+ u_char code;
+ u_int16_t checksum;
+ u_char number;
+ u_char entry;
+ u_int16_t lifetime;
+} radv;
+
+void
+irdp_set (int sock)
+{
+ struct in_addr irdp_group;
+
+ switch (irdp_mode)
+ {
+ case IRDP_HOST:
+ irdp_group.s_addr = htonl (INADDR_ALLHOSTS_GROUP);
+ break;
+ case IRDP_ROUTER:
+ irdp_group.s_addr = htonl (INADDR_ALLRTRS_GROUP);
+ break;
+ case IRDP_NONE:
+ default:
+ return;
+ }
+ irdp_multicast_socket (sock, irdp_group);
+}
+
+/* Make ICMP Router Solicitation Message. */
+int
+make_solicit_packet (struct stream *s)
+{
+ int size;
+ int checksum;
+
+ stream_putc (s, ICMP_ROUTERSOLICIT); /* Type. */
+ stream_putc (s, 0); /* Code. */
+ stream_putw (s, 0); /* Checksum. */
+ stream_putl (s, 0); /* Reserved. */
+
+ /* in_cksum return network byte order value */
+ size = IRDP_SOLICIT_PACKET_SIZE;
+ checksum = in_cksum (s->data, size);
+ stream_putw_at (s, checksum, 2);
+
+ return IRDP_SOLICIT_PACKET_SIZE;
+}
+
+void
+irdp_solicit (int sock)
+{
+ struct stream *s;
+
+ s = stream_new (IRDP_SOLICIT_PACKET_SIZE);
+ make_solicit_packet (s);
+ irdp_send_solicit (sock, s, IRDP_SOLICIT_PACKET_SIZE);
+}
+
+#define ICMP_MINLEN 8
+
+/* check validity of the packet */
+int
+irdp_valid_check (char *packet, size_t size, struct sockaddr_in *from)
+{
+ struct icmp *icmp;
+
+ icmp = (struct icmp *) packet;
+
+ if (in_cksum (packet, size)) {
+ zlog_warn ("ICMP %s packet from %s: Bad checksum, silently ignored",
+ icmp_type (icmp->icmp_type),
+ inet_ntoa (from->sin_addr));
+ return -1;
+ }
+
+ if (icmp->icmp_code != 0) {
+ zlog_warn ("ICMP %s packet from %s: Bad ICMP type code, silently ignored",
+ icmp_type (icmp->icmp_type),
+ inet_ntoa (from->sin_addr));
+ return -1;
+ }
+
+ if (size < ICMP_MINLEN) {
+ zlog_warn ("ICMP %s packet from %s: IMCP message length is short",
+ icmp_type (icmp->icmp_type),
+ inet_ntoa (from->sin_addr));
+ return -1;
+ }
+ return 0;
+}
+
+int
+irdp_solicit_recv (struct stream *s, int size, struct sockaddr_in *from)
+{
+ if (irdp_valid_check (s->data, size, from)) {
+ return 1;
+ }
+ return 0;
+}
+
+void
+irdp_advert_recv (struct stream *s, int size, struct sockaddr_in *from)
+{
+ int i;
+ struct in_addr addr;
+ long pref;
+
+ if (irdp_valid_check (s->data, size, from) < 0) {
+ return;
+ }
+
+ radv.type = stream_getc (s);
+ radv.code = stream_getc (s);
+ radv.checksum = stream_getw (s);
+ radv.number = stream_getc (s);
+ radv.entry = stream_getc (s);
+ radv.lifetime = stream_getw (s);
+
+ printf ("type : %s\n", icmp_type (radv.type));
+ printf ("number: %d\n", radv.number);
+ printf ("entry: %d\n", radv.entry);
+ printf ("lifetime: %d\n", radv.entry);
+
+ for (i = 0; i < radv.number; i++)
+ {
+ addr.s_addr = stream_getl (s);
+ pref = stream_getl (s);
+ route_add (addr, ntohl (pref));
+ }
+ /* Packet size check is needed at here. */
+}
+
+void
+irdp_packet_process (char *buf, int size, struct sockaddr_in *from)
+{
+ struct ip *ip;
+ struct icmp *icmp;
+ int hlen;
+ struct stream *s = NULL;
+
+ ip = (struct ip *)buf;
+ hlen = ip->ip_hl << 2;
+
+ if (size < hlen + ICMP_MINLEN)
+ zlog_err ("ICMP relpy length is short\n");
+
+ icmp = (struct icmp *)(buf + hlen);
+
+ stream_forward (s, hlen);
+
+ switch (icmp->icmp_type)
+ {
+ case ICMP_ROUTERADVERT:
+ irdp_advert_recv (s, size - hlen, from);
+ break;
+ case ICMP_ROUTERSOLICIT:
+ irdp_solicit_recv (s, size - hlen, from);
+ break;
+ }
+}
+
+/* Make socket for ICMP Router Discovery. */
+int
+irdp_make_socket ()
+{
+ int sock;
+ struct protoent *pent;
+
+ if ((pent = getprotobyname ("icmp")) == NULL) {
+ perror ("getprotobyname");
+ exit (1);
+ }
+
+ if ((sock = socket (AF_INET, SOCK_RAW, pent->p_proto)) < 0)
+ {
+ perror ("socket");
+ exit (1);
+ }
+
+ return sock;
+}
+
+/* recv routine */
+int
+irdp_recv (int sock)
+{
+#define PACKET_BUF 4096
+ int nbytes;
+ struct sockaddr_in from;
+ int fromlen;
+ char buf[PACKET_BUF];
+
+ fromlen = sizeof (from);
+ nbytes = recvfrom (sock, (char *)buf, PACKET_BUF, 0,
+ (struct sockaddr *)&from, &fromlen);
+
+ if (nbytes < 0)
+ {
+ perror ("recvfrom");
+ exit (1);
+ }
+
+ irdp_packet_process (buf, nbytes, &from);
+
+ return 0;
+}
+
+/* irdp packet recv loop */
+void
+irdp_loop (int sock)
+{
+ while (1)
+ {
+ irdp_recv (sock);
+ }
+}
+
+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 <zebra.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "sockunion.h"
+#include "connected.h"
+#include "memory.h"
+#include "ioctl.h"
+#include "log.h"
+#include "str.h"
+#include "table.h"
+#include "rib.h"
+
+#include "zebra/interface.h"
+#include "zebra/zserv.h"
+#include "zebra/debug.h"
+
+/* Socket length roundup function. */
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+
+/* And this macro is wrapper for handling sa_len. */
+#ifdef HAVE_SA_LEN
+#define WRAPUP(X) ROUNDUP(((struct sockaddr *)(X))->sa_len)
+#else
+#define WRAPUP(X) ROUNDUP(sizeof (struct sockaddr))
+#endif /* HAVE_SA_LEN */
+
+/* Routing socket message types. */
+struct message rtm_type_str[] =
+{
+ {RTM_ADD, "RTM_ADD"},
+ {RTM_DELETE, "RTM_DELETE"},
+ {RTM_CHANGE, "RTM_CHANGE"},
+ {RTM_GET, "RTM_GET"},
+ {RTM_LOSING, "RTM_LOSING"},
+ {RTM_REDIRECT, "RTM_REDIRECT"},
+ {RTM_MISS, "RTM_MISS"},
+ {RTM_LOCK, "RTM_LOCK"},
+ {RTM_OLDADD, "RTM_OLDADD"},
+ {RTM_OLDDEL, "RTM_OLDDEL"},
+ {RTM_RESOLVE, "RTM_RESOLVE"},
+ {RTM_NEWADDR, "RTM_NEWADDR"},
+ {RTM_DELADDR, "RTM_DELADDR"},
+ {RTM_IFINFO, "RTM_IFINFO"},
+#ifdef RTM_OIFINFO
+ {RTM_OIFINFO, "RTM_OIFINFO"},
+#endif /* RTM_OIFINFO */
+#ifdef RTM_NEWMADDR
+ {RTM_NEWMADDR, "RTM_NEWMADDR"},
+#endif /* RTM_NEWMADDR */
+#ifdef RTM_DELMADDR
+ {RTM_DELMADDR, "RTM_DELMADDR"},
+#endif /* RTM_DELMADDR */
+#ifdef RTM_IFANNOUNCE
+ {RTM_IFANNOUNCE, "RTM_IFANNOUNCE"},
+#endif /* RTM_IFANNOUNCE */
+ {0, NULL}
+};
+
+struct message rtm_flag_str[] =
+{
+ {RTF_UP, "UP"},
+ {RTF_GATEWAY, "GATEWAY"},
+ {RTF_HOST, "HOST"},
+ {RTF_REJECT, "REJECT"},
+ {RTF_DYNAMIC, "DYNAMIC"},
+ {RTF_MODIFIED, "MODIFIED"},
+ {RTF_DONE, "DONE"},
+#ifdef RTF_MASK
+ {RTF_MASK, "MASK"},
+#endif /* RTF_MASK */
+ {RTF_CLONING, "CLONING"},
+ {RTF_XRESOLVE, "XRESOLVE"},
+ {RTF_LLINFO, "LLINFO"},
+ {RTF_STATIC, "STATIC"},
+ {RTF_BLACKHOLE, "BLACKHOLE"},
+ {RTF_PROTO1, "PROTO1"},
+ {RTF_PROTO2, "PROTO2"},
+#ifdef RTF_PRCLONING
+ {RTF_PRCLONING, "PRCLONING"},
+#endif /* RTF_PRCLONING */
+#ifdef RTF_WASCLONED
+ {RTF_WASCLONED, "WASCLONED"},
+#endif /* RTF_WASCLONED */
+#ifdef RTF_PROTO3
+ {RTF_PROTO3, "PROTO3"},
+#endif /* RTF_PROTO3 */
+#ifdef RTF_PINNED
+ {RTF_PINNED, "PINNED"},
+#endif /* RTF_PINNED */
+#ifdef RTF_LOCAL
+ {RTF_LOCAL, "LOCAL"},
+#endif /* RTF_LOCAL */
+#ifdef RTF_BROADCAST
+ {RTF_BROADCAST, "BROADCAST"},
+#endif /* RTF_BROADCAST */
+#ifdef RTF_MULTICAST
+ {RTF_MULTICAST, "MULTICAST"},
+#endif /* RTF_MULTICAST */
+ {0, NULL}
+};
+
+/* Kernel routing update socket. */
+int routing_sock = -1;
+
+/* Yes I'm checking ugly routing socket behavior. */
+/* #define DEBUG */
+
+/* Supported address family check. */
+static int
+af_check (int family)
+{
+ if (family == AF_INET)
+ return 1;
+#ifdef HAVE_IPV6
+ if (family == AF_INET6)
+ return 1;
+#endif /* HAVE_IPV6 */
+ return 0;
+}
+
+/* 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 <zebra.h>
+
+#include "version.h"
+#include "getopt.h"
+#include "command.h"
+#include "thread.h"
+#include "filter.h"
+#include "memory.h"
+#include "prefix.h"
+#include "log.h"
+
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+#include "zebra/debug.h"
+#include "zebra/rib.h"
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* process id. */
+pid_t old_pid;
+pid_t pid;
+
+/* Route retain mode flag. */
+int retain_mode = 0;
+
+/* Don't delete kernel route. */
+int keep_kernel_mode = 0;
+
+/* Command line options. */
+struct option longopts[] =
+{
+ { "batch", no_argument, NULL, 'b'},
+ { "daemon", no_argument, NULL, 'd'},
+ { "keep_kernel", no_argument, NULL, 'k'},
+ { "log_mode", no_argument, NULL, 'l'},
+ { "config_file", required_argument, NULL, 'f'},
+ { "pid_file", required_argument, NULL, 'i'},
+ { "help", no_argument, NULL, 'h'},
+ { "vty_addr", required_argument, NULL, 'A'},
+ { "vty_port", required_argument, NULL, 'P'},
+ { "retain", no_argument, NULL, 'r'},
+ { "version", no_argument, NULL, 'v'},
+ { 0 }
+};
+
+/* Default configuration file path. */
+char config_current[] = DEFAULT_CONFIG_FILE;
+char config_default[] = SYSCONFDIR DEFAULT_CONFIG_FILE;
+
+/* Process ID saved for use by init system */
+char *pid_file = PATH_ZEBRA_PID;
+
+/* Help information display. */
+static void
+usage (char *progname, int status)
+{
+ if (status != 0)
+ fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+ else
+ {
+ printf ("Usage : %s [OPTION...]\n\n\
+Daemon which manages kernel routing table management and \
+redistribution between different routing protocols.\n\n\
+-b, --batch Runs in batch mode\n\
+-d, --daemon Runs in daemon mode\n\
+-f, --config_file Set configuration file name\n\
+-i, --pid_file Set process identifier file name\n\
+-k, --keep_kernel Don't delete old routes which installed by zebra.\n\
+-l, --log_mode Set verbose log mode flag\n\
+-A, --vty_addr Set vty's bind address\n\
+-P, --vty_port Set vty's port number\n\
+-r, --retain When program terminates, retain added route by zebra.\n\
+-v, --version Print program version\n\
+-h, --help Display this help and exit\n\
+\n\
+Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
+ }
+
+ exit (status);
+}
+
+/* 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 <zebra.h>
+
+#include <kvm.h>
+#include <limits.h>
+#include <fcntl.h>
+
+#include "if.h"
+
+/* get interface MTU to use kvm_read */
+void
+if_kvm_get_mtu (struct interface *ifp)
+{
+ kvm_t *kvmd;
+ struct ifnet ifnet;
+ unsigned long ifnetaddr;
+ int len;
+
+ char ifname[IFNAMSIZ];
+ char tname[INTERFACE_NAMSIZ + 1];
+ char buf[_POSIX2_LINE_MAX];
+
+ struct nlist nl[] =
+ {
+ {"_ifnet"},
+ {""}
+ };
+
+ ifp->mtu = -1;
+
+ kvmd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, buf);
+
+ if (kvmd == NULL)
+ return ;
+
+ kvm_nlist(kvmd, nl);
+
+ ifnetaddr = nl[0].n_value;
+
+ if (kvm_read(kvmd, ifnetaddr, (char *)&ifnetaddr, sizeof ifnetaddr) < 0)
+ {
+ kvm_close (kvmd);
+ return ;
+ }
+
+ while(ifnetaddr != 0)
+ {
+ if (kvm_read (kvmd, ifnetaddr, (char *)&ifnet, sizeof ifnet) < 0)
+ {
+ kvm_close (kvmd);
+ return ;
+ }
+
+ if (kvm_read (kvmd, (u_long)ifnet.if_name, ifname, IFNAMSIZ) < 0)
+ {
+ kvm_close (kvmd);
+ return ;
+ }
+
+ len = snprintf (tname, INTERFACE_NAMSIZ + 1,
+ "%s%d", ifname, ifnet.if_unit);
+
+ if (strncmp (tname, ifp->name, len) == 0)
+ break;
+
+ ifnetaddr = (u_long)ifnet.if_next;
+ }
+
+ kvm_close (kvmd);
+
+ if (ifnetaddr == 0)
+ {
+ return ;
+ }
+
+ ifp->mtu = ifnet.if_mtu;
+}
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
new file mode 100644
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 <zebra.h>
+
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+#include "prefix.h"
+#include "table.h"
+#include "stream.h"
+#include "zclient.h"
+#include "linklist.h"
+#include "log.h"
+
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/debug.h"
+
+int
+zebra_check_addr (struct prefix *p)
+{
+ if (p->family == AF_INET)
+ {
+ u_int32_t addr;
+
+ addr = p->u.prefix4.s_addr;
+ addr = ntohl (addr);
+
+ if (IPV4_NET127 (addr) || IN_CLASSD (addr))
+ return 0;
+ }
+#ifdef HAVE_IPV6
+ if (p->family == AF_INET6)
+ {
+ if (IN6_IS_ADDR_LOOPBACK (&p->u.prefix6))
+ return 0;
+ if (IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6))
+ return 0;
+ }
+#endif /* HAVE_IPV6 */
+ return 1;
+}
+
+int
+is_default (struct prefix *p)
+{
+ if (p->family == AF_INET)
+ if (p->u.prefix4.s_addr == 0 && p->prefixlen == 0)
+ return 1;
+#ifdef HAVE_IPV6
+#if 0 /* IPv6 default separation is now pending until protocol daemon
+ can handle that. */
+ if (p->family == AF_INET6)
+ if (IN6_IS_ADDR_UNSPECIFIED (&p->u.prefix6) && p->prefixlen == 0)
+ return 1;
+#endif /* 0 */
+#endif /* HAVE_IPV6 */
+ return 0;
+}
+
+void
+zebra_redistribute_default (struct zserv *client)
+{
+ struct prefix_ipv4 p;
+ struct route_table *table;
+ struct route_node *rn;
+ struct rib *newrib;
+#ifdef HAVE_IPV6
+ struct prefix_ipv6 p6;
+#endif /* HAVE_IPV6 */
+
+
+ /* Lookup default route. */
+ memset (&p, 0, sizeof (struct prefix_ipv4));
+ p.family = AF_INET;
+
+ /* Lookup table. */
+ table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+ if (table)
+ {
+ rn = route_node_lookup (table, (struct prefix *)&p);
+ if (rn)
+ {
+ for (newrib = rn->info; newrib; newrib = newrib->next)
+ if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
+ && newrib->distance != DISTANCE_INFINITY)
+ zsend_ipv4_add_multipath (client, &rn->p, newrib);
+ route_unlock_node (rn);
+ }
+ }
+
+#ifdef HAVE_IPV6
+ /* Lookup default route. */
+ memset (&p6, 0, sizeof (struct prefix_ipv6));
+ p6.family = AF_INET6;
+
+ /* Lookup table. */
+ table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+ if (table)
+ {
+ rn = route_node_lookup (table, (struct prefix *)&p6);
+ if (rn)
+ {
+ for (newrib = rn->info; newrib; newrib = newrib->next)
+ if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
+ && newrib->distance != DISTANCE_INFINITY)
+ zsend_ipv6_add_multipath (client, &rn->p, newrib);
+ route_unlock_node (rn);
+ }
+ }
+#endif /* HAVE_IPV6 */
+}
+
+/* Redistribute routes. */
+void
+zebra_redistribute (struct zserv *client, int type)
+{
+ struct rib *newrib;
+ struct route_table *table;
+ struct route_node *rn;
+
+ table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+ if (table)
+ for (rn = route_top (table); rn; rn = route_next (rn))
+ for (newrib = rn->info; newrib; newrib = newrib->next)
+ if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
+ && newrib->type == type
+ && newrib->distance != DISTANCE_INFINITY
+ && zebra_check_addr (&rn->p))
+ zsend_ipv4_add_multipath (client, &rn->p, newrib);
+
+#ifdef HAVE_IPV6
+ table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+ if (table)
+ for (rn = route_top (table); rn; rn = route_next (rn))
+ for (newrib = rn->info; newrib; newrib = newrib->next)
+ if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
+ && newrib->type == type
+ && newrib->distance != DISTANCE_INFINITY
+ && zebra_check_addr (&rn->p))
+ zsend_ipv6_add_multipath (client, &rn->p, newrib);
+#endif /* HAVE_IPV6 */
+}
+
+extern list client_list;
+
+void
+redistribute_add (struct prefix *p, struct rib *rib)
+{
+ listnode node;
+ struct zserv *client;
+
+ for (node = listhead (client_list); node; nextnode (node))
+ if ((client = getdata (node)) != NULL)
+ {
+ if (is_default (p))
+ {
+ if (client->redist_default || client->redist[rib->type])
+ {
+ if (p->family == AF_INET)
+ zsend_ipv4_add_multipath (client, p, rib);
+#ifdef HAVE_IPV6
+ if (p->family == AF_INET6)
+ zsend_ipv6_add_multipath (client, p, rib);
+#endif /* HAVE_IPV6 */
+ }
+ }
+ else if (client->redist[rib->type])
+ {
+ if (p->family == AF_INET)
+ zsend_ipv4_add_multipath (client, p, rib);
+#ifdef HAVE_IPV6
+ if (p->family == AF_INET6)
+ zsend_ipv6_add_multipath (client, p, rib);
+#endif /* HAVE_IPV6 */
+ }
+ }
+}
+
+void
+redistribute_delete (struct prefix *p, struct rib *rib)
+{
+ listnode node;
+ struct zserv *client;
+
+ /* Add DISTANCE_INFINITY check. */
+ if (rib->distance == DISTANCE_INFINITY)
+ return;
+
+ for (node = listhead (client_list); node; nextnode (node))
+ if ((client = getdata (node)) != NULL)
+ {
+ if (is_default (p))
+ {
+ if (client->redist_default || client->redist[rib->type])
+ {
+ if (p->family == AF_INET)
+ zsend_ipv4_delete_multipath (client, p, rib);
+#ifdef HAVE_IPV6
+ if (p->family == AF_INET6)
+ zsend_ipv6_delete_multipath (client, p, rib);
+#endif /* HAVE_IPV6 */
+ }
+ }
+ else if (client->redist[rib->type])
+ {
+ if (p->family == AF_INET)
+ zsend_ipv4_delete_multipath (client, p, rib);
+#ifdef HAVE_IPV6
+ if (p->family == AF_INET6)
+ zsend_ipv6_delete_multipath (client, p, rib);
+#endif /* HAVE_IPV6 */
+ }
+ }
+}
+
+void
+zebra_redistribute_add (int command, struct zserv *client, int length)
+{
+ int type;
+
+ type = stream_getc (client->ibuf);
+
+ switch (type)
+ {
+ case ZEBRA_ROUTE_KERNEL:
+ case ZEBRA_ROUTE_CONNECT:
+ case ZEBRA_ROUTE_STATIC:
+ case ZEBRA_ROUTE_RIP:
+ case ZEBRA_ROUTE_RIPNG:
+ case ZEBRA_ROUTE_OSPF:
+ case ZEBRA_ROUTE_OSPF6:
+ case ZEBRA_ROUTE_BGP:
+ if (! client->redist[type])
+ {
+ client->redist[type] = 1;
+ zebra_redistribute (client, type);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void
+zebra_redistribute_delete (int command, struct zserv *client, int length)
+{
+ int type;
+
+ type = stream_getc (client->ibuf);
+
+ switch (type)
+ {
+ case ZEBRA_ROUTE_KERNEL:
+ case ZEBRA_ROUTE_CONNECT:
+ case ZEBRA_ROUTE_STATIC:
+ case ZEBRA_ROUTE_RIP:
+ case ZEBRA_ROUTE_RIPNG:
+ case ZEBRA_ROUTE_OSPF:
+ case ZEBRA_ROUTE_OSPF6:
+ case ZEBRA_ROUTE_BGP:
+ client->redist[type] = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+void
+zebra_redistribute_default_add (int command, struct zserv *client, int length)
+{
+ client->redist_default = 1;
+ zebra_redistribute_default (client);
+}
+
+void
+zebra_redistribute_default_delete (int command, struct zserv *client,
+ int length)
+{
+ client->redist_default = 0;;
+}
+
+/* Interface up information. */
+void
+zebra_interface_up_update (struct interface *ifp)
+{
+ listnode node;
+ struct zserv *client;
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_info ("MESSAGE: ZEBRA_INTERFACE_UP %s", ifp->name);
+
+ for (node = listhead (client_list); node; nextnode (node))
+ if ((client = getdata (node)) != NULL)
+ zsend_interface_up (client, ifp);
+}
+
+/* Interface down information. */
+void
+zebra_interface_down_update (struct interface *ifp)
+{
+ listnode node;
+ struct zserv *client;
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_info ("MESSAGE: ZEBRA_INTERFACE_DOWN %s", ifp->name);
+
+ for (node = listhead (client_list); node; nextnode (node))
+ if ((client = getdata (node)) != NULL)
+ zsend_interface_down (client, ifp);
+}
+
+/* Interface information update. */
+void
+zebra_interface_add_update (struct interface *ifp)
+{
+ listnode node;
+ struct zserv *client;
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_info ("MESSAGE: ZEBRA_INTERFACE_ADD %s", ifp->name);
+
+ for (node = listhead (client_list); node; nextnode (node))
+ if ((client = getdata (node)) != NULL)
+ if (client->ifinfo)
+ zsend_interface_add (client, ifp);
+}
+
+void
+zebra_interface_delete_update (struct interface *ifp)
+{
+ listnode node;
+ struct zserv *client;
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_info ("MESSAGE: ZEBRA_INTERFACE_DELETE %s", ifp->name);
+
+ for (node = listhead (client_list); node; nextnode (node))
+ if ((client = getdata (node)) != NULL)
+ if (client->ifinfo)
+ zsend_interface_delete (client, ifp);
+}
+
+/* Interface address addition. */
+void
+zebra_interface_address_add_update (struct interface *ifp,
+ struct connected *ifc)
+{
+ listnode node;
+ struct zserv *client;
+ struct prefix *p;
+ char buf[BUFSIZ];
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ {
+ p = ifc->address;
+ zlog_info ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD %s/%d on %s",
+ inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+ p->prefixlen, ifc->ifp->name);
+ }
+
+ for (node = listhead (client_list); node; nextnode (node))
+ if ((client = getdata (node)) != NULL)
+ if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+ zsend_interface_address_add (client, ifp, ifc);
+}
+
+/* Interface address deletion. */
+void
+zebra_interface_address_delete_update (struct interface *ifp,
+ struct connected *ifc)
+{
+ listnode node;
+ struct zserv *client;
+ struct prefix *p;
+ char buf[BUFSIZ];
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ {
+ p = ifc->address;
+ zlog_info ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE %s/%d on %s",
+ inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+ p->prefixlen, ifc->ifp->name);
+ }
+
+ for (node = listhead (client_list); node; nextnode (node))
+ if ((client = getdata (node)) != NULL)
+ if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+ zsend_interface_address_delete (client, ifp, ifc);
+}
diff --git a/zebra/redistribute.h b/zebra/redistribute.h
new file mode 100644
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 <zebra.h>
+
+#include "prefix.h"
+#include "log.h"
+#include "if.h"
+
+#include "zebra/rib.h"
+#include "zebra/debug.h"
+
+/* Initialize of kernel interface. There is no kernel communication
+ support under ioctl(). So this is dummy stub function. */
+void
+kernel_init ()
+{
+ return;
+}
+
+/* Dummy function of routing socket. */
+void
+kernel_read (int sock)
+{
+ return;
+}
+
+#if 0
+/* Initialization prototype of struct sockaddr_in. */
+static struct sockaddr_in sin_proto =
+{
+#ifdef HAVE_SIN_LEN
+ sizeof (struct sockaddr_in),
+#endif /* HAVE_SIN_LEN */
+ AF_INET, 0, {0}, {0}
+};
+#endif /* 0 */
+
+/* Solaris has ortentry. */
+#ifdef HAVE_OLD_RTENTRY
+#define rtentry ortentry
+#endif /* HAVE_OLD_RTENTRY */
+
+/* Interface to ioctl route message. */
+int
+kernel_add_route (struct prefix_ipv4 *dest, struct in_addr *gate,
+ int index, int flags)
+{
+ int ret;
+ int sock;
+ struct rtentry rtentry;
+ struct sockaddr_in sin_dest, sin_mask, sin_gate;
+
+ memset (&rtentry, 0, sizeof (struct rtentry));
+
+ /* Make destination. */
+ memset (&sin_dest, 0, sizeof (struct sockaddr_in));
+ sin_dest.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+ sin_dest.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+ sin_dest.sin_addr = dest->prefix;
+
+ /* Make gateway. */
+ if (gate)
+ {
+ memset (&sin_gate, 0, sizeof (struct sockaddr_in));
+ sin_gate.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+ sin_gate.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+ sin_gate.sin_addr = *gate;
+ }
+
+ memset (&sin_mask, 0, sizeof (struct sockaddr_in));
+ sin_mask.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+ sin_gate.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+ masklen2ip (dest->prefixlen, &sin_mask.sin_addr);
+
+ /* Set destination address, mask and gateway.*/
+ memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in));
+ if (gate)
+ memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in));
+#ifndef SUNOS_5
+ memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in));
+#endif /* SUNOS_5 */
+
+ /* Routing entry flag set. */
+ if (dest->prefixlen == 32)
+ rtentry.rt_flags |= RTF_HOST;
+
+ if (gate && gate->s_addr != INADDR_ANY)
+ rtentry.rt_flags |= RTF_GATEWAY;
+
+ rtentry.rt_flags |= RTF_UP;
+
+ /* Additional flags */
+ rtentry.rt_flags |= flags;
+
+
+ /* For tagging route. */
+ /* rtentry.rt_flags |= RTF_DYNAMIC; */
+
+ /* Open socket for ioctl. */
+ sock = socket (AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ {
+ zlog_warn ("can't make socket\n");
+ return -1;
+ }
+
+ /* Send message by ioctl(). */
+ ret = ioctl (sock, SIOCADDRT, &rtentry);
+ if (ret < 0)
+ {
+ switch (errno)
+ {
+ case EEXIST:
+ close (sock);
+ return ZEBRA_ERR_RTEXIST;
+ break;
+ case ENETUNREACH:
+ close (sock);
+ return ZEBRA_ERR_RTUNREACH;
+ break;
+ case EPERM:
+ close (sock);
+ return ZEBRA_ERR_EPERM;
+ break;
+ }
+
+ close (sock);
+ zlog_warn ("write : %s (%d)", strerror (errno), errno);
+ return 1;
+ }
+ close (sock);
+
+ return ret;
+}
+
+/* Interface to ioctl route message. */
+int
+kernel_ioctl_ipv4 (u_long cmd, struct prefix *p, struct rib *rib, int family)
+{
+ int ret;
+ int sock;
+ struct rtentry rtentry;
+ struct sockaddr_in sin_dest, sin_mask, sin_gate;
+ struct nexthop *nexthop;
+ int nexthop_num = 0;
+ struct interface *ifp;
+
+ memset (&rtentry, 0, sizeof (struct rtentry));
+
+ /* Make destination. */
+ memset (&sin_dest, 0, sizeof (struct sockaddr_in));
+ sin_dest.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+ sin_dest.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+ sin_dest.sin_addr = p->u.prefix4;
+
+ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
+ {
+ SET_FLAG (rtentry.rt_flags, RTF_REJECT);
+
+ if (cmd == SIOCADDRT)
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+ goto skip;
+ }
+
+ memset (&sin_gate, 0, sizeof (struct sockaddr_in));
+
+ /* Make gateway. */
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ {
+ if ((cmd == SIOCADDRT
+ && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ || (cmd == SIOCDELRT
+ && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
+ {
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ {
+ if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
+ nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
+ {
+ sin_gate.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+ sin_gate.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+ sin_gate.sin_addr = nexthop->rgate.ipv4;
+ rtentry.rt_flags |= RTF_GATEWAY;
+ }
+ if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+ || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
+ {
+ ifp = if_lookup_by_index (nexthop->rifindex);
+ if (ifp)
+ rtentry.rt_dev = ifp->name;
+ else
+ return -1;
+ }
+ }
+ else
+ {
+ if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
+ nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+ {
+ sin_gate.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+ sin_gate.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+ sin_gate.sin_addr = nexthop->gate.ipv4;
+ rtentry.rt_flags |= RTF_GATEWAY;
+ }
+ if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+ || nexthop->type == NEXTHOP_TYPE_IFNAME)
+ {
+ ifp = if_lookup_by_index (nexthop->ifindex);
+ if (ifp)
+ rtentry.rt_dev = ifp->name;
+ else
+ return -1;
+ }
+ }
+
+ if (cmd == SIOCADDRT)
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+ nexthop_num++;
+ break;
+ }
+ }
+
+ /* If there is no useful nexthop then return. */
+ if (nexthop_num == 0)
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_info ("netlink_route_multipath(): No useful nexthop.");
+ return 0;
+ }
+
+ skip:
+
+ memset (&sin_mask, 0, sizeof (struct sockaddr_in));
+ sin_mask.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+ sin_mask.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+ masklen2ip (p->prefixlen, &sin_mask.sin_addr);
+
+ /* Set destination address, mask and gateway.*/
+ memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in));
+
+ if (rtentry.rt_flags & RTF_GATEWAY)
+ memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in));
+
+#ifndef SUNOS_5
+ memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in));
+#endif /* SUNOS_5 */
+
+ /* Metric. It seems metric minus one value is installed... */
+ rtentry.rt_metric = rib->metric;
+
+ /* Routing entry flag set. */
+ if (p->prefixlen == 32)
+ rtentry.rt_flags |= RTF_HOST;
+
+ rtentry.rt_flags |= RTF_UP;
+
+ /* Additional flags */
+ /* rtentry.rt_flags |= flags; */
+
+ /* For tagging route. */
+ /* rtentry.rt_flags |= RTF_DYNAMIC; */
+
+ /* Open socket for ioctl. */
+ sock = socket (AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ {
+ zlog_warn ("can't make socket\n");
+ return -1;
+ }
+
+ /* Send message by ioctl(). */
+ ret = ioctl (sock, cmd, &rtentry);
+ if (ret < 0)
+ {
+ switch (errno)
+ {
+ case EEXIST:
+ close (sock);
+ return ZEBRA_ERR_RTEXIST;
+ break;
+ case ENETUNREACH:
+ close (sock);
+ return ZEBRA_ERR_RTUNREACH;
+ break;
+ case EPERM:
+ close (sock);
+ return ZEBRA_ERR_EPERM;
+ break;
+ }
+
+ close (sock);
+ zlog_warn ("write : %s (%d)", strerror (errno), errno);
+ return ret;
+ }
+ close (sock);
+
+ return ret;
+}
+
+int
+kernel_add_ipv4 (struct prefix *p, struct rib *rib)
+{
+ return kernel_ioctl_ipv4 (SIOCADDRT, p, rib, AF_INET);
+}
+
+int
+kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
+{
+ return kernel_ioctl_ipv4 (SIOCDELRT, p, rib, AF_INET);
+}
+
+#ifdef HAVE_IPV6
+
+/* Below is hack for GNU libc definition and Linux 2.1.X header. */
+#undef RTF_DEFAULT
+#undef RTF_ADDRCONF
+
+#include <asm/types.h>
+
+#if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
+/* struct in6_rtmsg will be declared in net/route.h. */
+#else
+#include <linux/ipv6_route.h>
+#endif
+
+int
+kernel_ioctl_ipv6 (u_long type, struct prefix_ipv6 *dest, struct in6_addr *gate,
+ int index, int flags)
+{
+ int ret;
+ int sock;
+ struct in6_rtmsg rtm;
+
+ memset (&rtm, 0, sizeof (struct in6_rtmsg));
+
+ rtm.rtmsg_flags |= RTF_UP;
+ rtm.rtmsg_metric = 1;
+ memcpy (&rtm.rtmsg_dst, &dest->prefix, sizeof (struct in6_addr));
+ rtm.rtmsg_dst_len = dest->prefixlen;
+
+ /* We need link local index. But this should be done caller...
+ if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
+ {
+ index = if_index_address (&rtm.rtmsg_gateway);
+ rtm.rtmsg_ifindex = index;
+ }
+ else
+ rtm.rtmsg_ifindex = 0;
+ */
+
+ rtm.rtmsg_flags |= RTF_GATEWAY;
+
+ /* For tagging route. */
+ /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
+
+ memcpy (&rtm.rtmsg_gateway, gate, sizeof (struct in6_addr));
+
+ if (index)
+ rtm.rtmsg_ifindex = index;
+ else
+ rtm.rtmsg_ifindex = 0;
+
+ rtm.rtmsg_metric = 1;
+
+ sock = socket (AF_INET6, SOCK_DGRAM, 0);
+ if (sock < 0)
+ {
+ zlog_warn ("can't make socket\n");
+ return -1;
+ }
+
+ /* Send message via ioctl. */
+ ret = ioctl (sock, type, &rtm);
+ if (ret < 0)
+ {
+ zlog_warn ("can't %s ipv6 route: %s\n", type == SIOCADDRT ? "add" : "delete",
+ strerror(errno));
+ ret = errno;
+ close (sock);
+ return ret;
+ }
+ close (sock);
+
+ return ret;
+}
+
+int
+kernel_ioctl_ipv6_multipath (u_long cmd, struct prefix *p, struct rib *rib,
+ int family)
+{
+ int ret;
+ int sock;
+ struct in6_rtmsg rtm;
+ struct nexthop *nexthop;
+ int nexthop_num = 0;
+
+ memset (&rtm, 0, sizeof (struct in6_rtmsg));
+
+ rtm.rtmsg_flags |= RTF_UP;
+ rtm.rtmsg_metric = rib->metric;
+ memcpy (&rtm.rtmsg_dst, &p->u.prefix, sizeof (struct in6_addr));
+ rtm.rtmsg_dst_len = p->prefixlen;
+
+ /* We need link local index. But this should be done caller...
+ if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
+ {
+ index = if_index_address (&rtm.rtmsg_gateway);
+ rtm.rtmsg_ifindex = index;
+ }
+ else
+ rtm.rtmsg_ifindex = 0;
+ */
+
+ rtm.rtmsg_flags |= RTF_GATEWAY;
+
+ /* For tagging route. */
+ /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
+
+ /* Make gateway. */
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ {
+ if ((cmd == SIOCADDRT
+ && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ || (cmd == SIOCDELRT
+ && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
+ {
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ {
+ if (nexthop->rtype == NEXTHOP_TYPE_IPV6
+ || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
+ || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
+ {
+ memcpy (&rtm.rtmsg_gateway, &nexthop->rgate.ipv6,
+ sizeof (struct in6_addr));
+ }
+ if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+ || nexthop->rtype == NEXTHOP_TYPE_IFNAME
+ || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
+ || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
+ rtm.rtmsg_ifindex = nexthop->rifindex;
+ else
+ rtm.rtmsg_ifindex = 0;
+
+ }
+ else
+ {
+ if (nexthop->type == NEXTHOP_TYPE_IPV6
+ || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+ || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+ {
+ memcpy (&rtm.rtmsg_gateway, &nexthop->gate.ipv6,
+ sizeof (struct in6_addr));
+ }
+ if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+ || nexthop->type == NEXTHOP_TYPE_IFNAME
+ || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+ || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+ rtm.rtmsg_ifindex = nexthop->ifindex;
+ else
+ rtm.rtmsg_ifindex = 0;
+ }
+
+ if (cmd == SIOCADDRT)
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+ nexthop_num++;
+ break;
+ }
+ }
+
+ /* If there is no useful nexthop then return. */
+ if (nexthop_num == 0)
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_info ("netlink_route_multipath(): No useful nexthop.");
+ return 0;
+ }
+
+ sock = socket (AF_INET6, SOCK_DGRAM, 0);
+ if (sock < 0)
+ {
+ zlog_warn ("can't make socket\n");
+ return -1;
+ }
+
+ /* Send message via ioctl. */
+ ret = ioctl (sock, cmd, &rtm);
+ if (ret < 0)
+ {
+ zlog_warn ("can't %s ipv6 route: %s\n",
+ cmd == SIOCADDRT ? "add" : "delete",
+ strerror(errno));
+ ret = errno;
+ close (sock);
+ return ret;
+ }
+ close (sock);
+
+ return ret;
+}
+
+int
+kernel_add_ipv6 (struct prefix *p, struct rib *rib)
+{
+ return kernel_ioctl_ipv6_multipath (SIOCADDRT, p, rib, AF_INET6);
+}
+
+int
+kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
+{
+ return kernel_ioctl_ipv6_multipath (SIOCDELRT, p, rib, AF_INET6);
+}
+
+/* Delete IPv6 route from the kernel. */
+int
+kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
+ int index, int flags, int table)
+{
+ return kernel_ioctl_ipv6 (SIOCDELRT, dest, gate, index, flags);
+}
+#endif /* HAVE_IPV6 */
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
new file mode 100644
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 <zebra.h>
+
+/* Hack for GNU libc version 2. */
+#ifndef MSG_TRUNC
+#define MSG_TRUNC 0x20
+#endif /* MSG_TRUNC */
+
+#include "linklist.h"
+#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "connected.h"
+#include "table.h"
+#include "rib.h"
+
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/interface.h"
+#include "zebra/debug.h"
+
+/* Socket interface to kernel */
+struct nlsock
+{
+ int sock;
+ int seq;
+ struct sockaddr_nl snl;
+ char *name;
+} netlink = { -1, 0, {0}, "netlink-listen" }, /* kernel messages */
+ netlink_cmd = { -1, 0, {0}, "netlink-cmd" }, /* command channel */
+ netlink_addr = {-1, 0, {0}, "netlink-addr" }; /* address channel */
+
+struct message nlmsg_str[] =
+{
+ {RTM_NEWROUTE, "RTM_NEWROUTE"},
+ {RTM_DELROUTE, "RTM_DELROUTE"},
+ {RTM_GETROUTE, "RTM_GETROUTE"},
+ {RTM_NEWLINK, "RTM_NEWLINK"},
+ {RTM_DELLINK, "RTM_DELLINK"},
+ {RTM_GETLINK, "RTM_GETLINK"},
+ {RTM_NEWADDR, "RTM_NEWADDR"},
+ {RTM_DELADDR, "RTM_DELADDR"},
+ {RTM_GETADDR, "RTM_GETADDR"},
+ {0, NULL}
+};
+
+extern int rtm_table_default;
+
+/* Make socket for Linux netlink interface. */
+static int
+netlink_socket (struct nlsock *nl, unsigned long groups)
+{
+ int ret;
+ struct sockaddr_nl snl;
+ int sock;
+ int namelen;
+
+ sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock < 0)
+ {
+ zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
+ strerror (errno));
+ return -1;
+ }
+
+ ret = fcntl (sock, F_SETFL, O_NONBLOCK);
+ if (ret < 0)
+ {
+ zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", nl->name,
+ strerror (errno));
+ close (sock);
+ return -1;
+ }
+
+ memset (&snl, 0, sizeof snl);
+ snl.nl_family = AF_NETLINK;
+ snl.nl_groups = groups;
+
+ /* Bind the socket to the netlink structure for anything. */
+ ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
+ if (ret < 0)
+ {
+ zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
+ nl->name, snl.nl_groups, strerror (errno));
+ close (sock);
+ return -1;
+ }
+
+ /* multiple netlink sockets will have different nl_pid */
+ namelen = sizeof snl;
+ ret = getsockname (sock, (struct sockaddr *) &snl, &namelen);
+ if (ret < 0 || namelen != sizeof snl)
+ {
+ zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
+ strerror (errno));
+ close (sock);
+ return -1;
+ }
+
+ nl->snl = snl;
+ nl->sock = sock;
+ return ret;
+}
+
+/* Get type specified information from netlink. */
+static int
+netlink_request (int family, int type, struct nlsock *nl)
+{
+ int ret;
+ struct sockaddr_nl snl;
+
+ struct
+ {
+ struct nlmsghdr nlh;
+ struct rtgenmsg g;
+ } req;
+
+
+ /* Check netlink socket. */
+ if (nl->sock < 0)
+ {
+ zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
+ return -1;
+ }
+
+ memset (&snl, 0, sizeof snl);
+ snl.nl_family = AF_NETLINK;
+
+ req.nlh.nlmsg_len = sizeof req;
+ req.nlh.nlmsg_type = type;
+ req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+ req.nlh.nlmsg_pid = 0;
+ req.nlh.nlmsg_seq = ++nl->seq;
+ req.g.rtgen_family = family;
+
+ ret = sendto (nl->sock, (void*) &req, sizeof req, 0,
+ (struct sockaddr*) &snl, sizeof snl);
+ if (ret < 0)
+ {
+ zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name, strerror (errno));
+ return -1;
+ }
+ return 0;
+}
+
+/* Receive message from netlink interface and pass those information
+ to the given function. */
+static int
+netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
+ struct nlsock *nl)
+{
+ int status;
+ int ret = 0;
+ int error;
+
+ while (1)
+ {
+ char buf[4096];
+ struct iovec iov = { buf, sizeof buf };
+ struct sockaddr_nl snl;
+ struct msghdr msg = { (void*)&snl, sizeof snl, &iov, 1, NULL, 0, 0};
+ struct nlmsghdr *h;
+
+ status = recvmsg (nl->sock, &msg, 0);
+
+ if (status < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ break;
+ zlog (NULL, LOG_ERR, "%s recvmsg overrun", nl->name);
+ continue;
+ }
+
+ if (status == 0)
+ {
+ zlog (NULL, LOG_ERR, "%s EOF", nl->name);
+ return -1;
+ }
+
+ if (msg.msg_namelen != sizeof snl)
+ {
+ zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
+ nl->name, msg.msg_namelen);
+ return -1;
+ }
+
+ for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, status);
+ h = NLMSG_NEXT (h, status))
+ {
+ /* Finish of reading. */
+ if (h->nlmsg_type == NLMSG_DONE)
+ return ret;
+
+ /* Error handling. */
+ if (h->nlmsg_type == NLMSG_ERROR)
+ {
+ struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
+
+ /* If the error field is zero, then this is an ACK */
+ if (err->error == 0)
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ {
+ zlog_info("%s: %s ACK: type=%s(%u), seq=%u, pid=%d",
+ __FUNCTION__, nl->name,
+ lookup (nlmsg_str, err->msg.nlmsg_type),
+ err->msg.nlmsg_type, err->msg.nlmsg_seq,
+ err->msg.nlmsg_pid);
+ }
+
+ /* return if not a multipart message, otherwise continue */
+ if(!(h->nlmsg_flags & NLM_F_MULTI))
+ {
+ return 0;
+ }
+ continue;
+ }
+
+ if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
+ {
+ zlog (NULL, LOG_ERR, "%s error: message truncated",
+ nl->name);
+ return -1;
+ }
+ zlog (NULL, LOG_ERR, "%s error: %s, type=%s(%u), seq=%u, pid=%d",
+ nl->name, strerror (-err->error),
+ lookup (nlmsg_str, err->msg.nlmsg_type),
+ err->msg.nlmsg_type, err->msg.nlmsg_seq,
+ err->msg.nlmsg_pid);
+ /*
+ ret = -1;
+ continue;
+ */
+ return -1;
+ }
+
+ /* OK we got netlink message. */
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_info ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%d",
+ nl->name,
+ lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
+ h->nlmsg_seq, h->nlmsg_pid);
+
+ /* skip unsolicited messages originating from command socket */
+ if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_info ("netlink_parse_info: %s packet comes from %s",
+ nl->name, netlink_cmd.name);
+ continue;
+ }
+
+ error = (*filter) (&snl, h);
+ if (error < 0)
+ {
+ zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
+ ret = error;
+ }
+ }
+
+ /* After error care. */
+ if (msg.msg_flags & MSG_TRUNC)
+ {
+ zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
+ continue;
+ }
+ if (status)
+ {
+ zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
+ status);
+ return -1;
+ }
+ }
+ return ret;
+}
+
+/* Utility function for parse rtattr. */
+static void
+netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta, int len)
+{
+ while (RTA_OK(rta, len))
+ {
+ if (rta->rta_type <= max)
+ tb[rta->rta_type] = rta;
+ rta = RTA_NEXT(rta,len);
+ }
+}
+
+/* Called from interface_lookup_netlink(). This function is only used
+ during bootstrap. */
+int
+netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+ int len;
+ struct ifinfomsg *ifi;
+ struct rtattr *tb[IFLA_MAX + 1];
+ struct interface *ifp;
+ char *name;
+ int i;
+
+ ifi = NLMSG_DATA (h);
+
+ if (h->nlmsg_type != RTM_NEWLINK)
+ return 0;
+
+ len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
+ if (len < 0)
+ return -1;
+
+ /* Looking up interface name. */
+ memset (tb, 0, sizeof tb);
+ netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
+ if (tb[IFLA_IFNAME] == NULL)
+ return -1;
+ name = (char *)RTA_DATA(tb[IFLA_IFNAME]);
+
+ /* Add interface. */
+ ifp = if_get_by_name (name);
+
+ ifp->ifindex = ifi->ifi_index;
+ ifp->flags = ifi->ifi_flags & 0x0000fffff;
+ ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]);
+ ifp->metric = 1;
+
+ /* Hardware type and address. */
+ ifp->hw_type = ifi->ifi_type;
+
+ if (tb[IFLA_ADDRESS])
+ {
+ int hw_addr_len;
+
+ hw_addr_len = RTA_PAYLOAD(tb[IFLA_ADDRESS]);
+
+ if (hw_addr_len > INTERFACE_HWADDR_MAX)
+ zlog_warn ("Hardware address is too large: %d", hw_addr_len);
+ else
+ {
+ ifp->hw_addr_len = hw_addr_len;
+ memcpy (ifp->hw_addr, RTA_DATA(tb[IFLA_ADDRESS]), hw_addr_len);
+
+ for (i = 0; i < hw_addr_len; i++)
+ if (ifp->hw_addr[i] != 0)
+ break;
+
+ if (i == hw_addr_len)
+ ifp->hw_addr_len = 0;
+ else
+ ifp->hw_addr_len = hw_addr_len;
+ }
+ }
+
+ if_add_update (ifp);
+
+ return 0;
+}
+
+/* Lookup interface IPv4/IPv6 address. */
+int
+netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+ int len;
+ struct ifaddrmsg *ifa;
+ struct rtattr *tb [IFA_MAX + 1];
+ struct interface *ifp;
+ void *addr = NULL;
+ void *broad = NULL;
+ u_char flags = 0;
+ char *label = NULL;
+
+ ifa = NLMSG_DATA (h);
+
+ if (ifa->ifa_family != AF_INET
+#ifdef HAVE_IPV6
+ && ifa->ifa_family != AF_INET6
+#endif /* HAVE_IPV6 */
+ )
+ return 0;
+
+ if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
+ return 0;
+
+ len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifaddrmsg));
+ if (len < 0)
+ return -1;
+
+ memset (tb, 0, sizeof tb);
+ netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
+
+ ifp = if_lookup_by_index (ifa->ifa_index);
+ if (ifp == NULL)
+ {
+ zlog_err ("netlink_interface_addr can't find interface by index %d",
+ ifa->ifa_index);
+ return -1;
+ }
+
+ if (tb[IFA_ADDRESS] == NULL)
+ tb[IFA_ADDRESS] = tb[IFA_LOCAL];
+
+ if (ifp->flags & IFF_POINTOPOINT)
+ {
+ if (tb[IFA_LOCAL])
+ {
+ addr = RTA_DATA (tb[IFA_LOCAL]);
+ if (tb[IFA_ADDRESS])
+ broad = RTA_DATA (tb[IFA_ADDRESS]);
+ else
+ broad = NULL;
+ }
+ else
+ {
+ if (tb[IFA_ADDRESS])
+ addr = RTA_DATA (tb[IFA_ADDRESS]);
+ else
+ addr = NULL;
+ }
+ }
+ else
+ {
+ if (tb[IFA_ADDRESS])
+ addr = RTA_DATA (tb[IFA_ADDRESS]);
+ else
+ addr = NULL;
+
+ if (tb[IFA_BROADCAST])
+ broad = RTA_DATA(tb[IFA_BROADCAST]);
+ else
+ broad = NULL;
+ }
+
+ /* Flags. */
+ if (ifa->ifa_flags & IFA_F_SECONDARY)
+ SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
+
+ /* Label */
+ if (tb[IFA_LABEL])
+ label = (char *) RTA_DATA (tb[IFA_LABEL]);
+
+ if (ifp && label && strcmp (ifp->name, label) == 0)
+ label = NULL;
+
+ /* Register interface address to the interface. */
+ if (ifa->ifa_family == AF_INET)
+ {
+ if (h->nlmsg_type == RTM_NEWADDR)
+ connected_add_ipv4 (ifp, flags,
+ (struct in_addr *) addr, ifa->ifa_prefixlen,
+ (struct in_addr *) broad, label);
+ else
+ connected_delete_ipv4 (ifp, flags,
+ (struct in_addr *) addr, ifa->ifa_prefixlen,
+ (struct in_addr *) broad, label);
+ }
+#ifdef HAVE_IPV6
+ if (ifa->ifa_family == AF_INET6)
+ {
+ if (h->nlmsg_type == RTM_NEWADDR)
+ connected_add_ipv6 (ifp,
+ (struct in6_addr *) addr, ifa->ifa_prefixlen,
+ (struct in6_addr *) broad);
+ else
+ connected_delete_ipv6 (ifp,
+ (struct in6_addr *) addr, ifa->ifa_prefixlen,
+ (struct in6_addr *) broad);
+ }
+#endif /* HAVE_IPV6*/
+
+ return 0;
+}
+
+/* Looking up routing table by netlink interface. */
+int
+netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+ int len;
+ struct rtmsg *rtm;
+ struct rtattr *tb [RTA_MAX + 1];
+ u_char flags = 0;
+
+ char anyaddr[16] = {0};
+
+ int index;
+ int table;
+ void *dest;
+ void *gate;
+
+ rtm = NLMSG_DATA (h);
+
+ if (h->nlmsg_type != RTM_NEWROUTE)
+ return 0;
+ if (rtm->rtm_type != RTN_UNICAST)
+ return 0;
+
+ table = rtm->rtm_table;
+#if 0 /* we weed them out later in rib_weed_tables () */
+ if (table != RT_TABLE_MAIN && table != rtm_table_default)
+ return 0;
+#endif
+
+ len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct rtmsg));
+ if (len < 0)
+ return -1;
+
+ memset (tb, 0, sizeof tb);
+ netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
+
+ if (rtm->rtm_flags & RTM_F_CLONED)
+ return 0;
+ if (rtm->rtm_protocol == RTPROT_REDIRECT)
+ return 0;
+ if (rtm->rtm_protocol == RTPROT_KERNEL)
+ return 0;
+
+ if (rtm->rtm_src_len != 0)
+ return 0;
+
+ /* Route which inserted by Zebra. */
+ if (rtm->rtm_protocol == RTPROT_ZEBRA)
+ flags |= ZEBRA_FLAG_SELFROUTE;
+
+ index = 0;
+ dest = NULL;
+ gate = NULL;
+
+ if (tb[RTA_OIF])
+ index = *(int *) RTA_DATA (tb[RTA_OIF]);
+
+ if (tb[RTA_DST])
+ dest = RTA_DATA (tb[RTA_DST]);
+ else
+ dest = anyaddr;
+
+ /* Multipath treatment is needed. */
+ if (tb[RTA_GATEWAY])
+ gate = RTA_DATA (tb[RTA_GATEWAY]);
+
+ if (rtm->rtm_family == AF_INET)
+ {
+ struct prefix_ipv4 p;
+ p.family = AF_INET;
+ memcpy (&p.prefix, dest, 4);
+ p.prefixlen = rtm->rtm_dst_len;
+
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, 0, 0);
+ }
+#ifdef HAVE_IPV6
+ if (rtm->rtm_family == AF_INET6)
+ {
+ struct prefix_ipv6 p;
+ p.family = AF_INET6;
+ memcpy (&p.prefix, dest, 16);
+ p.prefixlen = rtm->rtm_dst_len;
+
+ rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table);
+ }
+#endif /* HAVE_IPV6 */
+
+ return 0;
+}
+
+struct message rtproto_str [] =
+{
+ {RTPROT_REDIRECT, "redirect"},
+ {RTPROT_KERNEL, "kernel"},
+ {RTPROT_BOOT, "boot"},
+ {RTPROT_STATIC, "static"},
+ {RTPROT_GATED, "GateD"},
+ {RTPROT_RA, "router advertisement"},
+ {RTPROT_MRT, "MRT"},
+ {RTPROT_ZEBRA, "Zebra"},
+#ifdef RTPROT_BIRD
+ {RTPROT_BIRD, "BIRD"},
+#endif /* RTPROT_BIRD */
+ {0, NULL}
+};
+
+/* Routing information change from the kernel. */
+int
+netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+ int len;
+ struct rtmsg *rtm;
+ struct rtattr *tb [RTA_MAX + 1];
+
+ char anyaddr[16] = {0};
+
+ int index;
+ int table;
+ void *dest;
+ void *gate;
+
+ rtm = NLMSG_DATA (h);
+
+ if (! (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
+ {
+ /* If this is not route add/delete message print warning. */
+ zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
+ return 0;
+ }
+
+ /* Connected route. */
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_info ("%s %s %s proto %s",
+ h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
+ rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
+ rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
+ lookup (rtproto_str, rtm->rtm_protocol));
+
+ if (rtm->rtm_type != RTN_UNICAST)
+ {
+ return 0;
+ }
+
+ table = rtm->rtm_table;
+ if (table != RT_TABLE_MAIN && table != rtm_table_default)
+ {
+ return 0;
+ }
+
+ len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct rtmsg));
+ if (len < 0)
+ return -1;
+
+ memset (tb, 0, sizeof tb);
+ netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
+
+ if (rtm->rtm_flags & RTM_F_CLONED)
+ return 0;
+ if (rtm->rtm_protocol == RTPROT_REDIRECT)
+ return 0;
+ if (rtm->rtm_protocol == RTPROT_KERNEL)
+ return 0;
+
+ if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
+ return 0;
+
+ if (rtm->rtm_src_len != 0)
+ {
+ zlog_warn ("netlink_route_change(): no src len");
+ return 0;
+ }
+
+ index = 0;
+ dest = NULL;
+ gate = NULL;
+
+ if (tb[RTA_OIF])
+ index = *(int *) RTA_DATA (tb[RTA_OIF]);
+
+ if (tb[RTA_DST])
+ dest = RTA_DATA (tb[RTA_DST]);
+ else
+ dest = anyaddr;
+
+ if (tb[RTA_GATEWAY])
+ gate = RTA_DATA (tb[RTA_GATEWAY]);
+
+ if (rtm->rtm_family == AF_INET)
+ {
+ struct prefix_ipv4 p;
+ p.family = AF_INET;
+ memcpy (&p.prefix, dest, 4);
+ p.prefixlen = rtm->rtm_dst_len;
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ {
+ if (h->nlmsg_type == RTM_NEWROUTE)
+ zlog_info ("RTM_NEWROUTE %s/%d",
+ inet_ntoa (p.prefix), p.prefixlen);
+ else
+ zlog_info ("RTM_DELROUTE %s/%d",
+ inet_ntoa (p.prefix), p.prefixlen);
+ }
+
+ if (h->nlmsg_type == RTM_NEWROUTE)
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
+ else
+ rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
+ }
+
+#ifdef HAVE_IPV6
+ if (rtm->rtm_family == AF_INET6)
+ {
+ struct prefix_ipv6 p;
+ char buf[BUFSIZ];
+
+ p.family = AF_INET6;
+ memcpy (&p.prefix, dest, 16);
+ p.prefixlen = rtm->rtm_dst_len;
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ {
+ if (h->nlmsg_type == RTM_NEWROUTE)
+ zlog_info ("RTM_NEWROUTE %s/%d",
+ inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
+ p.prefixlen);
+ else
+ zlog_info ("RTM_DELROUTE %s/%d",
+ inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
+ p.prefixlen);
+ }
+
+ if (h->nlmsg_type == RTM_NEWROUTE)
+ rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
+ else
+ rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
+ }
+#endif /* HAVE_IPV6 */
+
+ return 0;
+}
+
+int
+netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+ int len;
+ struct ifinfomsg *ifi;
+ struct rtattr *tb [IFLA_MAX + 1];
+ struct interface *ifp;
+ char *name;
+
+ ifi = NLMSG_DATA (h);
+
+ if (! (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
+ {
+ /* If this is not link add/delete message so print warning. */
+ zlog_warn ("netlink_link_change: wrong kernel message %d\n",
+ h->nlmsg_type);
+ return 0;
+ }
+
+ len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
+ if (len < 0)
+ return -1;
+
+ /* Looking up interface name. */
+ memset (tb, 0, sizeof tb);
+ netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
+ if (tb[IFLA_IFNAME] == NULL)
+ return -1;
+ name = (char *)RTA_DATA(tb[IFLA_IFNAME]);
+
+ /* Add interface. */
+ if (h->nlmsg_type == RTM_NEWLINK)
+ {
+ ifp = if_lookup_by_name (name);
+
+ if (ifp == NULL || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+ {
+ if (ifp == NULL)
+ ifp = if_get_by_name (name);
+
+ ifp->ifindex = ifi->ifi_index;
+ ifp->flags = ifi->ifi_flags & 0x0000fffff;
+ ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]);
+ ifp->metric = 1;
+
+ /* If new link is added. */
+ if_add_update(ifp);
+ }
+ else
+ {
+ /* Interface status change. */
+ ifp->ifindex = ifi->ifi_index;
+ ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]);
+ ifp->metric = 1;
+
+ if (if_is_up (ifp))
+ {
+ ifp->flags = ifi->ifi_flags & 0x0000fffff;
+ if (! if_is_up (ifp))
+ if_down (ifp);
+ }
+ else
+ {
+ ifp->flags = ifi->ifi_flags & 0x0000fffff;
+ if (if_is_up (ifp))
+ if_up (ifp);
+ }
+ }
+ }
+ else
+ {
+ /* RTM_DELLINK. */
+ ifp = if_lookup_by_name (name);
+
+ if (ifp == NULL)
+ {
+ zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
+ name);
+ return 0;
+ }
+
+ if_delete_update (ifp);
+ }
+
+ return 0;
+}
+
+int
+netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+ switch (h->nlmsg_type)
+ {
+ case RTM_NEWROUTE:
+ return netlink_route_change (snl, h);
+ break;
+ case RTM_DELROUTE:
+ return netlink_route_change (snl, h);
+ break;
+ case RTM_NEWLINK:
+ return netlink_link_change (snl, h);
+ break;
+ case RTM_DELLINK:
+ return netlink_link_change (snl, h);
+ break;
+ case RTM_NEWADDR:
+ return netlink_interface_addr (snl, h);
+ break;
+ case RTM_DELADDR:
+ return netlink_interface_addr (snl, h);
+ break;
+ default:
+ zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
+ break;
+ }
+ return 0;
+}
+
+/* Interface lookup by netlink socket. */
+int
+interface_lookup_netlink ()
+{
+ int ret;
+
+ /* Get interface information. */
+ ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
+ if (ret < 0)
+ return ret;
+ ret = netlink_parse_info (netlink_interface, &netlink_cmd);
+ if (ret < 0)
+ return ret;
+
+ /* Get IPv4 address of the interfaces. */
+ ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
+ if (ret < 0)
+ return ret;
+ ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
+ if (ret < 0)
+ return ret;
+
+#ifdef HAVE_IPV6
+ /* Get IPv6 address of the interfaces. */
+ ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
+ if (ret < 0)
+ return ret;
+ ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
+ if (ret < 0)
+ return ret;
+#endif /* HAVE_IPV6 */
+
+ return 0;
+}
+
+/* Routing table read function using netlink interface. Only called
+ bootstrap time. */
+int
+netlink_route_read ()
+{
+ int ret;
+
+ /* Get IPv4 routing table. */
+ ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
+ if (ret < 0)
+ return ret;
+ ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
+ if (ret < 0)
+ return ret;
+
+#ifdef HAVE_IPV6
+ /* Get IPv6 routing table. */
+ ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
+ if (ret < 0)
+ return ret;
+ ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
+ if (ret < 0)
+ return ret;
+#endif /* HAVE_IPV6 */
+
+ return 0;
+}
+
+/* Utility function comes from iproute2.
+ Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
+int
+addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
+{
+ int len;
+ struct rtattr *rta;
+
+ len = RTA_LENGTH(alen);
+
+ if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
+ return -1;
+
+ rta = (struct rtattr*) (((char*)n) + NLMSG_ALIGN (n->nlmsg_len));
+ rta->rta_type = type;
+ rta->rta_len = len;
+ memcpy (RTA_DATA(rta), data, alen);
+ n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
+
+ return 0;
+}
+
+int
+rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
+{
+ int len;
+ struct rtattr *subrta;
+
+ len = RTA_LENGTH(alen);
+
+ if (RTA_ALIGN(rta->rta_len) + len > maxlen)
+ return -1;
+
+ subrta = (struct rtattr*) (((char*)rta) + RTA_ALIGN (rta->rta_len));
+ subrta->rta_type = type;
+ subrta->rta_len = len;
+ memcpy (RTA_DATA(subrta), data, alen);
+ rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
+
+ return 0;
+}
+
+/* Utility function comes from iproute2.
+ Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
+int
+addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
+{
+ int len;
+ struct rtattr *rta;
+
+ len = RTA_LENGTH(4);
+
+ if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
+ return -1;
+
+ rta = (struct rtattr*) (((char*)n) + NLMSG_ALIGN (n->nlmsg_len));
+ rta->rta_type = type;
+ rta->rta_len = len;
+ memcpy (RTA_DATA(rta), &data, 4);
+ n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
+
+ return 0;
+}
+
+static int
+netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+ zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
+ return 0;
+}
+
+/* sendmsg() to netlink socket then recvmsg(). */
+int
+netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
+{
+ int status;
+ struct sockaddr_nl snl;
+ struct iovec iov = { (void*) n, n->nlmsg_len };
+ struct msghdr msg = {(void*) &snl, sizeof snl, &iov, 1, NULL, 0, 0};
+ int flags = 0;
+
+ memset (&snl, 0, sizeof snl);
+ snl.nl_family = AF_NETLINK;
+
+ n->nlmsg_seq = ++netlink_cmd.seq;
+
+ /* Request an acknowledgement by setting NLM_F_ACK */
+ n->nlmsg_flags |= NLM_F_ACK;
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_info ("netlink_talk: %s type %s(%u), seq=%u", netlink_cmd.name,
+ lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
+ n->nlmsg_seq);
+
+ /* Send message to netlink interface. */
+ status = sendmsg (nl->sock, &msg, 0);
+ if (status < 0)
+ {
+ zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
+ strerror (errno));
+ return -1;
+ }
+
+ /*
+ * Change socket flags for blocking I/O.
+ * This ensures we wait for a reply in netlink_parse_info().
+ */
+ if((flags = fcntl(nl->sock, F_GETFL, 0)) < 0)
+ {
+ zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s",
+ __FUNCTION__, __LINE__, strerror (errno));
+ }
+ flags &= ~O_NONBLOCK;
+ if(fcntl(nl->sock, F_SETFL, flags) < 0)
+ {
+ zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
+ __FUNCTION__, __LINE__, strerror (errno));
+ }
+
+ /*
+ * Get reply from netlink socket.
+ * The reply should either be an acknowlegement or an error.
+ */
+ status = netlink_parse_info (netlink_talk_filter, nl);
+
+ /* Restore socket flags for nonblocking I/O */
+ flags |= O_NONBLOCK;
+ if(fcntl(nl->sock, F_SETFL, flags) < 0)
+ {
+ zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
+ __FUNCTION__, __LINE__, strerror (errno));
+ }
+
+ return status;
+}
+
+/* Routing table change via netlink interface. */
+int
+netlink_route (int cmd, int family, void *dest, int length, void *gate,
+ int index, int zebra_flags, int table)
+{
+ int ret;
+ int bytelen;
+ struct sockaddr_nl snl;
+ int discard;
+
+ struct
+ {
+ struct nlmsghdr n;
+ struct rtmsg r;
+ char buf[1024];
+ } req;
+
+ memset (&req, 0, sizeof req);
+
+ bytelen = (family == AF_INET ? 4 : 16);
+
+ req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
+ req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+ req.n.nlmsg_type = cmd;
+ req.r.rtm_family = family;
+ req.r.rtm_table = table;
+ req.r.rtm_dst_len = length;
+
+ if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
+ discard = 1;
+ else
+ discard = 0;
+
+ if (cmd == RTM_NEWROUTE)
+ {
+ req.r.rtm_protocol = RTPROT_ZEBRA;
+ req.r.rtm_scope = RT_SCOPE_UNIVERSE;
+
+ if (discard)
+ req.r.rtm_type = RTN_BLACKHOLE;
+ else
+ req.r.rtm_type = RTN_UNICAST;
+ }
+
+ if (dest)
+ addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
+
+ if (! discard)
+ {
+ if (gate)
+ addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
+ if (index > 0)
+ addattr32 (&req.n, sizeof req, RTA_OIF, index);
+ }
+
+ /* Destination netlink address. */
+ memset (&snl, 0, sizeof snl);
+ snl.nl_family = AF_NETLINK;
+
+ /* Talk to netlink socket. */
+ ret = netlink_talk (&req.n, &netlink);
+ if (ret < 0)
+ return -1;
+
+ return 0;
+}
+
+/* Routing table change via netlink interface. */
+int
+netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
+ int family)
+{
+ int bytelen;
+ struct sockaddr_nl snl;
+ struct nexthop *nexthop = NULL;
+ int nexthop_num = 0;
+ struct nlsock *nl;
+ int discard;
+
+ struct
+ {
+ struct nlmsghdr n;
+ struct rtmsg r;
+ char buf[1024];
+ } req;
+
+ memset (&req, 0, sizeof req);
+
+ bytelen = (family == AF_INET ? 4 : 16);
+
+ req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
+ req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+ req.n.nlmsg_type = cmd;
+ req.r.rtm_family = family;
+ req.r.rtm_table = rib->table;
+ req.r.rtm_dst_len = p->prefixlen;
+
+ if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
+ discard = 1;
+ else
+ discard = 0;
+
+ if (cmd == RTM_NEWROUTE)
+ {
+ req.r.rtm_protocol = RTPROT_ZEBRA;
+ req.r.rtm_scope = RT_SCOPE_UNIVERSE;
+
+ if (discard)
+ req.r.rtm_type = RTN_BLACKHOLE;
+ else
+ req.r.rtm_type = RTN_UNICAST;
+ }
+
+ addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
+
+ /* Metric. */
+ addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
+
+ if (discard)
+ {
+ if (cmd == RTM_NEWROUTE)
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+ goto skip;
+ }
+
+ /* Multipath case. */
+ if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
+ {
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ {
+ if ((cmd == RTM_NEWROUTE
+ && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ || (cmd == RTM_DELROUTE
+ && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
+ {
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ {
+ if (nexthop->rtype == NEXTHOP_TYPE_IPV4
+ || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
+ addattr_l (&req.n, sizeof req, RTA_GATEWAY,
+ &nexthop->rgate.ipv4, bytelen);
+#ifdef HAVE_IPV6
+ if (nexthop->rtype == NEXTHOP_TYPE_IPV6
+ || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
+ || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
+ addattr_l (&req.n, sizeof req, RTA_GATEWAY,
+ &nexthop->rgate.ipv6, bytelen);
+#endif /* HAVE_IPV6 */
+ if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+ || nexthop->rtype == NEXTHOP_TYPE_IFNAME
+ || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
+ || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
+ || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
+ addattr32 (&req.n, sizeof req, RTA_OIF,
+ nexthop->rifindex);
+ }
+ else
+ {
+ if (nexthop->type == NEXTHOP_TYPE_IPV4
+ || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+ addattr_l (&req.n, sizeof req, RTA_GATEWAY,
+ &nexthop->gate.ipv4, bytelen);
+#ifdef HAVE_IPV6
+ if (nexthop->type == NEXTHOP_TYPE_IPV6
+ || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+ || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+ addattr_l (&req.n, sizeof req, RTA_GATEWAY,
+ &nexthop->gate.ipv6, bytelen);
+#endif /* HAVE_IPV6 */
+ if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+ || nexthop->type == NEXTHOP_TYPE_IFNAME
+ || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
+ || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
+ || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+ addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
+ }
+
+ if (cmd == RTM_NEWROUTE)
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+ nexthop_num++;
+ break;
+ }
+ }
+ }
+ else
+ {
+ char buf[1024];
+ struct rtattr *rta = (void *) buf;
+ struct rtnexthop *rtnh;
+
+ rta->rta_type = RTA_MULTIPATH;
+ rta->rta_len = RTA_LENGTH(0);
+ rtnh = RTA_DATA(rta);
+
+ nexthop_num = 0;
+ for (nexthop = rib->nexthop;
+ nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
+ nexthop = nexthop->next)
+ {
+ if ((cmd == RTM_NEWROUTE
+ && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ || (cmd == RTM_DELROUTE
+ && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
+ {
+ nexthop_num++;
+
+ rtnh->rtnh_len = sizeof (*rtnh);
+ rtnh->rtnh_flags = 0;
+ rtnh->rtnh_hops = 0;
+ rta->rta_len += rtnh->rtnh_len;
+
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ {
+ if (nexthop->rtype == NEXTHOP_TYPE_IPV4
+ || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
+ {
+ rta_addattr_l (rta, 4096, RTA_GATEWAY,
+ &nexthop->rgate.ipv4, bytelen);
+ rtnh->rtnh_len += sizeof (struct rtattr) + 4;
+ }
+#ifdef HAVE_IPV6
+ if (nexthop->rtype == NEXTHOP_TYPE_IPV6
+ || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
+ || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
+ rta_addattr_l (rta, 4096, RTA_GATEWAY,
+ &nexthop->rgate.ipv6, bytelen);
+#endif /* HAVE_IPV6 */
+ /* ifindex */
+ if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+ || nexthop->rtype == NEXTHOP_TYPE_IFNAME
+ || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
+ || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
+ || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
+ rtnh->rtnh_ifindex = nexthop->rifindex;
+ else
+ rtnh->rtnh_ifindex = 0;
+ }
+ else
+ {
+ if (nexthop->type == NEXTHOP_TYPE_IPV4
+ || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+ {
+ rta_addattr_l (rta, 4096, RTA_GATEWAY,
+ &nexthop->gate.ipv4, bytelen);
+ rtnh->rtnh_len += sizeof (struct rtattr) + 4;
+ }
+#ifdef HAVE_IPV6
+ if (nexthop->type == NEXTHOP_TYPE_IPV6
+ || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+ || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+ rta_addattr_l (rta, 4096, RTA_GATEWAY,
+ &nexthop->gate.ipv6, bytelen);
+#endif /* HAVE_IPV6 */
+ /* ifindex */
+ if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+ || nexthop->type == NEXTHOP_TYPE_IFNAME
+ || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
+ || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+ || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+ rtnh->rtnh_ifindex = nexthop->ifindex;
+ else
+ rtnh->rtnh_ifindex = 0;
+ }
+ rtnh = RTNH_NEXT(rtnh);
+
+ if (cmd == RTM_NEWROUTE)
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+ }
+ }
+
+ if (rta->rta_len > RTA_LENGTH (0))
+ addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA(rta),
+ RTA_PAYLOAD(rta));
+ }
+
+ /* If there is no useful nexthop then return. */
+ if (nexthop_num == 0)
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_info ("netlink_route_multipath(): No useful nexthop.");
+ return 0;
+ }
+
+ skip:
+
+ /* Destination netlink address. */
+ memset (&snl, 0, sizeof snl);
+ snl.nl_family = AF_NETLINK;
+
+ if (family == AF_INET)
+ nl = &netlink_cmd;
+ else
+ nl = &netlink;
+
+ /* Talk to netlink socket. */
+ return netlink_talk (&req.n, nl);
+}
+
+int
+kernel_add_ipv4 (struct prefix *p, struct rib *rib)
+{
+ return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
+}
+
+int
+kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
+{
+ return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
+}
+
+#ifdef HAVE_IPV6
+int
+kernel_add_ipv6 (struct prefix *p, struct rib *rib)
+{
+ return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
+}
+
+int
+kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
+{
+ return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
+}
+
+/* Delete IPv6 route from the kernel. */
+int
+kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
+ int index, int flags, int table)
+{
+ return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix, dest->prefixlen,
+ gate, index, flags, table);
+}
+#endif /* HAVE_IPV6 */
+
+/* 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 <zebra.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "sockunion.h"
+#include "log.h"
+#include "str.h"
+
+#include "zebra/debug.h"
+#include "zebra/rib.h"
+
+int
+rtm_write (int message,
+ union sockunion *dest,
+ union sockunion *mask,
+ union sockunion *gate,
+ unsigned int index,
+ int zebra_flags,
+ int metric);
+
+/* Adjust netmask socket length. Return value is a adjusted sin_len
+ value. */
+int
+sin_masklen (struct in_addr mask)
+{
+ char *p, *lim;
+ int len;
+ struct sockaddr_in sin;
+
+ if (mask.s_addr == 0)
+ return sizeof (long);
+
+ sin.sin_addr = mask;
+ len = sizeof (struct sockaddr_in);
+
+ lim = (char *) &sin.sin_addr;
+ p = lim + sizeof (sin.sin_addr);
+
+ while (*--p == 0 && p >= lim)
+ len--;
+ return len;
+}
+
+/* Interface between zebra message and rtm message. */
+int
+kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family)
+
+{
+ struct sockaddr_in *mask;
+ struct sockaddr_in sin_dest, sin_mask, sin_gate;
+ struct nexthop *nexthop;
+ int nexthop_num = 0;
+ unsigned int ifindex = 0;
+ int gate = 0;
+ int error;
+
+ memset (&sin_dest, 0, sizeof (struct sockaddr_in));
+ sin_dest.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+ sin_dest.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+ sin_dest.sin_addr = p->u.prefix4;
+
+ memset (&sin_mask, 0, sizeof (struct sockaddr_in));
+
+ memset (&sin_gate, 0, sizeof (struct sockaddr_in));
+ sin_gate.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+ sin_gate.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+
+ /* Make gateway. */
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ {
+ gate = 0;
+
+ if ((cmd == RTM_ADD
+ && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ || (cmd == RTM_DELETE
+#if 0
+ && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+#endif
+ ))
+ {
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ {
+ if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
+ nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
+ {
+ sin_gate.sin_addr = nexthop->rgate.ipv4;
+ gate = 1;
+ }
+ if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+ || nexthop->rtype == NEXTHOP_TYPE_IFNAME
+ || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
+ ifindex = nexthop->rifindex;
+ }
+ else
+ {
+ if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
+ nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+ {
+ sin_gate.sin_addr = nexthop->gate.ipv4;
+ gate = 1;
+ }
+ if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+ || nexthop->type == NEXTHOP_TYPE_IFNAME
+ || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+ ifindex = nexthop->ifindex;
+ if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
+ {
+ struct in_addr loopback;
+
+ loopback.s_addr = htonl (INADDR_LOOPBACK);
+ sin_gate.sin_addr = loopback;
+ gate = 1;
+ }
+ }
+
+ if (cmd == RTM_ADD)
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+ if (gate && p->prefixlen == 32)
+ mask = NULL;
+ else
+ {
+ masklen2ip (p->prefixlen, &sin_mask.sin_addr);
+ sin_mask.sin_family = AF_UNSPEC;
+#ifdef HAVE_SIN_LEN
+ sin_mask.sin_len = sin_masklen (sin_mask.sin_addr);
+#endif /* HAVE_SIN_LEN */
+ mask = &sin_mask;
+ }
+ }
+
+ error = rtm_write (cmd,
+ (union sockunion *)&sin_dest,
+ (union sockunion *)mask,
+ gate ? (union sockunion *)&sin_gate : NULL,
+ ifindex,
+ rib->flags,
+ rib->metric);
+
+#if 0
+ if (error)
+ {
+ zlog_info ("kernel_rtm_ipv4(): nexthop %d add error=%d.",
+ nexthop_num, error);
+ }
+#endif
+
+ nexthop_num++;
+ }
+
+ /* If there is no useful nexthop then return. */
+ if (nexthop_num == 0)
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_info ("kernel_rtm_ipv4(): No useful nexthop.");
+ return 0;
+ }
+
+ return 0; /*XXX*/
+}
+
+int
+kernel_add_ipv4 (struct prefix *p, struct rib *rib)
+{
+ return kernel_rtm_ipv4 (RTM_ADD, p, rib, AF_INET);
+}
+
+int
+kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
+{
+ return kernel_rtm_ipv4 (RTM_DELETE, p, rib, AF_INET);
+}
+
+#ifdef HAVE_IPV6
+
+/* Calculate sin6_len value for netmask socket value. */
+int
+sin6_masklen (struct in6_addr mask)
+{
+ struct sockaddr_in6 sin6;
+ char *p, *lim;
+ int len;
+
+#if defined (INRIA)
+ if (IN_ANYADDR6 (mask))
+ return sizeof (long);
+#else /* ! INRIA */
+ if (IN6_IS_ADDR_UNSPECIFIED (&mask))
+ return sizeof (long);
+#endif /* ! INRIA */
+
+ sin6.sin6_addr = mask;
+ len = sizeof (struct sockaddr_in6);
+
+ lim = (char *) & sin6.sin6_addr;
+ p = lim + sizeof (sin6.sin6_addr);
+
+ while (*--p == 0 && p >= lim)
+ len--;
+
+ return len;
+}
+
+/* Interface between zebra message and rtm message. */
+int
+kernel_rtm_ipv6 (int message, struct prefix_ipv6 *dest,
+ struct in6_addr *gate, int index, int flags)
+{
+ struct sockaddr_in6 *mask;
+ struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
+
+ memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
+ sin_dest.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+ sin_dest.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* SIN6_LEN */
+
+ memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
+
+ memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
+ sin_gate.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+ sin_gate.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* SIN6_LEN */
+
+ sin_dest.sin6_addr = dest->prefix;
+
+ if (gate)
+ memcpy (&sin_gate.sin6_addr, gate, sizeof (struct in6_addr));
+
+ /* Under kame set interface index to link local address. */
+#ifdef KAME
+
+#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
+ do { \
+ (a).s6_addr[2] = ((i) >> 8) & 0xff; \
+ (a).s6_addr[3] = (i) & 0xff; \
+ } while (0)
+
+ if (gate && IN6_IS_ADDR_LINKLOCAL(gate))
+ SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, index);
+#endif /* KAME */
+
+ if (gate && dest->prefixlen == 128)
+ mask = NULL;
+ else
+ {
+ masklen2ip6 (dest->prefixlen, &sin_mask.sin6_addr);
+ sin_mask.sin6_family = AF_UNSPEC;
+#ifdef SIN6_LEN
+ sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
+#endif /* SIN6_LEN */
+ mask = &sin_mask;
+ }
+
+ return rtm_write (message,
+ (union sockunion *) &sin_dest,
+ (union sockunion *) mask,
+ gate ? (union sockunion *)&sin_gate : NULL,
+ index,
+ flags,
+ 0);
+}
+
+/* Interface between zebra message and rtm message. */
+int
+kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib,
+ int family)
+{
+ struct sockaddr_in6 *mask;
+ struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
+ struct nexthop *nexthop;
+ int nexthop_num = 0;
+ unsigned int ifindex = 0;
+ int gate = 0;
+ int error;
+
+ memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
+ sin_dest.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+ sin_dest.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* SIN6_LEN */
+ sin_dest.sin6_addr = p->u.prefix6;
+
+ memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
+
+ memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
+ sin_gate.sin6_family = AF_INET6;
+#ifdef HAVE_SIN_LEN
+ sin_gate.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* HAVE_SIN_LEN */
+
+ /* Make gateway. */
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ {
+ gate = 0;
+
+ if ((cmd == RTM_ADD
+ && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ || (cmd == RTM_DELETE
+#if 0
+ && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+#endif
+ ))
+ {
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ {
+ if (nexthop->rtype == NEXTHOP_TYPE_IPV6
+ || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
+ || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
+ {
+ sin_gate.sin6_addr = nexthop->rgate.ipv6;
+ gate = 1;
+ }
+ if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+ || nexthop->rtype == NEXTHOP_TYPE_IFNAME
+ || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
+ || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
+ ifindex = nexthop->rifindex;
+ }
+ else
+ {
+ if (nexthop->type == NEXTHOP_TYPE_IPV6
+ || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+ || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+ {
+ sin_gate.sin6_addr = nexthop->gate.ipv6;
+ gate = 1;
+ }
+ if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+ || nexthop->type == NEXTHOP_TYPE_IFNAME
+ || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+ || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+ ifindex = nexthop->ifindex;
+ }
+
+ if (cmd == RTM_ADD)
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+ }
+
+ /* Under kame set interface index to link local address. */
+#ifdef KAME
+
+#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
+ do { \
+ (a).s6_addr[2] = ((i) >> 8) & 0xff; \
+ (a).s6_addr[3] = (i) & 0xff; \
+ } while (0)
+
+ if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr))
+ SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, ifindex);
+#endif /* KAME */
+
+ if (gate && p->prefixlen == 128)
+ mask = NULL;
+ else
+ {
+ masklen2ip6 (p->prefixlen, &sin_mask.sin6_addr);
+ sin_mask.sin6_family = AF_UNSPEC;
+#ifdef SIN6_LEN
+ sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
+#endif /* SIN6_LEN */
+ mask = &sin_mask;
+ }
+
+ error = rtm_write (cmd,
+ (union sockunion *) &sin_dest,
+ (union sockunion *) mask,
+ gate ? (union sockunion *)&sin_gate : NULL,
+ ifindex,
+ rib->flags,
+ rib->metric);
+
+#if 0
+ if (error)
+ {
+ zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.",
+ nexthop_num, error);
+ }
+#endif
+
+ nexthop_num++;
+ }
+
+ /* If there is no useful nexthop then return. */
+ if (nexthop_num == 0)
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_info ("kernel_rtm_ipv6_multipath(): No useful nexthop.");
+ return 0;
+ }
+
+ return 0; /*XXX*/
+}
+
+int
+kernel_add_ipv6 (struct prefix *p, struct rib *rib)
+{
+ return kernel_rtm_ipv6_multipath (RTM_ADD, p, rib, AF_INET6);
+}
+
+int
+kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
+{
+ return kernel_rtm_ipv6_multipath (RTM_DELETE, p, rib, AF_INET6);
+}
+
+/* Delete IPv6 route from the kernel. */
+int
+kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
+ int index, int flags, int table)
+{
+ return kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index, flags);
+}
+#endif /* HAVE_IPV6 */
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
new file mode 100644
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 <zebra.h>
+
+#include "memory.h"
+#include "sockopt.h"
+#include "thread.h"
+#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "linklist.h"
+#include "command.h"
+
+#include "zebra/interface.h"
+#include "zebra/rtadv.h"
+#include "zebra/debug.h"
+
+#if defined (HAVE_IPV6) && defined (RTADV)
+
+/* If RFC2133 definition is used. */
+#ifndef IPV6_JOIN_GROUP
+#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
+#endif
+#ifndef IPV6_LEAVE_GROUP
+#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
+#endif
+
+#define ALLNODE "ff02::1"
+#define ALLROUTER "ff02::2"
+
+enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER, RTADV_READ};
+
+void rtadv_event (enum rtadv_event, int);
+
+int if_join_all_router (int, struct interface *);
+int if_leave_all_router (int, struct interface *);
+
+/* 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 <zebra.h>
+
+#include "prefix.h"
+#include "log.h"
+#include "if.h"
+
+#include "zebra/rib.h"
+
+#include <sys/stream.h>
+#include <sys/tihdr.h>
+
+/* Solaris defines these in both <netinet/in.h> and <inet/in.h>, sigh */
+#ifdef SUNOS_5
+#include <sys/tiuser.h>
+#ifndef T_CURRENT
+#define T_CURRENT MI_T_CURRENT
+#endif /* T_CURRENT */
+#ifndef IRE_CACHE
+#define IRE_CACHE 0x0020 /* Cached Route entry */
+#endif /* IRE_CACHE */
+#ifndef IRE_HOST_REDIRECT
+#define IRE_HOST_REDIRECT 0x0200 /* Host route entry from redirects */
+#endif /* IRE_HOST_REDIRECT */
+#ifndef IRE_CACHETABLE
+#define IRE_CACHETABLE (IRE_CACHE | IRE_BROADCAST | IRE_LOCAL | \
+ IRE_LOOPBACK)
+#endif /* IRE_CACHETABLE */
+#undef IPOPT_EOL
+#undef IPOPT_NOP
+#undef IPOPT_LSRR
+#undef IPOPT_RR
+#undef IPOPT_SSRR
+#endif /* SUNOS_5 */
+
+#include <inet/common.h>
+#include <inet/ip.h>
+#include <inet/mib2.h>
+
+/* device to read IP routing table from */
+#ifndef _PATH_GETMSG_ROUTE
+#define _PATH_GETMSG_ROUTE "/dev/ip"
+#endif /* _PATH_GETMSG_ROUTE */
+
+#define RT_BUFSIZ 8192
+
+void handle_route_entry (mib2_ipRouteEntry_t *routeEntry)
+{
+ struct prefix_ipv4 prefix;
+ struct in_addr tmpaddr, gateway;
+ u_char zebra_flags = 0;
+
+ if (routeEntry->ipRouteInfo.re_ire_type & IRE_CACHETABLE)
+ return;
+
+ if (routeEntry->ipRouteInfo.re_ire_type & IRE_HOST_REDIRECT)
+ zebra_flags |= ZEBRA_FLAG_SELFROUTE;
+
+ prefix.family = AF_INET;
+
+ tmpaddr.s_addr = routeEntry->ipRouteDest;
+ prefix.prefix = tmpaddr;
+
+ tmpaddr.s_addr = routeEntry->ipRouteMask;
+ prefix.prefixlen = ip_masklen (tmpaddr);
+
+ gateway.s_addr = routeEntry->ipRouteNextHop;
+
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &prefix,
+ &gateway, 0, 0, 0, 0);
+}
+
+void route_read ()
+{
+ char storage[RT_BUFSIZ];
+
+ struct T_optmgmt_req *TLIreq = (struct T_optmgmt_req *) storage;
+ struct T_optmgmt_ack *TLIack = (struct T_optmgmt_ack *) storage;
+ struct T_error_ack *TLIerr = (struct T_error_ack *) storage;
+
+ struct opthdr *MIB2hdr;
+
+ mib2_ipRouteEntry_t *routeEntry, *lastRouteEntry;
+
+ struct strbuf msgdata;
+ int flags, dev, retval, process;
+
+ if ((dev = open (_PATH_GETMSG_ROUTE, O_RDWR)) == -1) {
+ zlog_warn ("can't open %s: %s", _PATH_GETMSG_ROUTE,
+ strerror (errno));
+ return;
+ }
+
+ TLIreq->PRIM_type = T_OPTMGMT_REQ;
+ TLIreq->OPT_offset = sizeof (struct T_optmgmt_req);
+ TLIreq->OPT_length = sizeof (struct opthdr);
+ TLIreq->MGMT_flags = T_CURRENT;
+
+ MIB2hdr = (struct opthdr *) &TLIreq[1];
+
+ MIB2hdr->level = MIB2_IP;
+ MIB2hdr->name = 0;
+ MIB2hdr->len = 0;
+
+ msgdata.buf = storage;
+ msgdata.len = sizeof (struct T_optmgmt_req) + sizeof (struct opthdr);
+
+ flags = 0;
+
+ if (putmsg (dev, &msgdata, NULL, flags) == -1) {
+ zlog_warn ("putmsg failed: %s", strerror (errno));
+ goto exit;
+ }
+
+ MIB2hdr = (struct opthdr *) &TLIack[1];
+ msgdata.maxlen = sizeof (storage);
+
+ while (1) {
+ flags = 0;
+ retval = getmsg (dev, &msgdata, NULL, &flags);
+
+ if (retval == -1) {
+ zlog_warn ("getmsg(ctl) failed: %s", strerror (errno));
+ goto exit;
+ }
+
+ /* This is normal loop termination */
+ if (retval == 0 &&
+ msgdata.len >= sizeof (struct T_optmgmt_ack) &&
+ TLIack->PRIM_type == T_OPTMGMT_ACK &&
+ TLIack->MGMT_flags == T_SUCCESS &&
+ MIB2hdr->len == 0)
+ break;
+
+ if (msgdata.len >= sizeof (struct T_error_ack) &&
+ TLIerr->PRIM_type == T_ERROR_ACK) {
+ zlog_warn ("getmsg(ctl) returned T_ERROR_ACK: %s",
+ strerror ((TLIerr->TLI_error == TSYSERR)
+ ? TLIerr->UNIX_error : EPROTO));
+ break;
+ }
+
+ /* should dump more debugging info to the log statement,
+ like what GateD does in this instance, but not
+ critical yet. */
+ if (retval != MOREDATA ||
+ msgdata.len < sizeof (struct T_optmgmt_ack) ||
+ TLIack->PRIM_type != T_OPTMGMT_ACK ||
+ TLIack->MGMT_flags != T_SUCCESS) {
+ errno = ENOMSG;
+ zlog_warn ("getmsg(ctl) returned bizarreness");
+ break;
+ }
+
+ /* MIB2_IP_21 is the the pseudo-MIB2 ipRouteTable
+ entry, see <inet/mib2.h>. "This isn't the MIB data
+ you're looking for." */
+ process = (MIB2hdr->level == MIB2_IP &&
+ MIB2hdr->name == MIB2_IP_21) ? 1 : 0;
+
+ /* getmsg writes the data buffer out completely, not
+ to the closest smaller multiple. Unless reassembling
+ data structures across buffer boundaries is your idea
+ of a good time, set maxlen to the closest smaller
+ multiple of the size of the datastructure you're
+ retrieving. */
+ msgdata.maxlen = sizeof (storage) - (sizeof (storage)
+ % sizeof (mib2_ipRouteEntry_t));
+
+ msgdata.len = 0;
+ flags = 0;
+
+ do {
+ retval = getmsg (dev, NULL, &msgdata, &flags);
+
+ if (retval == -1) {
+ zlog_warn ("getmsg(data) failed: %s",
+ strerror (errno));
+ goto exit;
+ }
+
+ if (!(retval == 0 || retval == MOREDATA)) {
+ zlog_warn ("getmsg(data) returned %d", retval);
+ goto exit;
+ }
+
+ if (process) {
+ if (msgdata.len %
+ sizeof (mib2_ipRouteEntry_t) != 0) {
+ zlog_warn ("getmsg(data) returned "
+"msgdata.len = %d (%% sizeof (mib2_ipRouteEntry_t) != 0)", msgdata.len);
+ goto exit;
+ }
+
+ routeEntry = (mib2_ipRouteEntry_t *)
+ msgdata.buf;
+ lastRouteEntry = (mib2_ipRouteEntry_t *)
+ (msgdata.buf + msgdata.len);
+ do {
+ handle_route_entry (routeEntry);
+ } while (++routeEntry < lastRouteEntry);
+ }
+ } while (retval == MOREDATA);
+ }
+
+exit:
+ close (dev);
+}
diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c
new file mode 100644
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 <zebra.h>
+
+/* Extern from rt_netlink.c */
+void netlink_route_read ();
+
+void route_read ()
+{
+ netlink_route_read ();
+}
diff --git a/zebra/rtread_proc.c b/zebra/rtread_proc.c
new file mode 100644
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 <zebra.h>
+
+#include "prefix.h"
+#include "log.h"
+#include "if.h"
+#include "rib.h"
+
+/* Proc file system to read IPv4 routing table. */
+#ifndef _PATH_PROCNET_ROUTE
+#define _PATH_PROCNET_ROUTE "/proc/net/route"
+#endif /* _PATH_PROCNET_ROUTE */
+
+/* Proc file system to read IPv6 routing table. */
+#ifndef _PATH_PROCNET_ROUTE6
+#define _PATH_PROCNET_ROUTE6 "/proc/net/ipv6_route"
+#endif /* _PATH_PROCNET_ROUTE6 */
+
+/* To read interface's name */
+#define INTERFACE_NAMSIZ 20
+
+/* Reading buffer for one routing entry. */
+#define RT_BUFSIZ 1024
+
+/* Kernel routing table read up by /proc filesystem. */
+int
+proc_route_read ()
+{
+ FILE *fp;
+ char buf[RT_BUFSIZ];
+ char iface[INTERFACE_NAMSIZ], dest[9], gate[9], mask[9];
+ int flags, refcnt, use, metric, mtu, window, rtt;
+
+ /* Open /proc filesystem */
+ fp = fopen (_PATH_PROCNET_ROUTE, "r");
+ if (fp == NULL)
+ {
+ zlog_warn ("Can't open %s : %s\n", _PATH_PROCNET_ROUTE, strerror (errno));
+ return -1;
+ }
+
+ /* Drop first label line. */
+ fgets (buf, RT_BUFSIZ, fp);
+
+ while (fgets (buf, RT_BUFSIZ, fp) != NULL)
+ {
+ int n;
+ struct prefix_ipv4 p;
+ struct in_addr tmpmask;
+ struct in_addr gateway;
+ u_char zebra_flags = 0;
+
+ n = sscanf (buf, "%s %s %s %x %d %d %d %s %d %d %d",
+ iface, dest, gate, &flags, &refcnt, &use, &metric,
+ mask, &mtu, &window, &rtt);
+ if (n != 11)
+ {
+ zlog_warn ("can't read all of routing information\n");
+ continue;
+ }
+ if (! (flags & RTF_UP))
+ continue;
+ if (! (flags & RTF_GATEWAY))
+ continue;
+
+ if (flags & RTF_DYNAMIC)
+ zebra_flags |= ZEBRA_FLAG_SELFROUTE;
+
+ p.family = AF_INET;
+ sscanf (dest, "%lX", (unsigned long *)&p.prefix);
+ sscanf (mask, "%lX", (unsigned long *)&tmpmask);
+ p.prefixlen = ip_masklen (tmpmask);
+ sscanf (gate, "%lX", (unsigned long *)&gateway);
+
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, 0, 0, 0, 0);
+ }
+
+ return 0;
+}
+
+#ifdef HAVE_IPV6
+int
+proc_ipv6_route_read ()
+{
+ FILE *fp;
+ char buf [RT_BUFSIZ];
+
+ /* Open /proc filesystem */
+ fp = fopen (_PATH_PROCNET_ROUTE6, "r");
+ if (fp == NULL)
+ {
+ zlog_warn ("Can't open %s : %s", _PATH_PROCNET_ROUTE6,
+ strerror (errno));
+ return -1;
+ }
+
+ /* There is no title line, so we don't drop first line. */
+ while (fgets (buf, RT_BUFSIZ, fp) != NULL)
+ {
+ int n;
+ char dest[33], src[33], gate[33];
+ char iface[INTERFACE_NAMSIZ];
+ int dest_plen, src_plen;
+ int metric, use, refcnt, flags;
+ struct prefix_ipv6 p;
+ struct in6_addr gateway;
+ u_char zebra_flags = 0;
+
+ /* Linux 2.1.x write this information at net/ipv6/route.c
+ rt6_info_node () */
+ n = sscanf (buf, "%32s %02x %32s %02x %32s %08x %08x %08x %08x %s",
+ dest, &dest_plen, src, &src_plen, gate,
+ &metric, &use, &refcnt, &flags, iface);
+
+ if (n != 10)
+ {
+ /* zlog_warn ("can't read all of routing information %d\n%s\n", n, buf); */
+ continue;
+ }
+
+ if (! (flags & RTF_UP))
+ continue;
+ if (! (flags & RTF_GATEWAY))
+ continue;
+
+ if (flags & RTF_DYNAMIC)
+ zebra_flags |= ZEBRA_FLAG_SELFROUTE;
+
+ p.family = AF_INET6;
+ str2in6_addr (dest, &p.prefix);
+ str2in6_addr (gate, &gateway);
+ p.prefixlen = dest_plen;
+
+ rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, 0, 0);
+ }
+
+ return 0;
+}
+#endif /* HAVE_IPV6 */
+
+void
+route_read ()
+{
+ proc_route_read ();
+#ifdef HAVE_IPV6
+ proc_ipv6_route_read ();
+#endif /* HAVE_IPV6 */
+}
diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c
new file mode 100644
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 <zebra.h>
+
+#include "memory.h"
+#include "log.h"
+
+/* Kernel routing table read up by sysctl function. */
+int
+route_read ()
+{
+ caddr_t buf, end, ref;
+ size_t bufsiz;
+ struct rt_msghdr *rtm;
+ void rtm_read (struct rt_msghdr *);
+
+#define MIBSIZ 6
+ int mib[MIBSIZ] =
+ {
+ CTL_NET,
+ PF_ROUTE,
+ 0,
+ 0,
+ NET_RT_DUMP,
+ 0
+ };
+
+ /* Get buffer size. */
+ if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0)
+ {
+ zlog_warn ("sysctl fail: %s", strerror (errno));
+ return -1;
+ }
+
+ /* Allocate buffer. */
+ ref = buf = XMALLOC (MTYPE_TMP, bufsiz);
+
+ /* Read routing table information by calling sysctl(). */
+ if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0)
+ {
+ zlog_warn ("sysctl() fail by %s", strerror (errno));
+ return -1;
+ }
+
+ for (end = buf + bufsiz; buf < end; buf += rtm->rtm_msglen)
+ {
+ rtm = (struct rt_msghdr *) buf;
+ rtm_read (rtm);
+ }
+
+ /* Free buffer. */
+ XFREE (MTYPE_TMP, ref);
+
+ return 0;
+}
diff --git a/zebra/zebra.conf.sample b/zebra/zebra.conf.sample
new file mode 100644
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 <zebra.h>
+
+#include "prefix.h"
+#include "table.h"
+#include "memory.h"
+#include "str.h"
+#include "command.h"
+#include "if.h"
+#include "log.h"
+#include "sockunion.h"
+
+#include "zebra/rib.h"
+#include "zebra/rt.h"
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/debug.h"
+
+/* Default rtm_table for all clients */
+extern int rtm_table_default;
+
+/* Each route type's string and default distance value. */
+struct
+{
+ int key;
+ int distance;
+} route_info[] =
+{
+ {ZEBRA_ROUTE_SYSTEM, 0},
+ {ZEBRA_ROUTE_KERNEL, 0},
+ {ZEBRA_ROUTE_CONNECT, 0},
+ {ZEBRA_ROUTE_STATIC, 1},
+ {ZEBRA_ROUTE_RIP, 120},
+ {ZEBRA_ROUTE_RIPNG, 120},
+ {ZEBRA_ROUTE_OSPF, 110},
+ {ZEBRA_ROUTE_OSPF6, 110},
+ {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */}
+};
+
+/* 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 <zebra.h>
+
+#ifdef HAVE_SNMP
+#include <asn1.h>
+#include <snmp.h>
+#include <snmp_impl.h>
+
+#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "command.h"
+#include "smux.h"
+#include "table.h"
+
+#include "zebra/rib.h"
+
+#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 <zebra.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "command.h"
+#include "table.h"
+#include "rib.h"
+
+/* Return route type string for VTY output. */
+const char *
+route_type_str (u_char type)
+{
+ switch (type)
+ {
+ case ZEBRA_ROUTE_SYSTEM:
+ return "system";
+ case ZEBRA_ROUTE_KERNEL:
+ return "kernel";
+ case ZEBRA_ROUTE_CONNECT:
+ return "connected";
+ case ZEBRA_ROUTE_STATIC:
+ return "static";
+ case ZEBRA_ROUTE_RIP:
+ return "rip";
+ case ZEBRA_ROUTE_RIPNG:
+ return "rip";
+ case ZEBRA_ROUTE_OSPF:
+ return "ospf";
+ case ZEBRA_ROUTE_OSPF6:
+ return "ospf";
+ case ZEBRA_ROUTE_BGP:
+ return "bgp";
+ default:
+ return "unknown";
+ }
+};
+
+/* Return route type string for VTY output. */
+const char
+route_type_char (u_char type)
+{
+ switch (type)
+ {
+ case ZEBRA_ROUTE_SYSTEM:
+ return 'S';
+ case ZEBRA_ROUTE_KERNEL:
+ return 'K';
+ case ZEBRA_ROUTE_CONNECT:
+ return 'C';
+ case ZEBRA_ROUTE_STATIC:
+ return 'S';
+ case ZEBRA_ROUTE_RIP:
+ return 'R';
+ case ZEBRA_ROUTE_RIPNG:
+ return 'R';
+ case ZEBRA_ROUTE_OSPF:
+ return 'O';
+ case ZEBRA_ROUTE_OSPF6:
+ return 'O';
+ case ZEBRA_ROUTE_BGP:
+ return 'B';
+ default:
+ return '?';
+ }
+};
+
+/* General fucntion for static route. */
+int
+zebra_static_ipv4 (struct vty *vty, int add_cmd,
+ char *dest_str, char *mask_str, char *gate_str,
+ char *distance_str)
+{
+ int ret;
+ u_char distance;
+ struct prefix p;
+ struct in_addr gate;
+ struct in_addr mask;
+ char *ifname;
+
+ ret = str2prefix (dest_str, &p);
+ if (ret <= 0)
+ {
+ vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Cisco like mask notation. */
+ if (mask_str)
+ {
+ ret = inet_aton (mask_str, &mask);
+ if (ret == 0)
+ {
+ vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ p.prefixlen = ip_masklen (mask);
+ }
+
+ /* Apply mask for given prefix. */
+ apply_mask (&p);
+
+ /* Administrative distance. */
+ if (distance_str)
+ distance = atoi (distance_str);
+ else
+ distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
+
+ /* Null0 static route. */
+ if (strncasecmp (gate_str, "Null0", strlen (gate_str)) == 0)
+ {
+ if (add_cmd)
+ static_add_ipv4 (&p, NULL, NULL, distance, 0);
+ else
+ static_delete_ipv4 (&p, NULL, NULL, distance, 0);
+ return CMD_SUCCESS;
+ }
+
+ /* When gateway is A.B.C.D format, gate is treated as nexthop
+ address other case gate is treated as interface name. */
+ ret = inet_aton (gate_str, &gate);
+ if (ret)
+ ifname = NULL;
+ else
+ ifname = gate_str;
+
+ if (add_cmd)
+ static_add_ipv4 (&p, ifname ? NULL : &gate, ifname, distance, 0);
+ else
+ static_delete_ipv4 (&p, ifname ? NULL : &gate, ifname, distance, 0);
+
+ return CMD_SUCCESS;
+}
+
+/* Static route configuration. */
+DEFUN (ip_route,
+ ip_route_cmd,
+ "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0)",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n")
+{
+ return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL);
+}
+
+/* Mask as A.B.C.D format. */
+DEFUN (ip_route_mask,
+ ip_route_mask_cmd,
+ "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0)",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n")
+{
+ return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL);
+}
+
+/* Distance option value. */
+DEFUN (ip_route_distance,
+ ip_route_distance_cmd,
+ "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Distance value for this route\n")
+{
+ return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2]);
+}
+
+DEFUN (ip_route_mask_distance,
+ ip_route_mask_distance_cmd,
+ "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Distance value for this route\n")
+{
+ return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3]);
+}
+
+DEFUN (no_ip_route,
+ no_ip_route_cmd,
+ "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0)",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n")
+{
+ return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL);
+}
+
+DEFUN (no_ip_route_mask,
+ no_ip_route_mask_cmd,
+ "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0)",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n")
+{
+ return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN (no_ip_route_distance,
+ no_ip_route_distance_cmd,
+ "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Distance value for this route\n")
+{
+ return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], argv[2]);
+}
+
+DEFUN (no_ip_route_mask_distance,
+ no_ip_route_mask_distance_cmd,
+ "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Distance value for this route\n")
+{
+ return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], argv[3]);
+}
+
+/* New RIB. Detailed information for IPv4 route. */
+void
+vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
+{
+ struct rib *rib;
+ struct nexthop *nexthop;
+
+ for (rib = rn->info; rib; rib = rib->next)
+ {
+ vty_out (vty, "Routing entry for %s/%d%s",
+ inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
+ VTY_NEWLINE);
+ vty_out (vty, " Known via \"%s\"", route_type_str (rib->type));
+ vty_out (vty, ", distance %d, metric %d", rib->distance, rib->metric);
+ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ vty_out (vty, ", best");
+ if (rib->refcnt)
+ vty_out (vty, ", refcnt %ld", rib->refcnt);
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+ if (rib->type == ZEBRA_ROUTE_RIP
+ || rib->type == ZEBRA_ROUTE_OSPF
+ || rib->type == ZEBRA_ROUTE_BGP)
+ {
+ time_t uptime;
+ struct tm *tm;
+
+ uptime = time (NULL);
+ uptime -= rib->uptime;
+ tm = gmtime (&uptime);
+
+ vty_out (vty, " Last update ");
+
+ if (uptime < ONE_DAY_SECOND)
+ vty_out (vty, "%02d:%02d:%02d",
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ else if (uptime < ONE_WEEK_SECOND)
+ vty_out (vty, "%dd%02dh%02dm",
+ tm->tm_yday, tm->tm_hour, tm->tm_min);
+ else
+ vty_out (vty, "%02dw%dd%02dh",
+ tm->tm_yday/7,
+ tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+ vty_out (vty, " ago%s", VTY_NEWLINE);
+ }
+
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ {
+ vty_out (vty, " %c",
+ CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ');
+
+ switch (nexthop->type)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ vty_out (vty, " %s", inet_ntoa (nexthop->gate.ipv4));
+ if (nexthop->ifindex)
+ vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ vty_out (vty, " directly connected, %s",
+ ifindex2ifname (nexthop->ifindex));
+ break;
+ case NEXTHOP_TYPE_IFNAME:
+ vty_out (vty, " directly connected, %s", nexthop->ifname);
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ vty_out (vty, " directly connected, via Null0");
+ break;
+ default:
+ break;
+ }
+ if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ vty_out (vty, " inactive");
+
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ {
+ vty_out (vty, " (recursive");
+
+ switch (nexthop->rtype)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ vty_out (vty, " via %s)", inet_ntoa (nexthop->rgate.ipv4));
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IFNAME:
+ vty_out (vty, " is directly connected, %s)",
+ ifindex2ifname (nexthop->rifindex));
+ break;
+ default:
+ break;
+ }
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+}
+
+void
+vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib)
+{
+ struct nexthop *nexthop;
+ int len = 0;
+ char buf[BUFSIZ];
+
+ /* Nexthop information. */
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ {
+ if (nexthop == rib->nexthop)
+ {
+ /* Prefix information. */
+ len = vty_out (vty, "%c%c%c %s/%d",
+ route_type_char (rib->type),
+ CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)
+ ? '>' : ' ',
+ CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+ ? '*' : ' ',
+ inet_ntop (AF_INET, &rn->p.u.prefix, buf, BUFSIZ),
+ rn->p.prefixlen);
+
+ /* Distance and metric display. */
+ if (rib->type != ZEBRA_ROUTE_CONNECT
+ && rib->type != ZEBRA_ROUTE_KERNEL)
+ len += vty_out (vty, " [%d/%d]", rib->distance,
+ rib->metric);
+ }
+ else
+ vty_out (vty, " %c%*c",
+ CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+ ? '*' : ' ',
+ len - 3, ' ');
+
+ switch (nexthop->type)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4));
+ if (nexthop->ifindex)
+ vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ vty_out (vty, " is directly connected, %s",
+ ifindex2ifname (nexthop->ifindex));
+ break;
+ case NEXTHOP_TYPE_IFNAME:
+ vty_out (vty, " is directly connected, %s", nexthop->ifname);
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ vty_out (vty, " is directly connected, Null0");
+ default:
+ break;
+ }
+ if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ vty_out (vty, " inactive");
+
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ {
+ vty_out (vty, " (recursive");
+
+ switch (nexthop->rtype)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ vty_out (vty, " via %s)", inet_ntoa (nexthop->rgate.ipv4));
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IFNAME:
+ vty_out (vty, " is directly connected, %s)",
+ ifindex2ifname (nexthop->rifindex));
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (rib->type == ZEBRA_ROUTE_RIP
+ || rib->type == ZEBRA_ROUTE_OSPF
+ || rib->type == ZEBRA_ROUTE_BGP)
+ {
+ time_t uptime;
+ struct tm *tm;
+
+ uptime = time (NULL);
+ uptime -= rib->uptime;
+ tm = gmtime (&uptime);
+
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+
+ if (uptime < ONE_DAY_SECOND)
+ vty_out (vty, ", %02d:%02d:%02d",
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ else if (uptime < ONE_WEEK_SECOND)
+ vty_out (vty, ", %dd%02dh%02dm",
+ tm->tm_yday, tm->tm_hour, tm->tm_min);
+ else
+ vty_out (vty, ", %02dw%dd%02dh",
+ tm->tm_yday/7,
+ tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+}
+
+#define SHOW_ROUTE_V4_HEADER "Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF,%s B - BGP, > - selected route, * - FIB route%s%s"
+
+DEFUN (show_ip_route,
+ show_ip_route_cmd,
+ "show ip route",
+ SHOW_STR
+ IP_STR
+ "IP routing table\n")
+{
+ struct route_table *table;
+ struct route_node *rn;
+ struct rib *rib;
+ int first = 1;
+
+ table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+ if (! table)
+ return CMD_SUCCESS;
+
+ /* Show all IPv4 routes. */
+ for (rn = route_top (table); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = rib->next)
+ {
+ if (first)
+ {
+ vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, VTY_NEWLINE,
+ VTY_NEWLINE);
+ first = 0;
+ }
+ vty_show_ip_route (vty, rn, rib);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_prefix_longer,
+ show_ip_route_prefix_longer_cmd,
+ "show ip route A.B.C.D/M longer-prefixes",
+ SHOW_STR
+ IP_STR
+ "IP routing table\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Show route matching the specified Network/Mask pair only\n")
+{
+ struct route_table *table;
+ struct route_node *rn;
+ struct rib *rib;
+ struct prefix p;
+ int ret;
+ int first = 1;
+
+ ret = str2prefix (argv[0], &p);
+ if (! ret)
+ {
+ vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+ if (! table)
+ return CMD_SUCCESS;
+
+ /* Show matched type IPv4 routes. */
+ for (rn = route_top (table); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = rib->next)
+ if (prefix_match (&p, &rn->p))
+ {
+ if (first)
+ {
+ vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE,
+ VTY_NEWLINE, VTY_NEWLINE);
+ first = 0;
+ }
+ vty_show_ip_route (vty, rn, rib);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_supernets,
+ show_ip_route_supernets_cmd,
+ "show ip route supernets-only",
+ SHOW_STR
+ IP_STR
+ "IP routing table\n"
+ "Show supernet entries only\n")
+{
+ struct route_table *table;
+ struct route_node *rn;
+ struct rib *rib;
+ u_int32_t addr;
+ int first = 1;
+
+ table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+ if (! table)
+ return CMD_SUCCESS;
+
+ /* Show matched type IPv4 routes. */
+ for (rn = route_top (table); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = rib->next)
+ {
+ addr = ntohl (rn->p.u.prefix4.s_addr);
+
+ if ((IN_CLASSC (addr) && rn->p.prefixlen < 24)
+ || (IN_CLASSB (addr) && rn->p.prefixlen < 16)
+ || (IN_CLASSA (addr) && rn->p.prefixlen < 8))
+ {
+ if (first)
+ {
+ vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE,
+ VTY_NEWLINE, VTY_NEWLINE);
+ first = 0;
+ }
+ vty_show_ip_route (vty, rn, rib);
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_protocol,
+ show_ip_route_protocol_cmd,
+ "show ip route (bgp|connected|kernel|ospf|rip|static)",
+ SHOW_STR
+ IP_STR
+ "IP routing table\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Connected\n"
+ "Kernel\n"
+ "Open Shortest Path First (OSPF)\n"
+ "Routing Information Protocol (RIP)\n"
+ "Static routes\n")
+{
+ int type;
+ struct route_table *table;
+ struct route_node *rn;
+ struct rib *rib;
+ int first = 1;
+
+ if (strncmp (argv[0], "b", 1) == 0)
+ type = ZEBRA_ROUTE_BGP;
+ else if (strncmp (argv[0], "c", 1) == 0)
+ type = ZEBRA_ROUTE_CONNECT;
+ else if (strncmp (argv[0], "k", 1) ==0)
+ type = ZEBRA_ROUTE_KERNEL;
+ else if (strncmp (argv[0], "o", 1) == 0)
+ type = ZEBRA_ROUTE_OSPF;
+ else if (strncmp (argv[0], "r", 1) == 0)
+ type = ZEBRA_ROUTE_RIP;
+ else if (strncmp (argv[0], "s", 1) == 0)
+ type = ZEBRA_ROUTE_STATIC;
+ else
+ {
+ vty_out (vty, "Unknown route type%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+ if (! table)
+ return CMD_SUCCESS;
+
+ /* Show matched type IPv4 routes. */
+ for (rn = route_top (table); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = rib->next)
+ if (rib->type == type)
+ {
+ if (first)
+ {
+ vty_out (vty, SHOW_ROUTE_V4_HEADER,
+ VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ first = 0;
+ }
+ vty_show_ip_route (vty, rn, rib);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_addr,
+ show_ip_route_addr_cmd,
+ "show ip route A.B.C.D",
+ SHOW_STR
+ IP_STR
+ "IP routing table\n"
+ "Network in the IP routing table to display\n")
+{
+ int ret;
+ struct prefix_ipv4 p;
+ struct route_table *table;
+ struct route_node *rn;
+
+ ret = str2prefix_ipv4 (argv[0], &p);
+ if (ret <= 0)
+ {
+ vty_out (vty, "%% Malformed IPv4 address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+ if (! table)
+ return CMD_SUCCESS;
+
+ rn = route_node_match (table, (struct prefix *) &p);
+ if (! rn)
+ {
+ vty_out (vty, "%% Network not in table%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ vty_show_ip_route_detail (vty, rn);
+
+ route_unlock_node (rn);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_prefix,
+ show_ip_route_prefix_cmd,
+ "show ip route A.B.C.D/M",
+ SHOW_STR
+ IP_STR
+ "IP routing table\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+ int ret;
+ struct prefix_ipv4 p;
+ struct route_table *table;
+ struct route_node *rn;
+
+ ret = str2prefix_ipv4 (argv[0], &p);
+ if (ret <= 0)
+ {
+ vty_out (vty, "%% Malformed IPv4 address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+ if (! table)
+ return CMD_SUCCESS;
+
+ rn = route_node_match (table, (struct prefix *) &p);
+ if (! rn || rn->p.prefixlen != p.prefixlen)
+ {
+ vty_out (vty, "%% Network not in table%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ vty_show_ip_route_detail (vty, rn);
+
+ route_unlock_node (rn);
+
+ return CMD_SUCCESS;
+}
+
+void
+zebra_show_ip_route (struct vty *vty, struct vrf *vrf)
+{
+ vty_out (vty, "IP routing table name is %s(%d)%s",
+ vrf->name ? vrf->name : "", vrf->id, VTY_NEWLINE);
+
+ vty_out (vty, "Route Source Networks%s", VTY_NEWLINE);
+ vty_out (vty, "connected %d%s", 0, VTY_NEWLINE);
+ vty_out (vty, "static %d%s", 0, VTY_NEWLINE);
+ vty_out (vty, "rip %d%s", 0, VTY_NEWLINE);
+
+ vty_out (vty, "bgp %d%s", 0, VTY_NEWLINE);
+ vty_out (vty, " External: %d Internal: %d Local: %d%s",
+ 0, 0, 0, VTY_NEWLINE);
+
+ vty_out (vty, "ospf %d%s", 0, VTY_NEWLINE);
+ vty_out (vty,
+ " Intra-area: %d Inter-area: %d External-1: %d External-2: %d%s",
+ 0, 0, 0, 0, VTY_NEWLINE);
+ vty_out (vty, " NSSA External-1: %d NSSA External-2: %d%s",
+ 0, 0, VTY_NEWLINE);
+
+ vty_out (vty, "internal %d%s", 0, VTY_NEWLINE);
+ vty_out (vty, "Total %d%s", 0, VTY_NEWLINE);
+}
+
+/* Show route summary. */
+DEFUN (show_ip_route_summary,
+ show_ip_route_summary_cmd,
+ "show ip route summary",
+ SHOW_STR
+ IP_STR
+ "IP routing table\n"
+ "Summary of all routes\n")
+{
+ struct vrf *vrf;
+
+ /* Default table id is zero. */
+ vrf = vrf_lookup (0);
+ if (! vrf)
+ {
+ vty_out (vty, "%% No Default-IP-Routing-Table%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ zebra_show_ip_route (vty, vrf);
+
+ return CMD_SUCCESS;
+}
+
+/* Write IPv4 static route configuration. */
+int
+static_config_ipv4 (struct vty *vty)
+{
+ struct route_node *rn;
+ struct static_ipv4 *si;
+ struct route_table *stable;
+ int write;
+
+ write = 0;
+
+ /* Lookup table. */
+ stable = vrf_static_table (AFI_IP, SAFI_UNICAST, 0);
+ if (! stable)
+ return -1;
+
+ for (rn = route_top (stable); rn; rn = route_next (rn))
+ for (si = rn->info; si; si = si->next)
+ {
+ vty_out (vty, "ip route %s/%d", inet_ntoa (rn->p.u.prefix4),
+ rn->p.prefixlen);
+
+ switch (si->type)
+ {
+ case STATIC_IPV4_GATEWAY:
+ vty_out (vty, " %s", inet_ntoa (si->gate.ipv4));
+ break;
+ case STATIC_IPV4_IFNAME:
+ vty_out (vty, " %s", si->gate.ifname);
+ break;
+ case STATIC_IPV4_BLACKHOLE:
+ vty_out (vty, " Null0");
+ break;
+ }
+
+ if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT)
+ vty_out (vty, " %d", si->distance);
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ write = 1;
+ }
+ return write;
+}
+
+#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 <zebra.h>
+
+#include "prefix.h"
+#include "command.h"
+#include "if.h"
+#include "thread.h"
+#include "stream.h"
+#include "memory.h"
+#include "table.h"
+#include "rib.h"
+#include "network.h"
+#include "sockunion.h"
+#include "log.h"
+#include "zclient.h"
+
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/debug.h"
+#include "zebra/ipforward.h"
+
+/* 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 <sys/un.h>
+
+/* zebra server UNIX domain socket. */
+void
+zebra_serv_un (char *path)
+{
+ int ret;
+ int sock, len;
+ struct sockaddr_un serv;
+ mode_t old_mask;
+
+ /* First of all, unlink existing socket */
+ unlink (path);
+
+ /* Set umask */
+ old_mask = umask (0077);
+
+ /* Make UNIX domain socket. */
+ sock = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0)
+ {
+ perror ("sock");
+ return;
+ }
+
+ /* Make server socket. */
+ memset (&serv, 0, sizeof (struct sockaddr_un));
+ serv.sun_family = AF_UNIX;
+ strncpy (serv.sun_path, path, strlen (path));
+#ifdef HAVE_SUN_LEN
+ len = serv.sun_len = SUN_LEN(&serv);
+#else
+ len = sizeof (serv.sun_family) + strlen (serv.sun_path);
+#endif /* HAVE_SUN_LEN */
+
+ ret = bind (sock, (struct sockaddr *) &serv, len);
+ if (ret < 0)
+ {
+ perror ("bind");
+ close (sock);
+ return;
+ }
+
+ ret = listen (sock, 5);
+ if (ret < 0)
+ {
+ perror ("listen");
+ close (sock);
+ return;
+ }
+
+ umask (old_mask);
+
+ zebra_event (ZEBRA_SERV, sock, NULL);
+}
+
+/* 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 */