summaryrefslogtreecommitdiff
path: root/ospfd
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 /ospfd
Initial revision
Diffstat (limited to 'ospfd')
-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
50 files changed, 44393 insertions, 0 deletions
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 */