diff options
Diffstat (limited to 'ospfd')
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 */  | 
