From 718e3744195351130f4ce7dbe0613f4b3e23df93 Mon Sep 17 00:00:00 2001 From: paul Date: Fri, 13 Dec 2002 20:15:29 +0000 Subject: Initial revision --- ospfd/.cvsignore | 7 + ospfd/ChangeLog | 2970 +++++++++++++++++++ ospfd/Makefile.am | 44 + ospfd/Makefile.in | 532 ++++ ospfd/OSPF-MIB.txt | 2723 +++++++++++++++++ ospfd/OSPF-TRAP-MIB.txt | 443 +++ ospfd/ospf_abr.c | 1741 +++++++++++ ospfd/ospf_abr.h | 84 + ospfd/ospf_asbr.c | 287 ++ ospfd/ospf_asbr.h | 75 + ospfd/ospf_ase.c | 838 ++++++ ospfd/ospf_ase.h | 42 + ospfd/ospf_dump.c | 1673 +++++++++++ ospfd/ospf_dump.h | 139 + ospfd/ospf_flood.c | 1048 +++++++ ospfd/ospf_flood.h | 65 + ospfd/ospf_ia.c | 726 +++++ ospfd/ospf_ia.h | 42 + ospfd/ospf_interface.c | 1045 +++++++ ospfd/ospf_interface.h | 245 ++ ospfd/ospf_ism.h | 88 + ospfd/ospf_lsa.c | 3315 +++++++++++++++++++++ ospfd/ospf_lsa.h | 326 ++ ospfd/ospf_lsdb.c | 299 ++ ospfd/ospf_lsdb.h | 83 + ospfd/ospf_main.c | 293 ++ ospfd/ospf_neighbor.h | 106 + ospfd/ospf_network.c | 192 ++ ospfd/ospf_network.h | 34 + ospfd/ospf_nsm.h | 91 + ospfd/ospf_opaque.c | 2392 +++++++++++++++ ospfd/ospf_opaque.h | 155 + ospfd/ospf_packet.c | 3243 ++++++++++++++++++++ ospfd/ospf_packet.h | 171 ++ ospfd/ospf_route.c | 1026 +++++++ ospfd/ospf_route.h | 165 ++ ospfd/ospf_routemap.c | 828 ++++++ ospfd/ospf_snmp.c | 2443 +++++++++++++++ ospfd/ospf_snmp.h | 33 + ospfd/ospf_spf.c | 1088 +++++++ ospfd/ospf_spf.h | 50 + ospfd/ospf_te.c | 1921 ++++++++++++ ospfd/ospf_te.h | 193 ++ ospfd/ospf_vty.c | 7571 +++++++++++++++++++++++++++++++++++++++++++++++ ospfd/ospf_vty.h | 85 + ospfd/ospf_zebra.c | 1180 ++++++++ ospfd/ospf_zebra.h | 78 + ospfd/ospfd.c | 1603 ++++++++++ ospfd/ospfd.conf.sample | 13 + ospfd/ospfd.h | 559 ++++ 50 files changed, 44393 insertions(+) create mode 100644 ospfd/.cvsignore create mode 100644 ospfd/ChangeLog create mode 100644 ospfd/Makefile.am create mode 100644 ospfd/Makefile.in create mode 100644 ospfd/OSPF-MIB.txt create mode 100644 ospfd/OSPF-TRAP-MIB.txt create mode 100644 ospfd/ospf_abr.c create mode 100644 ospfd/ospf_abr.h create mode 100644 ospfd/ospf_asbr.c create mode 100644 ospfd/ospf_asbr.h create mode 100644 ospfd/ospf_ase.c create mode 100644 ospfd/ospf_ase.h create mode 100644 ospfd/ospf_dump.c create mode 100644 ospfd/ospf_dump.h create mode 100644 ospfd/ospf_flood.c create mode 100644 ospfd/ospf_flood.h create mode 100644 ospfd/ospf_ia.c create mode 100644 ospfd/ospf_ia.h create mode 100644 ospfd/ospf_interface.c create mode 100644 ospfd/ospf_interface.h create mode 100644 ospfd/ospf_ism.h create mode 100644 ospfd/ospf_lsa.c create mode 100644 ospfd/ospf_lsa.h create mode 100644 ospfd/ospf_lsdb.c create mode 100644 ospfd/ospf_lsdb.h create mode 100644 ospfd/ospf_main.c create mode 100644 ospfd/ospf_neighbor.h create mode 100644 ospfd/ospf_network.c create mode 100644 ospfd/ospf_network.h create mode 100644 ospfd/ospf_nsm.h create mode 100644 ospfd/ospf_opaque.c create mode 100644 ospfd/ospf_opaque.h create mode 100644 ospfd/ospf_packet.c create mode 100644 ospfd/ospf_packet.h create mode 100644 ospfd/ospf_route.c create mode 100644 ospfd/ospf_route.h create mode 100644 ospfd/ospf_routemap.c create mode 100644 ospfd/ospf_snmp.c create mode 100644 ospfd/ospf_snmp.h create mode 100644 ospfd/ospf_spf.c create mode 100644 ospfd/ospf_spf.h create mode 100644 ospfd/ospf_te.c create mode 100644 ospfd/ospf_te.h create mode 100644 ospfd/ospf_vty.c create mode 100644 ospfd/ospf_vty.h create mode 100644 ospfd/ospf_zebra.c create mode 100644 ospfd/ospf_zebra.h create mode 100644 ospfd/ospfd.c create mode 100644 ospfd/ospfd.conf.sample create mode 100644 ospfd/ospfd.h (limited to 'ospfd') diff --git a/ospfd/.cvsignore b/ospfd/.cvsignore new file mode 100644 index 00000000..d7e3a7e2 --- /dev/null +++ b/ospfd/.cvsignore @@ -0,0 +1,7 @@ +Makefile +*.o +ospfd +ospfd.conf +tags +TAGS +.deps diff --git a/ospfd/ChangeLog b/ospfd/ChangeLog new file mode 100644 index 00000000..31c5b0f7 --- /dev/null +++ b/ospfd/ChangeLog @@ -0,0 +1,2970 @@ +2002-10-23 endo@suri.co.jp (Masahiko Endo) + + * ospf_opaque.c: Update Opaque LSA patch. + +2002-10-23 Ralph Keller + + * ospf_vty.c (show_ip_ospf_database): Fix CLI parse. + +2002-10-23 Juris Kalnins + + * ospf_interface.c (ospf_if_stream_unset): When write queue + becomes empty stop write timer. + +2002-10-10 Greg Troxel + + * ospf_packet.c (ospf_check_md5_digest): Change >= to > to make it + conform to RFC. + +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2002-06-19 Kunihiro Ishiguro + + * ospf_spf.c (ospf_nexthop_calculation): Add NULL set to oi and + check of l2. Reported by: Daniel Drown + (ospf_lsa_has_link): LSA Length calculation fix. Reported by: + Paul Jakma . + + * ospfd.c (ospf_if_update): Fix nextnode reference bug. Reported + by: juris@mt.lv. + +2002-01-21 Kunihiro Ishiguro + + * ospfd.c: Merge [zebra 11445] Masahiko ENDO's Opaque-LSA support. + +2001-08-27 Kunihiro Ishiguro + + * ospf_interface.c (ospf_add_to_if): Use /32 address to register + OSPF interface information. + (ospf_delete_from_if): Likewise. + + * ospf_zebra.c (ospf_interface_address_delete): Likewise. + +2001-08-23 Kunihiro Ishiguro + + * ospf_zebra.c (ospf_redistribute_unset): When redistribute type + is OSPF, do not unset redistribute flag. + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-08-12 Kunihiro Ishiguro + + * ospfd.c (ospf_config_write): auto-cost reference-bandwidth + configuration display. + +2001-07-24 David Watson + + * ospf_spf.c (ospf_spf_next): Modify ospf_vertex_add_parent to + check for an existing link before connecting the parent and child. + ospf_nexthop_calculation is also modified to check for duplicate + entries when copying from the parent. Finally, ospf_spf_next + removes duplicates when it merges two equal cost candidates. + +2001-07-23 itojun@iijlab.net + + * ospfd.c (show_ip_ospf_neighbor): Check ospf_top before use it + [zebra 8549]. + +2001-07-23 Kunihiro Ishiguro + + * ospf_packet.c (ospf_write): Remove defined(__OpenBSD__) to make + it work on OpenBSD. + +2001-06-26 Kunihiro Ishiguro + + * ospf_zebra.c (config_write_ospf_default_metric): Display + default-metric configuration. + +2001-06-18 Kunihiro Ishiguro + + * ospf_ia.h (OSPF_EXAMINE_SUMMARIES_ALL): Remove old macros. + +2001-05-28 Kunihiro Ishiguro + + * ospf_snmp.c (ospfIfEntry): Fix interface lookup bug to avoid + crush. + (ospfIfMetricEntry): Likewise. + +2001-03-18 Kunihiro Ishiguro + + * ospf_packet.c (ospf_read): Fix typo. Reported by: "Jen B + Lin'Kova" . + +2001-03-15 Gleb Natapov + + * ospf_interface.c (ip_ospf_network): Set interface parameter. + (interface_config_write): Add check for OSPF_IFTYPE_LOOPBACK. + + * ospf_zebra.c (ospf_interface_add): Set interface parameter. + +2001-02-21 Kunihiro Ishiguro + + * ospf_packet.c (ospf_recv_packet): Solaris also need to add + (iph.ip_hl << 2) to iph.ip_len. + +2001-02-09 Kunihiro Ishiguro + + * ospfd.h (OSPF_LS_REFRESH_TIME): Fix OSPF_LS_REFRESH_TIME value. + Suggested by: David Watson . + + * ospf_zebra.c (zebra_init): Remove zebra node. + + * ospfd.c (ospf_area_range_set): Function name is changed from + ospf_ara_range_cmd. + (ospf_area_range_unset): New function which separated from DEFUN. + New commands are added: + "no area A.B.C.D range A.B.C.D/M advertise" + "no area <0-4294967295> range A.B.C.D/M advertise" + "no area A.B.C.D range A.B.C.D/M not-advertise" + "no area <0-4294967295> range A.B.C.D/M not-advertise" + + * ospf_lsa.c (ospf_lsa_more_recent): Fix previous change. + +2001-02-08 Matthew Grant + + * ospf_network.c (ospf_if_add_allspfrouters): Use + setsockopt_multicast_ipv4. + (ospf_if_drop_allspfrouters): Likewise. + + * ospf_lsa.c (ospf_router_lsa_install): Add rt_recalc flag. + (ospf_network_lsa_install): Likewise. + (ospf_summary_lsa_install): Likewise. + (ospf_summary_asbr_lsa_install): Likewise. + (ospf_external_lsa_install): Likewise. + (ospf_lsa_install): Call ospf_lsa_different to check this LSA is + new one or not. + +2001-02-08 Kunihiro Ishiguro + + * ospf_zebra.c (ospf_interface_delete): Do not free interface + structure when ospfd receive interface delete message to support + pseudo interface. + +2001-02-01 Dick Glasspool + + * ospfd.c (area_range_notadvertise): Change area range "suppress" + command to "not-advertise". + + * ospfd.h (OSPF_LS_REFRESH_TIME): Change OSPF_LS_REFRESH_TIME from + 1800 to 60. + + * ospf_abr.c (ospf_abr_update_aggregate): When update_aggregate is + updating the area-range, the lowest cost is now saved. + + * ospf_lsa.c (ospf_lsa_more_recent): Routing to compare sequence + numbers rather than creating overflow during calculation. + +2001-02-01 Kunihiro Ishiguro + + * zebra-0.91 is released. + +2001-01-31 Kunihiro Ishiguro + + * ospf_packet.c (ospf_db_desc_proc): Do not continue process when + NSM_SeqNumberMismatch is scheduled. + (ospf_ls_req): Free ls_upd when return from this function. + (ospf_ls_upd_timer): When update list is empty do not call + ospf_ls_upd_send(). Suggested by: endo@suri.co.jp (Masahiko + Endo). + +2001-01-26 Kunihiro Ishiguro + + * ospf_lsa.c (ospf_maxage_flood): Flood LSA when it reaches + MaxAge. RFC2328 Section 14. + (ospf_maxage_lsa_remover): Call above function during removing + MaxAge LSA. + +2001-01-26 Dick Glasspool + + * ospf_flood.c (ospf_flood_through_as): Function is updated for + NSSA Translations now done at ospf_abr.c with no change in P-bit. + + * ospf_lsa.c (ospf_get_nssa_ip): Get 1st IP connection for Forward + Addr. + (ospf_install_flood_nssa): Leave Type-7 LSA at Lock Count = 2. + + * ospf_ase.c (ospf_ase_calculate_route): Add debug codes. + + * ospf_abr.c (ospf_abr_translate_nssa): Recalculate LSA checksum. + + * ospf_packet.h (OSPF_SEND_PACKET_LOOP): Added for test packet. + + * ospf_dump.c (ospf_lsa_type_msg): Add OSPF_GROUP_MEMBER_LSA and + OSPF_AS_NSSA_LSA. + + * ospfd.c (data_injection): Function to inject LSA. This is + debugging command. + +2001-01-11 Kunihiro Ishiguro + + * ospf_route.c (ospf_route_match_same): Remove function. + (ospf_route_match_same_new): Renamed to ospf_route_match_same. + + * ospf_zebra.c (ospf_interface_address_delete): Add check for + oi->address. Suggested by Matthew Grant + . + (ospf_zebra_add): Remove function. + (ospf_zebra_add_multipath): Rename to ospf_zebra_add. + + * ospf_interface.c: Remove HAVE_IF_PSEUDO part. + + * ospf_zebra.c: Likewise. + +2001-01-10 Kunihiro Ishiguro + + * ospf_ase.c: Remove OLD_RIB part. + + * ospf_route.c: Likewise. + + * zebra-0.90 is released. + + * ospf_packet.c (ospf_recv_packet): Use ip_len adjestment code to + NetBSD. + +2001-01-09 Kunihiro Ishiguro + + * ospf_route.c (ospf_route_delete): Use + ospf_zebra_delete_multipath. + +2001-01-09 Matthew Grant + + * ospf_interface.c (ospf_if_cleanup): Function name is renamed + from ospf_if_free(). Rewrite whole procudure to support primary + address deletion. + + * ospf_zebra.c (ospf_interface_address_delete): Add primary + address deletion process. + +2001-01-09 Kunihiro Ishiguro + + * ospf_packet.c (ospf_recv_packet): OpenBSD has same ip_len + treatment like FreeBSD. + +2001-01-09 endo@suri.co.jp (Masahiko Endo) + + * ospf_packet.c (ospf_recv_packet): FreeBSD kernel network code + strips IP header size from receiving IP Packet. So we adjust + ip_len to whole IP packet size by adding IP header size. + +2001-01-08 endo@suri.co.jp (Masahiko Endo) + + * ospf_network.c (ospf_serv_sock): When socket() is failed return + immediately. + (ospf_serv_sock): Close socket when it is not used. + + * ospf_packet.c (ospf_write): Set sin_len when HAVE_SIN_LEN is + defined. + (ospf_write): When bind is fined, close sock. + +2001-01-07 Gleb Natapov + + * ospf_zebra.c (ospf_interface_state_up): Fixes coredump that + appears when you try to configure bandwidth on the ppp interface + that is not yet configured in ospfd. + +2001-01-07 Michael Rozhavsky + + * ospf_route.c (show_ip_ospf_route_external): "show ip ospf route" + will print nexthops for AS-external routes. + + * ospf_ase.c (ospf_ase_route_match_same): New function to compare + ASE route under multipath environment. + (ospf_ase_compare_tables): Likewise. + +2001-01-01 Kunihiro Ishiguro + + * ospfd.h (OSPF_VTYSH_PATH): Change "/tmp/ospfd" to "/tmp/.ospfd". + +2000-12-28 Kunihiro Ishiguro + + * ospf_route.c (ospf_route_install): Install multipath information + to zebra daemon. + + * ospf_zebra.c (ospf_zebra_add_multipath): Function for passing + multipath information to zebra daemon. + +2000-12-25 Dick Glasspool + + * ospf_packet.c (ospf_write): Call ospf_packet_delete when sendto + fail. + (DISCARD_LSA): Add argument N for logging point of DISCARD_LSA is + called. + + * ospf_lsa.c (ospf_external_lsa_refresh): NSSA install_flood will + leave Type-7 LSA at Lock Count = 2. + + * ospf_flood.c (ospf_flood_through): Flood_though_as updated for + NSSA no P-bit off during Area flooding, but P-bit is turned off + for mulitple NSSA AS flooding. + + * ospf_ase.c (ospf_ase_calculate_timer): Added calculations for + Type-7 LSDB. + + * ospf_abr.c (ospf_abr_translate_nssa): Removed one unlock call. + (ospf_abr_announce_nssa_defaults): Corrected Debug from EVENT to + NSSA. + +2000-12-25 Michael Rozhavsky + + * ospf_zebra.c (ospf_zebra_read_ipv4): Checking the age of the + found LSA and if the LSA is MAXAGE we should call refresh instead + of originate. + +2000-12-18 Dick Glasspool + + * ospf_abr.c: Removed redundant "...flood" in + announce_network_to_area(). Repaired nssa Unlock by using + discard. + + * ospf_packet.c: Removed old NSSA translate during mk_ls_update. + + * ospfd.c: Free up all data bases including NSSA. + + * ospf_lsa.c: Now allow removal of XLATE LSA's Check in + discard_callback. Added routine to get ip addr from within the + ifp. + + * ospf_flood.c: Now set Forward Address for outgoing Type-7. + + * ospf_lsa.h: Added prototype for the below. struct in_addr + ospf_get_ip_from_ifp (struct interface *ifp). + +2000-12-14 Gleb Natapov + + * ospf_packet.c (ospf_recv_packet): New OSPF pakcet read method. + Now maximum packet length may be 65535 bytes (maximum IP packet + length). + + * ospf_interface.c (ospf_if_stream_set): Don't make input buffer. + + * ospfd.c (config_write_network_area): Remove unnecessary area + lookup code. + +2000-12-13 Kunihiro Ishiguro + + * ospf_packet.c (ospf_read): Accept packet bigger than MTU value. + +2000-12-13 Gleb Natapov + + * ospfd.c (config_write_network_area): Fix bug in + config_write_network_area function. + +2000-12-12 Gleb Natapov + + * ospf_abr.c (ospf_abr_announce_network_to_area): Make Summary + LSA's origination and refreshment as same as other type of LSA. + + * ospf_lsa.c (ospf_summary_lsa_refresh): Return struct ospf_lsa *. + + * ospf_lsa.c (ospf_summary_asbr_lsa_refresh): Likewise. + +2000-12-08 Dick Glasspool + + The bulk of NSSA changes are contained herein; This version will + require manual setting of "always" for NSSA Translator, and will + not perform aggregation yet. + + * ospf_dump.c: "debug ospf nssa" is added. + + * ospf_dump.h: Likewise. + + * ospf_packet.c (ospf_hello): Display router ID on Bad NSSA Hello. + + * ospfd.c: Discard_LSA to stay away from LOCAL_XLT Process NSSA + 'never, candidate, always'. Change "suppress" to "not-advertise". + + * ospfd.h: Add TranslatorRole to struct ospf_area. Add anyNSSA to + struct ospf. + + * ospf_ase.c (ospf_ase_calculate_route): External to stay away + from LOCAL_XLT + + * ospf_nsm.c (ospf_db_summary_add): External to stay away from + LOCAL_XLT + + * ospf_abr.c: Major logic added for abr_nssa_task(). If ABR, and + NSSA translator, then do it. Approve the global list, and flush + any unapproved. + + * ospf_lsa.h: New LSA flag OSPF_LSA_LOCAL_XLT to indicate that the + Type-5 resulted from a Local Type-7 translation; not used for + flooding, but used for flushing. + + * ospf_flood.c: New NSSA flooding. + +2000-12-08 Michael Rozhavsky + + * ospfd.c (ospf_find_vl_data): New function for looking up virtual + link data. + (ospf_vl_set_security): Virtual link configuration with + authentication. + (ospf_vl_set_timers): Set timers for virtual link. + + * New commands are added. + "area A.B.C.D virtual-link A.B.C.D" + "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535>" + "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535> authentication-key AUTH_KEY" + "area A.B.C.D virtual-link A.B.C.D authentication-key AUTH_KEY" + "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535> message-digest-key <1-255> md5 KEY" + "area A.B.C.D virtual-link A.B.C.D message-digest-key <1-255> md5 KEY" + + * ospf_packet.c (ospf_check_md5_digest): Add neighbor's + cryptographic sequence number treatment. + (ospf_check_auth): OSPF input buffer is added to argument. + (ospf_read): Save neighbor's cryptographic sequence number. + + * ospf_nsm.c (nsm_change_status): Clear cryptographic sequence + number when neighbor status is changed to NSM down. + + * ospf_neighbor.c (ospf_nbr_new): Set zero to crypt_seqnum. + + * ospf_neighbor.h (struct ospf_neighbor): Add cryptographic + sequence number to neighbor structure. + +2000-11-29 Kunihiro Ishiguro + + * ospf_snmp.c (ospfIfLookup): OSPF MIB updates. + (ospfExtLsdbEntry): Add OspfExtLsdbTable treatment. + +2000-11-28 Michael Rozhavsky + + * ospfd.c (ospf_interface_down): Clear a ls_upd_queue queue of the + interface. + (ospf_ls_upd_queue_empty): New function to empty ls update queue + of the OSPF interface. + (no_router_ospf): 'no router ospf' unregister redistribution + requests from zebra. + +2000-11-28 Kunihiro Ishiguro + + * ospf_ism.c (ism_change_status): Increment status change number. + + * ospf_interface.h (struct ospf_interface): Add new member for + status change statistics. + + * Makefile.am: Update dependencies. + + * ospf_zebra.c (ospf_interface_add): OSPF SNMP interface update. + (ospf_interface_delete): OSPF SNMP interface delete. + + * ospf_snmp.h: New file is added. + +2000-11-23 Dick Glasspool + + * ospfd.h: Add new ospf_area structure member for + NSSATranslatorRole and NSSATranslator state. + + * ospfd.c: Provided for eventual commands to specify NSSA + elections for "translator- ALWAYS/NEVER/CANDIDATE". Provided for + decimal integer version of area-suppress. + + * ospf_flood.c: Flood Type-7's only into NSSA (not AS). + + * ospf_lsa.c: Undo some previous changes for NSSA. If NSSA + translator, advertise Nt bit. + + * ospf_route.c: 1st version of "sh ip os border-routers". + +2000-11-23 Michael Rozhavsky + + * ospfd.c (area_vlink): Virtual link can not configured in stub + area. + +2000-11-23 Gleb Natapov + + * ospf_packet.c (ospf_db_desc): In states Loading and Full the + slave must resend its last Database Description packet in response + to duplicate Database Description packets received from the + master. For this reason the slave must wait RouterDeadInterval + seconds before freeing the last Database Description packet. + Reception of a Database Description packet from the master after + this interval will generate a SeqNumberMismatch neighbor + event. RFC2328 Section 10.8 + (ospf_make_db_desc): DD Master flag treatment. + + * ospf_nsm.c (nsm_twoway_received): Move DD related procedure to + nsm_change_status(). + (nsm_bad_ls_req): Likewise. + (nsm_adj_ok): Likewise. + (nsm_seq_number_mismatch): Likewise. + (nsm_oneway_received): Likewise. + + * ospf_neighbor.h (struct ospf_neighbor): New structure member + last_send_ts for timestemp when last Database Description packet + was sent. + + * ospf_nsm.c (ospf_db_desc_timer): Make it sure nbr->last_send is + there. Call ospf_db_desc_resend() in any case. + +2000-11-16 Michael Rozhavsky + + * ospf_lsa.c (lsa_link_broadcast_set): When there is no DR on + network (suppose you have only one router with interface priority + 0). It's router LSA does not contain the link information about + this network. + + * ospf_nsm.c (nsm_timer_set): When you change a priority of + interface from/to 0 ISM_NeighborChange event should be scheduled + in order to elect new DR/BDR on the network. + + * ospf_interface.c (ip_ospf_priority): Likewise. + + * ospf_flood.c (ospf_ls_retransmit_add): When we add some LSA into + retransmit list we need to check whether the present old LSA in + retransmit list is not more recent than the new + one. + +2000-11-09 Dick Glasspool + + * ospf_packet.c: Allows for NSSA Type-7 LSA's throughout the NSSA + area. Any that exit the NSSA area are translated to type-5 LSA's. + The instantiated image is restored after translation. + (ospf_ls_upd_send_list): Renamed to ospf_ls_upd_queu_send(). + (ospf_ls_upd_send): Old function which enclosed by #ifdef 0 is + removed. + (ospf_ls_ack_send): Likewise. + + * ospf_flood.c: NSSA-LSA's without P-bit will be restricted to + local area. Otherwise they are allowed out the area to be + translated by ospf_packet.c. + + * ospf_lsa.c: Undo some previous changes for NSSA. + + * ospf_lsdb.h: New access for type 7. + +2000-11-07 Kunihiro Ishiguro + + * ospf_route.c (ospf_path_exist): New function to check nexthop + and interface are in current OSPF path or not. + (ospf_route_copy_nexthops_from_vertex): Add nexthop to OSPF path + when it is not there. Reported by Michael Rozhavsky + + +2000-11-06 Kunihiro Ishiguro + + * ospf_dump.c (config_write_debug): Add seventh string "detail" is + added for flag is OSPF_DEBUG_SEND | OSPF_DEBUG_RECV | + OSPF_DEBUG_DETAIL. + +2000-11-06 Michael Rozhavsky + + * ospf_lsa.c (router_lsa_flags): ASBR can't exit in stub area. + +2000-11-06 Kunihiro Ishiguro + + * ospf_lsa.c (ospf_router_lsa_originate): Reduce unconditional + logging. + +2000-11-06 Dick Glasspool + + * ospfd.h: Add ait_ntoa function prototype. + + * ospfd.c (ait_ntoa): New function for displaying area ID and + Stub/NSSA status. + (show_ip_ospf_interface_sub): Use ait_ntoa. + (show_ip_ospf_nbr_static_detail_sub): Likewise. + (show_ip_ospf_neighbor_detail_sub): Likewise. + + * ospf_route.c (ospf_intra_route_add): Set external routing type + to ospf route. + (ospf_intra_add_router): Likewise. + (ospf_intra_add_transit): Likewise. + (ospf_intra_add_stub): Likewise. + (ospf_add_discard_route): Likewise. + (show_ip_ospf_route_network): Use ait_ntoa. + (show_ip_ospf_route_network): Likewise. + (show_ip_ospf_route_router): Likewise. + + * ospf_lsa.c (show_lsa_detail): Use ait_ntoa. + (show_lsa_detail_adv_router): Likewise. + (show_ip_ospf_database_summary): Likewise. + + * ospf_route.h (struct route_standard): Add new member + external_routing. + + * ospf_ia.c (process_summary_lsa): Set external routing tyep to ospf + route. + (ospf_update_network_route): Likewise. + (ospf_update_router_route): Likewise. + +2000-11-04 Kunihiro Ishiguro + + * ospf_flood.c (ospf_process_self_originated_lsa): Enclose + OSPF_AS_NSSA_LSA treatment with #ifdef HAVE_NSSA. + +2000-11-03 Kunihiro Ishiguro + + * Unconditional logging is enclosed with if (IS_DEBUG_OSPF_EVENT). + Please specify "debug ospf event" for enable logging. + + * ospf_ism.c: Do not extern debug flag varible. It is done by + ospf_debug.h + * ospf_asbr.c: Likewise. + * ospf_lsa.c: Likewise. + * ospf_nsm.c: Likewise. + * ospf_zebra.c: Likewise. + + * ospf_dump.c (debug_ospf_event): New command "debug ospf event" + is added. + + * ospfd.c (router_ospf): Change logging from vty_out() to + zlog_info(). + (ospf_area_stub_cmd): Likewise. + + * ospf_dump.h: Extern term_debug flags. + (OSPF_DEBUG_EVENT): Add new flag. + (IS_DEBUG_OSPF_EVENT): Add new macro. + +2000-11-03 Dick Glasspool + + * ospf_flood.c (ospf_process_self_originated_lsa): + OSPF_AS_NSSA_LSA is treated as same as OSPF_AS_EXTERNAL_LSA. + (ospf_flood): Type-5's have no change. Type-7's can be received, + and will Flood the AS as Type-5's They will also flood the local + NSSA Area as Type-7's. The LSDB will be updated as Type-5's, and + during re-fresh will be converted back to Type-7's (if within an + NSSA). + (ospf_flood_through): Incoming Type-7's were allowed here if our + neighbor was an NSSA. So Flood our area with the Type-7 and also + if we are an ABR, flood thru AS as Type-5. + + * ospf_lsa.c (ospf_external_lsa_refresh): Flood NSSA both NSSA + area and other area. + + * ospf_packet.c (ospf_db_desc_proc): When AS External LSA is + exists in DD packet, make it sure that this area is not stub. + (ospf_ls_upd_list_lsa): When LSA type is NSSA then set lsa's area + to NULL. + (ospf_ls_upd): If the LSA is AS External LSA and the area is stub + then discard the lsa. If the LSA is NSSA LSA and the area is not + NSSA then discard the lsa. + +2000-11-03 Kunihiro Ishiguro + + * ospfd.c (ospf_interface_run): Fix bug of Hello packet's option + is not properly set when interface comes up. + +2000-11-02 Kunihiro Ishiguro + + * ospfd.h (OSPF_OPTION_O): Add new hello header option. + +2000-11-01 Dick Glasspool + + * ospf_lsa.h: Define OSPF_MAX_LSA to 8 when HAVE_NSSA is enabled. + (OSPF_GROUP_MEMBER_LSA): Define OSPF_GROUP_MEMBER_LSA. + + * ospf_lsa.c (show_database_desc): Add "Group Membership LSA" + string. + +2000-10-31 Dick Glasspool + + * ospf_lsa.h (OSPF_AS_NSSA_LSA): Define OSPF_AS_NSSA_LSA. + + * ospf_lsa.c (show_ip_ospf_database): NSSA database display + function is added. ALIASES which have "show ip ospf database + nssa-external" is added. + (show_ip_ospf_border_routers): New command "show ip ospf + border-routers" is added. + +2000-10-30 Dick Glasspool + + * ospfd.c (router_ospf): NSSA Enabled message is added for + testing. + (ospf_area_type_set): Are type set for NSSA area. + (ospf_area_stub_cmd): Special translation of no_summary into NSSA + and summary information. If NSSA is enabled pass the information + to ospf_area_type_set(). + (area_nssa): New commands are added: + "area A.B.C.D nssa" + "area <0-4294967295> nssa" + "area A.B.C.D nssa no-summary" + "area <0-4294967295> nssa no-summary" + (ospf_no_area_stub_cmd): Special translation of no_summary into + NSSA and summary information. If external_routing is + OSPF_AREA_NSSA unset area with ospf_area_type_set (area, + OSPF_AREA_DEFAULT). + (show_ip_ospf_area): Display NSSA status. + (config_write_ospf_area): Show NSSA configuration. + + * ospf_packet.c (ospf_hello): For NSSA support, ensure that NP is + on and E is off. + +2000-10-26 Gleb Natapov + + * ospf_lsa.c (ospf_network_lsa_body_set): The network-LSA lists + those routers that are fully adjacent to the Designated Router; + each fully adjacent router is identified by its OSPF Router ID. + The Designated Router includes itself in this list. RFC2328, + Section 12.4.2. + +2000-10-23 Jochen Friedrich + + * ospf_snmp.c: ospf_oid and ospfd_oid are used in smux_open after + it is registered. So those variables must be static. + +2000-10-18 K N Sridhar + + * ospfd.c: Add area_default_cost_decimal_cmd and + no_area_default_cost_decimal_cmd alias. + +2000-10-05 Gleb Natapov + + * ospfd.c (ospf_network_new): Fix setting area format. + (no_router_ospf): Check area existance when calling + ospf_interface_down(). + + * ospf_flood.c (ospf_external_info_check): Fix bug of refreshing + default route. + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 is released. + +2000-09-29 Kunihiro Ishiguro + + * ospf_snmp.c (ospfHostEntry): OSPF Host MIB is implemented. + + * ospfd.c (ospf_nbr_static_cmp): OSPF neighbor is sorted by it's + address. + +2000-09-28 Michael Rozhavsky + + * ospf_interface.c (ospf_if_free): Fix deleting self neighbor twice. + +2000-09-27 Kunihiro Ishiguro + + * ospf_packet.c (ospf_read): Solaris on x86 has ip_len with host + byte order. + +2000-09-25 Toshiaki Takada + + * ospfd.c (ospf_compatible_rfc1583), (no_ospf_compatible_rfc1583): + Add CISCO compatible command. + +2000-09-25 Kunihiro Ishiguro + + * ospf_abr.c (ospf_area_range_lookup): New function is added for + area range lookup in OSPF-MIB. + (ospf_area_range_lookup_next): Likewise. + +2000-09-22 Kunihiro Ishiguro + + * ospfd.c (no_router_ospf): Delete virtual link before deleting + area structure. + + * ospf_lsa.c (ospf_external_lsa_refresh_type): Check + EXTERNAL_INFO(type). + + * ospfd.c (no_router_ospf): Call ospf_vl_delete() instead of + ospf_vl_data_free(). + + * ospf_interface.c (ospf_vl_shutdown): Execute ISM_InterfaceDown + when ospf_vl_shutdown is called. + (ospf_vl_delete): Call ospf_vl_shutdown() to delete virtual link + interface's thread. + +2000-09-21 Gleb Natapov + + * ospf_lsa.c: New implementation of OSPF refresh. + +2000-09-20 Kunihiro Ishiguro + + * ospf_snmp.c (ospfLsdbLookup): Add LSDB MIB implementation. + +2000-09-18 Kunihiro Ishiguro + + * ospf_snmp.c (ospfStubAreaEntry): Add OSPF stub area MIB. + +2000-09-18 Gleb Natapov + + * ospf_route.h (route_standard): Change member from `struct area' + to area_id. + + * ospf_abr.c (ospf_abr_announce_network), (ospf_abr_should_announce), + (ospf_abr_process_network_rt), (ospf_abr_announce_rtr), + (ospf_abr_process_router_rt): + * ospf_ase.c (ospf_find_asbr_route), + (ospf_find_asbr_router_through_area), + * ospf_ia.c (ospf_find_abr_route), (ospf_ia_router_route), + (process_summary_lsa), (ospf_update_network_route), + (ospf_update_router_route): + * ospf_route.c (ospf_intra_route_add), (ospf_intra_add_router), + (ospf_intra_add_transit), (ospf_intra_add_stub), + (ospf_route_table_dump), (show_ip_ospf_route_network), + (show_ip_ospf_route_router), (ospf_asbr_route_cmp), + (ospf_prune_unreachable_routers): + * ospf_spf.c (ospf_rtrs_print): + * ospfd.c (ospf_rtrs_free): Fix the struct change above. + +2000-09-14 Kunihiro Ishiguro + + * ospf_network.c (ospf_serv_sock_init): Enclose SO_BINDTODEVICE + with ifdef. + +2000-09-13 Gleb Natapov + + * ospf_ism.c (ospf_elect_dr), (ospf_elect_bdr): Fix DR election. + + * ospf_network.c (ospf_serv_sock_init): Add socket option + SO_BINDTODEVICE on read socket. + + * ospf_packet.c (ospf_hello): Ignore Hello packet if E-bit does + not match. + + * ospfd.c (ospf_area_check_free), (ospf_area_get), + (ospf_area_add_if): New function added. + +2000-09-13 Kunihiro Ishiguro + + * ospf_route.c (ospf_intra_add_router): Update ABR and ASBR router + count. + + * ospf_spf.c (ospf_spf_init): Rest ABR and ASBR router count + starting SPF calculation. + + * ospfd.h (struct ospf_area): Add ABR and ASBR router count. + +2000-09-12 Kunihiro Ishiguro + + * ospfd.c (ospf_area_id_cmp): New area structure is sorted by area + ID. + + * ospf_lsa.c (ospf_router_lsa_originate): For OSPF MIB update + lsa_originate_count. + (ospf_network_lsa_originate): Likewise. + (ospf_summary_lsa_originate): Likewise. + (ospf_summary_asbr_lsa_originate): Likewise. + (ospf_external_lsa_originate): Likewise. + +2000-09-11 Kunihiro Ishiguro + + * ospf_snmp.c (ospf_variables): ospfRouterID's type RouterID + syntax is IpAddress. + (ospf_admin_stat): New function for OSPF administrative status + check. + +2000-09-10 Jochen Friedrich + + * ospf_snmp.c: Implement OSPF MIB skeleton. + +2000-09-08 Kunihiro Ishiguro + + * ospf_snmp.c: New file is added. + +2000-09-07 David Lipovkov + + * ospf_zebra.c (ospf_interface_delete): Add pseudo interface + treatment. + + * ospf_interface.c (interface_config_write): Likewise. + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 is released. + +2000-08-17 Michael Rozhavsky + + * ospfd.c (ospf_area_free): Remove virtual link configuration only + when Area is removed. + +2000-08-17 Kunihiro Ishiguro + + * ospfd.c (network_area): Revert check for EXTERNAL_INFO + (ZEBRA_ROUTE_CONNECT). + (no_network_area): Likewise. + +2000-08-16 Kunihiro Ishiguro + + * ospfd.h (struct ospf): Add distance_table and + distance_{all,intra,inter,external}. + + * ospf_zebra.c: Add OSPF distance related functions. + +2000-08-15 Gleb Natapov + + * ospf_asbr.c (ospf_external_info_find_lsa): New function added. + + * ospf_lsa.c (ospf_default_external_info), + (ospf_default_originate_timer), (ospf_external_lsa_refresh_default): + New function added. + + * ospf_zebra.c + (ospf_default_information_originate_metric_type_routemap), + (ospf_default_information_originate_always_metric_type_routemap): + Change name and add route-map function. + (ospf_default_information_originate_metric_routemap), + (ospf_default_information_originate_routemap), + (ospf_default_information_originate_type_metric_routemap): + New DEFUN added. + +2000-08-14 Kunihiro Ishiguro + + * ospf_zebra.c (zebra_interface_if_set_value): Change ifindex + restore size from two octet to four. + +2000-08-14 Michael Rozhavsky + + * ospf_ase.c (ospf_ase_incremental_update): Implement incremental + AS-external-LSA in 16.6 of RFC2328. + +2000-08-14 Matthew Grant + + * ospf_interface.c (ospf_if_get_output_cost): Change cost + calculation algorithm. + + * ospf_packet (ospf_ls_upd): Fix problem of LSA retransmitting. + +2000-08-11 Michael Rozhavsky + + * ospf_lsa.c (ospf_maxage_lsa_remover): Fix maxage remover for + AS-external-LSAs. + +2000-08-10 Toshiaki Takada + + * ospfd.c (auto_cost_reference_bandwidth): New DEFUN added. + `auto-cost reference-bandwidth' OSPF router command added. + +2000-08-08 Gleb Natapov + + * ospf_routemap.c (ospf_route_map_update): New function added. + Add route-map event hook. + +2000-08-08 Toshiaki Takada + + * ospf_zebra.c (ospf_distribute_check_connected): If redistribute + prefix is connected route on OSPF enabled interface, suppress to + announce it. + +2000-08-08 Matthew Grant + + * ospf_interface.c (ospf_if_get_output_cost): + New function added. Handle bandwidth parameter for cost + calculation. + +2000-08-08 Michael Rozhavsky + + * ospf_interface.c (interface_config_write): Show interface + configuration regardless interface is down. + + * ospf_ase.c (ospf_ase_caocluate_route): Whole rewritten external + route calculate function. + +2000-08-08 Gleb Natapov + + * ospf_routemap.c: New file added. + + * ospf_asbr.c (ospf_reset_route_map_set_values), + (ospf_route_map_set_compare): New function added. + + * ospf_lsa.c (ospf_external_lsa_body_set): Set routemap metric + with AS-external-LSA. + +2000-08-05 Kunihiro Ishiguro + + * ospf_ase.c (ospf_ase_calculate_route_add): Pass new->cost to + ospf_zebra_add as metric. + (ospf_ase_calculate_route_add): Likewise. + + * ospf_route.c (ospf_route_install): Pass or->cost to + ospf_zebra_add as metric. + + * ospf_zebra.c (ospf_zebra_add): Add metric arguemnt. + (ospf_zebra_delete): Likewise. + +2000-08-03 Matthew Grant + + * ospf_flood.c (ospf_flood_delayed_lsa_ack): New function added. + Dispatch delayed-ACK with flooding AS-external-LSA across virtual + link. + +2000-07-31 Matthew Grant + + * ospfd.c (show_ip_ospf_area): Fix lack of VTY_NEWLINE when + `show ip ospf'. + + * ospf_interface.c (ospf_if_free): Fix bug of crash with + Point-to-Point interface. + +2000-07-27 Michael Rozhavsky + + * ospf_flood.c (ospf_process_self_originated_lsa): + Make sure to clear LSA->param (redistributed external information) + before refreshment. + +2000-07-27 Gleb Natapov + + * ospfd.c (refresh_group_limit), (refresh_per_slice), + (refresh_age_diff): New defun added. Refresher related parameter + can be configurable. + +2000-07-27 Akihiro Mizutani + + * ospf_interface.c (interface_config_write): Print `description' + config directive to work. + +2000-07-24 Akihiro Mizutani + + * ospf_interface.c (ospf_if_init): Use install_default for + INTERFACE_NODE. + +2000-07-24 Gleb Natapov + + * ospf_packet.c (ospf_ls_upd_send_list), (ospf_ls_upd_send_event), + (ospf_ls_ack_send_list), (ospf_ls_ack_send_event): New function added. + This make sending always as many LS update/Ack combined in one ospf + packet. + +2000-07-24 Gleb Natapov + + * ospf_packet.c (ospf_ls_upd_list_lsa): Set NULL to lsa->area if + LSA is AS-external-LSA. + + * ospf_nsm.c (nsm_reset_nbr): Do not cancel Inactivity timer. + +2000-07-21 Toshiaki Takada + + * ospf_zebra.c (ospf_default_originate_timer): Set timer for + `default-information originate'. Fix some default originate + related functions. + +2000-07-12 Toshiaki Takada + + * ospf_lsa.c (stream_put_ospf_metric): New function added. + +2000-07-12 Toshiaki Takada + + * ospf_lsa.c (show_ip_ospf_database_router), + (show_ip_ospf_database_network), (show_ip_ospf_database_summary), + (show_ip_ospf_database_summary_asbr), (show_ip_ospf_database_externel), + (show_router_lsa), (show_any_lsa), (show_router_lsa_self), + (show_any_lsa_self): Functions removed. + + (show_lsa_prefix_set), (show_lsa_detail_proc), (show_lsa_detail), + (show_lsa_detail_adv_router_proc), (show_lsa_detail_adv_router): + New functions added. Replace above functions. + + (show_ip_ospf_database_all), (show_ip_ospf_database_self_originated): + Functions removed. + (show_ip_ospf_database_summary): New functions added. Replace + above functions. + + (show_ip_ospf_database_cmd): DEFUN rearranged. + (show_ip_ospf_database_type_id_cmd), + (show_ip_ospf_database_type_id_adv_router_cmd), + (show_ip_ospf_database_type_is_self_cmd): New ALIASes added. + (show_ip_ospf_database_type_adv_rotuer_cmd): New DEFUN added. + (show_ip_ospf_database_type_self_cmd): New ALIAS added. + +2000-07-11 Toshiaki Takada + + * ospf_asbr.c (ospf_external_info_new), + (ospf_external_info_free): New functions added. + + * ospf_lsa.h (ospf_lsa): Add new member `void *param' to set + origination parameter for external-LSA. + Remove member `redistribute'. + + * ospf_zebra.c (ospf_redistirbute_set): When `redistribute' + command executed, metric and metric-type values are overridden. + If one of those is changed refresh AS-external-LSAs for appropriate + type. + +2000-07-11 Michael Rozhavsky + + * ospf_lsa.c (ospf_summary_lsa_refresh), + (ospf_summary_asbr_lsa_refresh): Make sure to refresh summary-LSAs. + + * ospf_abr.c (set_metric): New function added. + +2000-07-07 Toshiaki Takada + + * ospf_zebra.c (ospf_default_information_originate_metric_type), + (ospf_default_information_originate_type_metric): New defun added. + Metic and Metric type can be set to default route. + (ospf_default_information_originate_always_metric_type): + (ospf_default_information_originate_always_type_metric): + New defun added. Metric and Metric type can be set to default + always route. + + * ospf_zebra.c (ospf_default_metric), (no_ospf_default_metric): + New defun added. + +2000-07-06 Gleb Natapov + + * ospf_flood.c (ospf_flood_through_area): Fix bug of considering + on the same interface the LSA was received from. + +2000-07-06 Michael Rozhavsky + + * ospfd.c (ospf_config_write): Fix bug of printing `area stub' + command with `write mem'. + + * ospfd.c (no_router_ospf): Remove installed routes from zebra. + + * ospf_zebra.c (ospf_interface_delete): Fix function to handle + zebra interface delete event. + +2000-07-06 Toshiaki Takada + + * ospf_zebra.c (ospf_default_information_originate), + (ospf_default_information_originate_always): New DEFUN added. + +2000-07-05 Michael Rozhavsky + + * ospf_route.c (ospf_terminate): Make sure to remove external route + when SIGINT received. + +2000-07-03 Gleb Natapov + + * ospf_flood.c, ospf_ism.c, ospf_lsa,c, ospfd.c: Make sure to free + many structure with `no router ospf'. + +2000-06-30 Gleb Natapov + + * ospf_neighbor.c (ospf_nbr_new), + ospf_nsm.c (nsm_timer_set): Start LS update timer only + when neighbor enters Exchange state. + +2000-06-29 Gleb Natapov + + * ospf_nsm.c (nsm_timer_set), (nsm_exchange_done), + ospf_packet.c (ospf_db_desc_proc): + Do not cancel DD retransmit timer when Master. + +2000-06-29 Gleb Natapov + + * ospf_abr.c (ospf_abr_announce_network_to_area), + (ospf_abr_announce_rtr_to_area) + ospf_ase.c (ospf_ase_rtrs_register_lsa), + ospf_flood.c (ospf_process_self_originated_lsa), + (ospf_flood_through_area), (ospf_ls_request_delete), + ospf_interface.c (ospf_if_free), + ospf_ism.c (ism_change_status), + ospf_lsa.c (ospf_router_lsa_update_timer), + (ospf_router_lsa_install), (ospf_network_lsa_install), + (ospf_lsa_maxage_delete), (ospf_lsa_action), + (ospf_schedule_lsa_flood_area), + ospf_nsm.c (nsm_change_status), + ospf_packet.c (ospf_make_ls_req_func), (ospf_make_ls_ack): + Use ospf_lsa_{lock,unlock} for all looking-up of LSA. + + * ospf_flood.c (ospf_ls_request_free): Function deleted. + + * ospf_lsa.c (ospf_discard_from_db): New function added. + +2000-06-26 Toshiaki Takada + + * ospfd.h (ospf): struct member `external_lsa' name changed to + `lsdb'. + +2000-06-26 Toshiaki Takada + + * ospf_lsa.c (ospf_lsa_install), (ospf_router_lsa_install), + (ospf_network_lsa_install), (ospf_summary_lsa_install), + (ospf_summary_asbr_lsa_install), (ospf_external_lsa_install): + Functions re-arranged. + + * ospf_lsa.c (IS_LSA_MAXAGE), (IS_LSA_SELF): Macro added. + +2000-06-20 Michael Rozhavsky + + * ospf_packet.c (ospf_ls_req), (ospf_ls_upd), (ospf_ls_ack): Add + verification of LS type. + +2000-06-20 Gleb Natapov + + * ospf_ase.c (ospf_ase_calculate_timer): Add more sanity check + whether rn->info is NULL. + +2000-06-20 Toshiaki Takada + + * ospfd.c (show_ip_ospf_interface_sub): Show Router-ID of both + DR and Backup correctly with `show ip ospf interface' command. + +2000-06-20 Toshiaki Takada + + * ospf_lsa.c (ospf_lsa_lock), (ospf_lsa_unlock), + (ospf_lsa_discard): These functions are used for avoiding + unexpected reference to freed LSAs. + +2000-06-13 Kunihiro Ishiguro + + * ospf_packet.c (ospf_ls_upd): Initialize lsa by NULL to avoid + warning. + +2000-06-12 Kunihiro Ishiguro + + * ospf_ase.h (ospf_ase_rtrs_register_lsa): Add prototype. + +2000-06-12 Toshiaki Takada + + * ospf_lsa.c (ospf_external_lsa_install): Make sure to register + LSA to rtrs_external when replacing AS-external-LSAs in LSDB. + Fix core dump. + +2000-06-10 Toshiaki Takada + + * ospf_lsdb.c (id_to_prefix), (ospf_lsdb_hash_key), + (ospf_lsdb_hash_cmp), (ospf_lsdb_new), (ospf_lsdb_iterator), + (lsdb_free), (ospf_lsdb_free), (ospf_lsdb_add), (ospf_lsdb_delete), + (find_lsa), (ospf_lsdb_lookup), (find_by_id), + (ospf_lsdb_lookup_by_id), (ospf_lsdb_lookup_by_header): Functinos + removed for migration to new_lsdb. + + * ospf_lsa.c (ospf_summary_lsa_install), + (ospf_summary_asbr_lsa_install), (ospf_maxage_lsa_remover), + (ospf_lsa_maxage_walker), (ospf_lsa_lookup), + (ospf_lsa_lookup_by_id): Use new_lsdb instead of ospf_lsdb. + (count_lsa), (ospf_lsa_count_table), (ospf_lsa_count), + (ospf_get_free_id_for_prefix): Funcitions removed. + +2000-06-09 Gleb Natapov + + * ospf_ism.c (ism_interface_down): Prevent some unneeded DR changes. + + * ospf_packet.c (ospf_db_desc_proc): Fix memory leak. + (ospf_hello): Always copy router-ID when hello is received. + +2000-06-08 Gleb Natapov + + * ospf_lsa.h (struct ospf_lsa): Add member of pointer to struct + ospf_area. + +2000-06-08 Michael Rozhavsky + + * ospf_ase.c (ospf_asbr_route_same): New function added. + This function makes sure external route calculation more + precisely. + +2000-06-07 Michael Rozhavsky + + * ospf_ism.c (ism_change_status): Use ospf_lsa_flush_area for + network-LSA deletion instead of using ospf_lsdb_delete. + Also cancel network-LSA origination timer. + +2000-06-07 Levi Harper + + * ospf_interface.c (ospf_if_down): Close read fd when an interface + goes down. + +2000-06-05 Kunihiro Ishiguro + + * ospf_asbr.c (ospf_external_info_lookup): Add explicit brace for + avoid ambiguous else. + + * ospf_flood.c (ospf_external_info_check): Likewise. + +2000-06-05 Toshiaki Takada + + * ospf_nsm.c (nsm_adj_ok): Fix bug of DR election. + +2000-06-04 Toshiaki Takada + + * ospf_zebra.c (ospf_default_information_originate), + (no_ospf_default_information_originate): New DEFUN added. + +2000-06-03 Toshiaki Takada + + * ospf_lsa.h, ospf_asbr.h (external_info): Struct moved from + ospf_lsa.h to ospf_asbr.h. + + * ospf_lsa.c, ospf_asbr.c (ospf_external_info_add), + (ospf_external_info_delete): Function moved from ospf_lsa.c + to ospf_asbr.c. + +2000-06-03 Toshiaki Takada + + * ospf_flood.c (ospf_external_info_check): New function added. + (ospf_process_self_orignated_lsa): Make sure to flush + self-originated AS-external-LSA, when router reboot and no longer + originate those AS-external-LSA. + +2000-06-02 Toshiaki Takada + + * ospf_network.c (ospf_serv_sock): Remove SO_DONTROUTE + socket option. + + * ospf_packet.c (ospf_write): Set MSG_DONTROUTE flag for + unicast destination packets. + +2000-06-02 Toshiaki Takada + + * ospf_lsdb.c (new_lsdb_delete): Delete entry from LSDB only when + specified LSA matches. + +2000-06-02 Gleb Natapov + + * ospf_network.c (ospf_serv_sock): Set SO_DONTROUTE + socket option. + +2000-06-01 Akihiro Mizutani + + * ospf_dump.c: Replace string `Debugging functions\n' with DEBUG_STR. + Replace string `OSPF information\n' with OSPF_STR. + +2000-06-01 Toshiaki Takada + + * ospf_lsdb.[ch]: Use new_lsdb struct for network-LSA instead of + ospf_lsdb. + +2000-06-01 Toshiaki Takada + + * ospf_dump.c (config_debug_ospf_packet), (config_debug_ospf_event), + (config_debug_ospf_ism), (config_debug_ospf_nsm), + (config_debug_ospf_lsa), (config_debug_ospf_zebra), + (term_debug_ospf_packet), (term_debug_ospf_event), + (term_debug_ospf_ism), (term_debug_ospf_nsm), + (term_debug_ospf_lsa), (term_debug_ospf_zebra): Repalce debug_ospf_* + variable to use for debug option flags. + + (debug_ospf_packet), (debug_ospf_ism), (debug_ospf_nsm), + (debug_ospf_lsa), (debug_ospf_zebra): Set {config,term}_debug_* + flags when vty->node is CONFIG_NODE, otherwise set only term_debug_* + flags. + + * ospf_dump.h (CONF_DEBUG_PACKET_ON), (CONF_DEBUG_PACKET_OFF), + (TERM_DEBUG_PACKET_ON), (TERM_DEBUG_PACKET_OFF), + (CONF_DEBUG_ON), (CONF_DEBUG_OFF), (IS_CONF_DEBUG_OSPF_PACKET), + (IS_CONF_DEBUG_OSPF): New Macro added. + +2000-05-31 Toshiaki Takada + + * ospfd.c (clear_ip_ospf_neighbor): New DEFUN added. + Currently this command is used for only debugging. + + * ospf_nsm.c (nsm_change_status): Make sure thread cancellation + for network-LSA when DR has no full neighbors. + + * ospf_nsm.c (ospf_db_summary_clear): New function added. + +2000-05-30 Toshiaki Takada + + * ospf_lsdb.c (new_lsdb_insert): LSAs are always freed by + maxage_lsa_remover when LSA is replaced. + +2000-05-25 Gleb Natapov + + * ospf_flood.c (ospf_ls_retransmit_delete_nbr_all): Add argument + `struct ospf_area' to remove LSA from Link State retransmission list + of neighbor from only one Area. + +2000-05-24 Michael Rozhavsky + + * ospf_lsdb.c (ospf_lsdb_add): Preserve flags field when + overriting old LSA with new LSA. + +2000-05-24 Gleb Natapov + + * ospf_lsa.c (ospf_router_lsa_body_set): Fix bug of router-LSA + size calculation. + +2000-05-22 Michael Rozhavsky + + * ospf_route.c (ospf_intra_add_stub): + * ospf_spf.h (struct vertex): Use u_int32_t for distance (cost) + value instead of u_int16_t. + +2000-05-22 Axel Gerlach + + * ospf_ia.c (ospf_ia_network_route): Fix bug of Inter-area route + equal cost path calculation. + +2000-05-21 Toshiaki Takada + + * ospf_ase.c (ospf_ase_calculate_route_delete): New function added. + Make sure, when rotuer route is deleted, related external routes + are also deleted. + +2000-05-20 Toshiaki Takada + + * ospfd.c (ospf_interface_down): Make sure interface flag is disable + and set fd to -1. + +2000-05-16 Toshiaki Takada + + * ospf_asbr.c (ospf_asbr_should_announce), (ospf_asbr_route_remove): + Functions removed. + + * ospfd.h (EXTERNAL_INFO): Macro added. + Substitute `ospf_top->external_info[type]' with it. + +2000-05-16 Toshiaki Takada + + * ospf_lsa.c (ospf_rtrs_external_remove): New function added. + +2000-05-14 Gleb Natapov + + * ospf_flood.c (ospf_ls_retransmit_delete_nbr_all) + * ospf_lsdb.c (new_lsdb_insert) + * ospf_packet.c (ospf_ls_ack): Fix database synchonization problem. + +2000-05-14 Gleb Natapov + + * ospf_lsa.h (tv_adjust), (tv_ceil), (tv_floor), (int2tv), + (tv_add), (tv_sub), (tv_cmp): Prototype definition added. + + * ospf_nsm.h (ospf_db_summary_delete_all): Prototype definition added. + +2000-05-13 Toshiaki Takada + + * ospf_lsa.[ch] (ospf_lsa): struct timestamp type is changed from + time_t to struct timeval. + (tv_adjust), (tv_ceil), (tv_floor), (int2tv), (tv_add), + (tv_sub), (tv_cmp): timeval utillity functions added. + +2000-05-12 Toshiaki Takada + + * ospf_lsa.[ch] (ospf_schedule_update_router_lsas): Delete function. + Change to use macro OSPF_LSA_UPDATE_TIMER instead of using + this function. + router-LSA refresh timer related stuff is re-organized. + +2000-05-10 Gleb Natapov + + * ospf_interface.c (ospf_vl_set_params): + * ospf_packet.c (ospf_check_network_mask): + * ospf_spf.[ch] (ospf_spf_next): + Remove field address from `struct vertex', and search for peer + address of virtual link in function `ospf_vl_set_params' instead. + +2000-05-10 Gleb Natapov + + * ospf_packet.c (ospf_ls_upd): Fix some memory leak related LSA. + +2000-05-08 Thomas Molkenbur + + * ospf_packet.c (ospf_packet_dup): Replace ospf_steram_copy() + with ospf_stream_dup() to fix memory leak. + +2000-05-08 Michael Rozhavsky + + * ospf_flood.c (ospf_flood_through_area): Fix the problem of + LSA update without DROther. + +2000-05-04 Gleb Natapov + + * ospf_spf.c (ospf_vertex_free): Fix memory leak of SPF calculation. + +2000-05-03 Toshiaki Takada + + * ospf_neighbor.c (ospf_db_summary_add): Use new_lsdb struct + instead linked-list. + (ospf_db_summary_count), (ospf_db_summary_isempty): + New function added. + + * ospf_lsa.c (ospf_rotuer_lsa): Re-arrange and divide functions. + +2000-05-02 Gleb Natapov + + * ospf_lsdb.c (new_lsdb_cleanup): Fix memory leak. When LSDB are + not needed any more, then free them. + +2000-05-02 Toshiaki Takada + + * ospfd.c (timers_spf), (no_timers_spf): New defun added. + SPF calculation timers related stuff is rearranged. + + * ospf_spf.c (ospf_spf_calculate_timer_add): Function removed. + SPF timer is scheduled by SPF calculation delay and holdtime + configuration variable. + + * ospf_lsa.c (ospf_external_lsa_nexthop_get): Set AS-external-LSA's + forwarding address when nexthop learned by other protocols is + in the OSPF domain. + + * ospf_zebra.c (ospf_redistribute_source_metric_type), + (ospf_redistribute_source_type_metric): Re-arrange DEFUNs and + ALIASes. + +2000-05-01 Toshiaki Takada + + * ospf_flood.c (ospf_ls_retransmit_count), + (ospf_ls_retransmit_isempty): New function added. + + (ospf_ls_retransmit_add), (ospf_ls_retransmit_delete), + (ospf_ls_retransmit_clear), (ospf_ls_retransmit_lookup), + (ospf_ls_retransmit_delete_all), (ospf_ls_retransmit_delete_nbr_all), + (ospf_ls_retransmit_add_nbr_all): Replace these functions to use + new_lsdb. + +2000-04-29 Toshiaki Takada + + * ospfd.c (no_network_area): Add check Area-ID whether specified + Area-ID with prefix matches config. + +2000-04-27 Toshiaki Takada + + * ospf_lsa.c (ospf_maxage_lsa_remover): Fix problem of + remaining withdrawn routes on zebra. + +2000-04-25 Michael Rozhavsky + + * ospf_nsm.c (nsm_kill_nbr), (nsm_ll_down), (nsm_change_status), + (ospf_nsm_event): Fix network-LSA re-origination problem. + +2000-04-24 Toshiaki Takada + + * ospf_nsm.c (ospf_db_desc_timer): Fix bug of segmentation fault + with DD retransmission. + + * ospf_nsm.c (nsm_kill_nbr): Fix bug of re-origination when + a neighbor disappears. + +2000-04-23 Michael Rozhavsky + + * ospf_abr.c (ospf_abr_announce_network_to_area): Fix bug of + summary-LSAs reorigination. Correctly copy OSPF_LSA_APPROVED + flag to new LSA. when summary-LSA is reoriginatd. + + * ospf_flood.c (ospf_flood_through_area): Fix bug of flooding + procedure. Change the condition of interface selection. + +2000-04-21 Toshiaki Takada + + * ospf_lsa.c (ospf_refresher_register_lsa): Fix bug of refresh never + occurs. + + * ospfd.c (show_ip_ospf_neighbor_id): New defun added. + `show ip ospf neighbor' related commands are re-arranged. + +2000-04-20 Toshiaki Takada + + * ospf_dump.c (debug_ospf_zebra): New defun added. + Suppress zebra related debug information. + +2000-04-19 Toshiaki Takada + + * ospf_zebra.c (ospf_distribute_list_update_timer), + (ospf_distribute_list_update), (ospf_filter_update): + New function added. Re-organize `distribute-list' router ospf + command. + +2000-04-13 Michael Rozhavsky + + * ospf_packet.c (ospf_make_ls_upd): Add check for MAX_AGE. + +2000-04-14 Michael Rozhavsky + + * ospf_packet.c (ospf_make_ls_upd): Increment LS age by configured + interface transmit_delay. + +2000-04-14 Sira Panduranga Rao + + * ospf_interface.c (ip_ospf_cost), (no_ip_ospf_cost): + Add to schedule router_lsa origination when the interface cost changes. + +2000-04-12 Toshiaki Takada + + * ospf_lsa.c (ospf_refresher_register_lsa), + (ospf_refresher_unregister_lsa): Fix bug of core dumped. + + * ospfd.c (no_router_ospf): Fix bug of core dumped. + +2000-03-29 Toshiaki Takada + + * ospf_nsm.c (nsm_oneway_received): Fix bug of MS flag unset. + +2000-03-29 Michael Rozhavsky + + * ospf_lsa.c (ospf_network_lsa): + * ospf_nsm.c (ospf_nsm_event): Fix bug of Network-LSA originated + in stub network. + +2000-03-28 Toshiaki Takada + + * ospf_nsm.c (nsm_bad_ls_req), (nsm_seq_number_mismatch), + (nsm_oneway_received): Fix bug of NSM state flapping between + ExStart and Exchange. + +2000-03-28 Toshiaki Takada + + * ospf_packet.h (strcut ospf_header): Fix the size of ospf_header, + change u_int8_t to u_char. + +2000-03-27 Toshiaki Takada + + * ospf_lsa.c (ospf_lsa_checksum): Take care of BIGENDIAN architecture. + +2000-03-27 Toshiaki Takada + + * ospfd.c (ospf_interface_run): Make sure Address family matches. + +2000-03-26 Love + + * ospf_packet.c (ospf_write): Chack result of sendto(). + +2000-03-26 Sira Panduranga Rao + + * ospf_nsm.c (nsm_oneway_received): Fix bug of 1-WayReceived in NSM. + +2000-03-23 Libor Pechacek + + * ospf_lsa.c (ospf_network_lsa) + * ospf_lsdb.c (new_lsdb_insert): Fix bug of accessing to + unallocated memory. + +2000-03-23 Toshiaki Takada + + * ospfd.c (ospf_config_write): Fix bug of duplicate line for + `area A.B.C.D authentication'. + +2000-03-22 Toshiaki Takada + + * ospf_debug.c (debug_ospf_lsa), (no_debug_ospf_lsa): Defun added. + Suppress all zlog related to LSAs with this config option. + +2000-03-21 Kunihiro Ishiguro + + * ospf_nsm.c (ospf_nsm_event): Add check for NSM_InactivityTimer. + +2000-03-21 Toshiaki Takada + + * ospf_packet.c (ospf_ls_upd_timer), (ospf_ls_req): + Fix bug of memory leak about linklist. + + * ospf_flood.c (ospf_flood_through_area): Likewise. + +2000-03-18 Sira Panduranga Rao + + * ospf_flood.c (ospf_ls_retransmit_lookup): Add checksum comparison + to identify LSA uniquely. This fix routes lost. + +2000-03-18 Toshiaki Takada + + * ospf_ase.c (ospf_find_asbr_route): Add sanity check with router + routing table. + +2000-03-17 Alex Zinin + + * ospf_spf.[ch]: Bug fix. + The 2nd stage of Dijkstra could consider one vertex + more than once if there is more than one link + between the routers, thus adding extra CPU overhead + and extra next-hops. + Fixed. + +2000-03-15 Sira Panduranga Rao + + * ospf_nsm.c (nsm_inactivity_timer): Changed to call nsm_kill_nbr(). + +2000-03-14 Toshiaki Takada + + * ospf_route.c (ospf_route_copy_nexthops): Fix bug of memory leak of + ospf_path. Actually ignore merging ospf_route with completely same + paths. + +2000-03-12 Toshiaki Takada + + * ospf_lsa.c (show_as_external_lsa_detail): fix bug of + external route tag byte order. + +2000-03-11 Toshiaki Takada + + * ospf_lsdb.c (ospf_lsdb_insert): New function added. + +2000-03-09 Toshiaki Takada + + * ospf_lsa.c (ospf_external_lsa_install), + (ospf_lsa_lookup), (show_ip_ospf_database_all), + (show_ip_ospf_database_self_originate): Use struct new_lsdb for + LSDB of AS-external-LSAs instead of ospf_lsdb. + + * ospf_lsa.c (ospf_lsa_unique_id): New function added. + Use for assigning Unique Link State ID instead of + ospf_get_free_id_for_prefix(). + +2000-03-09 Toshiaki Takada + + * ospf_ase.c (ospf_ase_calculate_timer): Fix bug of segmentation + fault reported by George Bonser . + +2000-03-07 Libor Pechacek + + * ospfd.c (ospf_interface_down): Fix bug of segmentation fault. + +2000-03-06 Toshiaki Takada + + * ospf_route.c (ospf_route_cmp): Change meaning of return values. + +2000-03-02 Alex Zinin + * ospfd.h, ospf_ia.h + New Shortcut ABR code. Now area's flag can be configured + with Default, Enable, and Disable values. + More info will be in the new ver of I-D soon (see IETF web). + +2000-02-25 Toshiaki Takada + + * ospf_lsa.c (ospf_lsa_header_set), (ospf_external_lsa_body_set), + (osfp_external_lsa_originate), (ospf_external_lsa_queue), + (ospf_external_lsa_originate_from_queue): New function added. + (ospf_external_lsa): Function removed. + + * ospf_zebra.c (ospf_zebra_read_ipv4): Originate AS-external-LSA + when listen a route from Zebra, instead creating external route. + + * ospf_asbr.c (ospf_asbr_route_add_flood_lsa), + (ospf_asbr_route_add_queue_lsa), + (ospf_asbr_route_install_lsa), (ospf_asbr_route_add): + Functions removed. + + * ospf_ase.c (process_ase_lsa): Function will not be used. + (ospf_ase_calculate), (ospf_ase_calculate_route_add), + (ospf_ase_calculate_new_route), (ospf_ase_caluculate_asbr_route): + process_ase_lsa () is separated to these functions. + + OSPF AS-external-LSA origination is whole re-organized. + +2000-02-18 Toshiaki Takada + + * ospf_packet.c (ospf_ls_upd): Fix bug of OSPF LSA memory leak. + + * ospf_asbr.c (ospf_asbr_route_add_flood_lsa), + (ospf_asbr_route_add_queue_lsa): Fix bug of OSPF external route + memory leak. + +2000-02-12 Kunihiro Ishiguro + + * ospf_asbr.c (ospf_asbr_route_install_lsa): Re-calculate LSA + checksum after change Advertised Router field. + +2000-02-09 Toshiaki Takada + + * ospf_asbr.c (ospf_external_route_lookup): Add new function. + +2000-02-08 Toshiaki Takada + + * ospfd.c (ospf_router_id_get), (ospf_router_id_update), + (ospf_router_id_update_timer): Router ID decision algorithm is changed. + Router ID is chosen from all of eligible interface addresses even if + it is not enable to OSPF. + +2000-02-08 Toshiaki Takada + + * ospf_asbr.c (ospf_asbr_route_add): Function divided to + ospf_asbr_route_add_flood_lsa, ospf_asbr_route_add_queue_lsa and + ospf_asbr_route_install_lsa. If Router-ID is not set, then LSA is + waited to install to LSDB. + `0.0.0.0 adv_router' AS-external-LSA origination bug was fixed. + +2000-02-01 Sira Panduranga Rao + + * ospf_flood.c (ospf_ls_retransmit_lookup): Compare LS seqnum + in the ACK before deleting. + + * ospf_packet.c (ospf_hello): Reset the flags after a shutdown + and no shutdown of the interface. + +2000-01-31 Toshiaki Takada + + * ospf_packet.c (ospf_ls_req): Send multiple Link State Update + packets respond to a Link State Request packet. + + * ospfd.c (show_ip_ospf_neighbor_detail_sub): Show thread state. + + * ospf_interface.c (ospf_vl_new): Crash when backbone area + is not configured and set virtual-link to no-backbone area, + bug fixed. + +2000-01-30 Kunihiro Ishiguro + + * ospf_neighbor.h (struct ospf_neighbor): Add pointer to last send + LS Request LSA. + + * ospf_packet.c (ospf_ls_upd): Comment out LS request list + treatment. That should be done in OSPF flooding procedure. + + * ospf_flood.c (ospf_flood_through_area): Enclose + ospf_check_nbr_loding inside if-else close. + +2000-01-31 Toshiaki Takada + + * ospf_packet.c (ospf_make_ls_upd): Fix bug of #LSAs counting. + +2000-01-29 Toshiaki Takada + + * ospf_packet.c (ospf_make_md5_digest): Fix bug of md5 authentication. + +2000-01-28 Toshiaki Takada + + * ospfd.c (show_ip_ospf): Show Number of ASE-LSAs. + +2000-01-27 Kunihiro Ishiguro + + * ospf_packet.c (ospf_make_db_desc): Don't use rm_list for + removing LSA from nbr->db_summary. + +2000-01-27 Sira Panduranga Rao + + * ospf_packet.c (ospf_ls_upd_send): Set AllSPFRouters to + destination when the link is point-to-point. + (ospf_ls_ack_send_delayed): Likewise. + +2000-01-27 Kunihiro Ishiguro + + * ospf_flood.c (ospf_ls_request_delete_all): Fix bug of next + pointer lookup after the node is freed. + +2000-01-26 Kunihiro Ishiguro + + * ospf_asbr.c (ospf_asbr_route_add): Instead of scanning all AS + external route, use ospf_top->external_self. + +2000-01-27 Toshiaki Takada + + * ospf_lsa.c (ospf_forward_address_get): New function added. + + * ospf_asbr.c (ospf_asbr_check_lsas): Originate AS-external-LSA + only when it should be replaced. + +2000-01-25 Kunihiro Ishiguro + + * ospf_flood.c (ospf_ls_retransmit_clear): Delete list node. + + * ospf_lsa.c (ospf_lsa_free): Reduce logging message using + ospf_zlog value. + + * ospf_ism.c (ism_change_status): Fix bug of DR -> non DR status + change. Self originated LSA is freed but not deleted from lsdb. + +2000-01-24 Kunihiro Ishiguro + + * ospf_ism.c (ism_interface_down): Don't use router_id for + detecting self neighbor structure. Instead of that compare + pointer itself. + + * ospf_neighbor.c (ospf_nbr_free): Cancel all timer when neighbor + is deleted. + (ospf_nbr_free): Free last send packet. + + * ospf_neighbor.h (struct ospf_neighbor): Remove host strucutre. + Instead of that src is introduced. + + * ospf_nsm.h: Enclose macro defenition with do {} while (0). + +2000-01-17 Kunihiro Ishiguro + + * ospfd.c: Change part of passive interface implementation. For + passive interface just disabling sending/receiving Hello on the + interface. + +2000-01-16 Kai Bankett + + * ospf_interface.h (OSPF_IF_PASSIVE): Add passive flag. + * ospf_interface.c (ospf_if_lookup_by_name): Add new function. + * ospf_lsa.c (ospf_router_lsa): Skip passive interface. + * ospfd.c (passive_interface): New command passive-interface is + added. + (ospf_config_write): Print passive interface. + +2000-01-15 Toshiaki Takada + + * ospf_interface.h (crypt_key): New struct added to store + multiple cryptographic autheitication keys. + (ospf_interface): struct changed. + + * ospf_interface.c: ospf_crypt_key_new, ospf_crypt_key_add, + ospf_crypt_key_lookup, ospf_crypt_key_delete: new functions added. + + * ospf_packet.c (ip_ospf_message_digest_key): Changed to store + multiple cryptographic authentication keys. + +2000-01-14 Toshiaki Takada + + * ospf_interface.c: DEFUN (if_ospf_*) commands changed name to + ip_ospf_* (). + Old notation `ospf *' still remains backward compatibility. + +1999-12-29 Alex Zinin + * ospf_lsa.c: ospf_lsa_more_recent() bug fix + * ospf_nsm.c, ospf_packet.c: remove nbr data struct when + int goes down, also check DD flags correctly (bug fix) + +1999-12-28 Alex Zinin + * "redistribute metric-type (1|2) metric " added + +1999-12-23 Alex Zinin + * added RFC1583Compatibility flag + * added dynamic interface up/down functionality + +1999-11-19 Toshiaki Takada + + * ospf_neighbor.h (struct ospf_neighbor): Add member state_change + for NSM state change statistics. + +1999-11-19 Toshiaki Takada + + * ospfd.c (show_ip_ospf_neighbor_detail), + (show_ip_ospf_neighbor_int_detail): DEFUN Added. + +1999-11-14 Kunihiro Ishiguro + + * ospf_asbr.c (ospf_asbr_check_lsas): Add check of + lsa->refresh_list. + +1999-11-11 Toshiaki Takada + + * ospf_ia.[ch] (OSPF_EXAMINE_SUMMARIES_ALL): Macro added. + This macro is expanded to ospf_examine_summaries () + for SUMMARY_LSA and SUMMARY_LSA_ASBR. + (OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL): Macro added. + This macro is expanded to ospf_examine_transit_summaries () + for SUMMARY_LSA and SUMMARY_LSA_ASBR. + +1999-11-11 Toshiaki Takada + + * ospf_lsa.[ch] (ospf_find_self_summary_lsa_by_prefix): Changed to + macro OSPF_SUMMARY_LSA_SELF_FIND_BY_PREFIX. + (ospf_find_self_summary_asbr_lsa_by_prefix): Changed to + macro OSPF_SUMMARY_ASBR_LSA_SELF_FIND_BY_PREFIX. + (ospf_find_self_external_lsa_by_prefix): Changed to + macro OSPF_EXTERNAL_LSA_SELF_FIND_BY_PREFIX. + +1999-11-11 Toshiaki Takada + + * ospfd.c (ospf_abr_type): ospf_abr_type_cisco, ospf_abr_type_ibm, + ospf_abr_type_shortcut and ospf_abr_type_standard DEFUNs are + combined. + * ospfd.c (no_ospf_abr_type): no_ospf_abr_type_cisco, + no_ospf_abr_type_ibm and no_ospf_abr_type_shortcut DEFUNS are + combined. + +1999-11-10 Toshiaki Takada + + * ospf_route.c (ospf_lookup_int_by_prefix): Move function to + ospf_interface.c and change name to ospf_if_lookup_by_prefix (). + +1999-11-01 Alex Zinin + * ospf_packet.c + some correction to LSU processing + + * ospf_lsa.c ospfd.h + randomize initial LSA refreshment interval + and limit the size of LSA-group to 10 + to let randomization work more effectively. + +1999-10-31 Alex Zinin + * ospf_interface.c + cancel t_network_lsa_self + when freeing int structure + + * ospf_abr.c ospf_asbr.c ospf_flood.c ospf_lsa.c + ospf_lsa.h ospf_lsdb.h ospfd.c ospfd.h + + Summary and ASE LSA refreshment functions + added---LSA refreshment is paced to 70 LSAs + per sec to avoid link overflow. Refreshment events + are further randomized within a 10 sec interval + to avoid syncing. + + Also the sigfault of memcmp() in ospf_lsa_is_different() + is fixed. + +1999-10-30 Alex Zinin + * ospf_nsm.c + Fix the bug where MAX_AGE LSAs + are included into the DB summary. + + * ospf_interface.c + allocate 2*MTU input buffer instead of just MTU + for the cases when the other router mistakenly + sends larger packets thus causing fragmentation, etc. + + * ospf_nsm.c + in nsm_reset_nbr() lists should be freed + not when they are empty. + +1999-10-29 Kunihiro Ishiguro + + * ospf_zebra.c (ospf_acl_hook): Move OSPF_IS_ASBR and OSPF_IS_ABR + check inside of if (ospf_top). + +1999-10-29 Alex Zinin + * ospf_lsa.c ospf_lsdb.c : + add assertion in lsa and lsa->data alloc functions, + as well as in lsdb_add for new->data + + * ospf_lsdb.c: free hash table correctly + +1999-10-28 John Capo + + * ospf_packet.h (OSPF_PACKET_MAX): Correct MAX packet length + calculation + +1999-10-27 Kunihiro Ishiguro + + * OSPF-TRAP-MIB.txt: New file added. Edited version of RFC1850. + + * OSPF-MIB.txt: New file added. Edited version of RFC1850. + +1999-10-27 Alex Zinin + * ospfd, ospf_zebra, ospf_abr + "area import-list" command is added. + This command allows to filter the inter-area routes + injected into an area. Access list hook function + extended to invalidate area exp/imp lists. + +1999-10-25 Yoshinobu Inoue + + * ospfd.c (ospf_interface_run): Enable to detect P2P network + on an OSPF interface. + +1999-10-19 Jordan Mendelson + + * ospf_lsdb.c (ospf_lsdb_add): Fix bug of crash + in ospf_ls_retransmit_lookup (). + +1999-10-19 Vladimir B. Grebenschikov + + * ospf_route.c: Workaround about installation of OSPF routes into + the zebra daemon. Add checking of existance routes. Free + ospf_top->old_table if it exists. + +1999-10-15 Jordan Mendelson + + * Add support for MD5 authentication. + +1999-10-12 Alex Zinin + * ospfd.c, ospfd.h, ospf_abr.c: + a new command "area export-list" was added, it allows + the admin. to control which intra-area routes are + announced to other areas by the ABR + +1999-10-12 Alex Zinin + * ospf_asbr.c (ospf_asbr_check_lsas): Fix bug of coredump + when "no redistribute" is used after a distribute list + denying some networks was used + +1999-10-05 Toshiaki Takada + + * ospf_route.c (ospf_path_dup): New function added. + +1999-10-05 Toshiaki Takada + + * ospf_interface.[ch]: Some of VL related funciton name changed. + +1999-09-27 Alex Zinin + + * ospf_zebra.c: Distribute-list functionality added + +1999-09-27 Toshiaki Takada + + * ospfd.c (show_ip_ospf): Fix bug of segmentation fault when no ospf + instance exists. + +1999-09-25 Kunihiro Ishiguro + + * ospfd.c (ospf_interface_down): Fix bug of misusing nextnode() + instead of node->next. Reported by Hiroki Ishibashi + . + + * ospf_route.c (show_ip_ospf_route): Add check for ospf is enabled + or not. + +1999-09-23 Alex Zinin + + * stub area support added + +1999-09-23 Alex Zinin + + * fwd_addr in ASE-LSAs is now set correctly + * ASE routing changed to check the fwd_addr + and skip the route if the addr points to one + of our interfaces to avoid loops. + +1999-09-22 Alex Zinin + + * ospf_interface: + ospf_vls_in_area() added, it returns + the number of VLs configured through the area + + * ospf_interface.c ospf_lsa.c ospf_lsdb.c ospfd.c + honor correct mem alloc + +1999-09-22 Alex Zinin + + * memory.[ch]: + Some OSPF mem types added, + plus more info in "show mem" + +1999-09-21 Alex Zinin + + * ospfd.c: + "area range substitute" added. + It can be used on NAT-enabled (IP-masquarade) + routers to announce private networks + from an area as public ones into the outside + world (not in the RFC, btw :) + +1999-09-21 Alex Zinin + + * ospfd.c: + "area range suppress" added. + This command allows to instruct the router + to be silent about specific ranges, i.e., + it is a method of route filtering on area + borders + +1999-09-21 Alex Zinin + + * ospfd.c VLs removed when "no network area" executed + +1999-09-20 Alex Zinin + + * ospf_ase.c bug fix for not-zero fwd_addr + and directly connected routes. + +1999-09-20 Yon Uriarte + + * ospf_packet.c (ospf_make_ls_req): Introduce delta value for + checking the length of OSPF packet exceeds MTU or not. + + * ospf_lsa.c (ospf_lsa_different): Apply ntohs for checking + l1->data->length. + +1999-09-18 Alex Zinin + + * ospf_lsa.c bug fix for ospf_network_lsa() to + include itself into the RID list + +1999-09-10 Alex Zinin + + * Alternative ABR behaviors IBM/Cisco/Shortcut + implemented + +1999-09-10 Alex Zinin + + * router and network-LSA origination + changed to honor MinLSInterval + +1999-09-08 Alex Zinin + + * modified ABR behavior to honor VLs and transit + areas + +1999-09-07 Alex Zinin + + * completed VL functionality + +1999-09-06 Kunihiro Ishiguro + + * ospf_asbr.c: New file. + ospf_asbr.h: New file. + + * ospf_zebra.c (ospf_redistribute_connected): Add redistribute + related stuff. + +1999-09-05 Kunihiro Ishiguro + + * ospfd.h (OSPF_FLAG_VIRTUAL_LINK): Change OSPF_FLAG_VEND to + OSPF_FLAG_VIRTUAL_LINK for comprehensiveness. + +1999-09-03 Kunihiro Ishiguro + + * ospf_spf.c (ospf_spf_register): Change name from + ospf_spf_route_add() to ospf_spf_register(). + Include "ospfd/ospf_abr.h" for ospf_abr_task() prototype. + +1999-09-02 Kunihiro Ishiguro + + * ospf_lsa.c (ospf_external_lsa_install): Change to update + lsa->data rather than install new one, when same id lsa is already + installed. + +1999-09-01 Kunihiro Ishiguro + + * ospf_lsa.c (ospf_router_lsa_install): Return lsa value. + (ospf_network_lsa_install): Likewise. + (ospf_summary_lsa_install): Likewise. + (ospf_summary_asbr_lsa_install): Likewise. + (ospf_external_lsa_install): Likewise. + + * ospf_spf.c (ospf_spf_calculate): Comment out debug function + ospf_rtrs_print(). + +1999-08-31 Kunihiro Ishiguro + + * ospf_spf.c (ospf_rtrs_free): Add ospf_spf_calculate() for + freeing rtrs. + +1999-08-31 Toshiaki Takada + + * ospf_lsa.c (show_ip_ospf_database_summary), + (show_ip_ospf_database_summary_asbr), + (show_ip_ospf_database_external): New function added. + `show ip ospf database summary', + `show ip ospf database asbr-summary' + `show ip ospf database external' command can be used. + + * ospf_lsa.c (ospf_lsa_count_table): New function added. + (show_ip_ospf_database_all): show nothing if a type of LSA + does not exist. + +1999-08-31 Kunihiro Ishiguro + + * ospf_lsa.c (ospf_maxage_lsa_remover): Preserve next pointer when + the node is deleted. + +1999-08-31 Toshiaki Takada + + * ospf_flood.c (ospf_ls_retransmit_lookup): change to return + struct ospf_lsa *. + (ospf_ls_request_new), (ospf_ls_request_free), + (ospf_ls_request_add), (ospf_ls_request_delete), + (ospf_ls_request_delete_all), (ospf_ls_request_lookup): + New function added. + + * ospf_packet.c (ospf_ls_upd_send_lsa): New function added. + + * ospf_lsa.h (LS_AGE): Slightly change macro definition. + + * ospf_lsa.c (ospf_lsa_more_recent), (ospf_lsa_diffrent): + Use LS_AGE macro. + +1999-08-30 Alex Zinin + + * ospfd.c + fix a bug with area range config write + added "show ip ospf" command, it will be enhanced later on + +1999-08-30 Alex Zinin + + * ospf_lsa.c + updated ospf_router_lsa() to honor flags (B-bit) + +1999-08-30 Alex Zinin + + * ospf_abr.c + wrote major functions implementing ABR activity + +1999-08-30 Alex Zinin + + * ospf_ia.c ospf_route.c ospf_route.h + fixed the bug with ospf_route.origin field. + Now it holds pointer to lsa_header + +1999-08-30 Alex Zinin + + * ospf_flood.c ospf_flood.h: + transformed ospf_flood_if_select into ospf_flood_through_area() + added new ospf_flood_if_select() and ospf_flood_through_as() + +1999-08-30 Toshiaki Takada + + * ospf_flood.[ch]: New file added. + + * ospf_packet.c (ospf_lsa_flooding), + (ospf_lsa_flooding_select_if): functions move to ospf_flood.c + + * ospf_neighbor.c (ospf_put_lsa_on_retransm_list), + (ospf_remove_lsa_from_retransm_list), + (ospf_nbr_remove_all_lsas_from_retransm_list), + (ospf_lsa_remove_from_ls_retransmit): + (ospf_lsa_retransmit): functions move to + ospf_flood.c, and change function's name: + + ospf_put_lsa_on_retransm_list () + -> ospf_ls_retransmit_add () + ospf_remove_lsa_from_retransm_list () + -> ospf_ls_retransmit_delete () + ospf_nbr_remove_all_lsas_from_retransm_list () + -> ospf_ls_retransmit_clear () + ospf_lsa_remove_from_ls_retransmit () + -> ospf_ls_retransmit_delete_nbr_all () + ospf_lsa_retransmit () + -> ospf_ls_retransmit_add_nbr_all () + + * ospf_lsa.c (ospf_lsa_lookup_from_list): function move to + ospf_flood.c, and change name to ospf_ls_retransmit_lookup (). + +1999-08-30 Kunihiro Ishiguro + + * ospf_neighbor.c (ospf_nbr_lookup_by_addr): Use + route_node_lookup() instead of route_node_get(). + + * ospf_packet.c (ospf_ls_upd): Temporary comment out (6) check. + +1999-08-30 Kunihiro Ishiguro + + * ospf_route.c (ospf_lookup_int_by_prefix): Add check of + oi->address. + +1999-08-29 Alex Zinin + * ospf_lsa.c + MaxAge LSA deletion functions added. + +1999-08-29 Alex Zinin + * ospf_neighbor.c + ospf_nbr_lookup_by_addr(): added route_unlock_node() + when function returns NULL if (rn->info == NULL) + +1999-08-29 Alex Zinin + * ospfd.c + added a hack for area range deletion + +1999-08-29 Alex Zinin + * ospf_lsa.h + included lsdb field into struct ospf_lsa, to find + LSDB easier when removing MaxAge LSAs. + +1999-08-29 Alex Zinin + * ospf_lsa.c ospf_neighbor.c ospf_nsm.c + ospf_packet.c changed to honor new retransmit list + management functions + +1999-08-29 Alex Zinin + * ospf_neighbor.c , .h added new retransmit list functions. + +1999-08-29 Alex Zinin + * Makefile.in + added ospf_ase, ospf_abr, ospf_ia + +1999-08-29 Alex Zinin + * ospf_spf.c: + - changed ospf_next_hop_calculation() to include interface + and nexthop addr for directly connected routers---more informative + and solves problem with route installation into the kernel + - changed ospf_nexthop_out_if_addr() to support routers, not only + transit networks + - added ospf_process_stubs(); + +1999-08-29 Alex Zinin + * ospf_lsa.c: + - changed ospf_router_lsa() to provide correct links + for p-t-p interfaces; + - changed ospf_summary_lsa_install() to support table + of self-originated summary-LSAs; + - added ospf_summary_asbr_lsa_install() and ospf_external_lsa_install() + - changed ospf_lsa_install() accordingly + - changed show_ip_ospf_database_router_links() to support p-t-p + +1999-08-29 Kunihiro Ishiguro + + * ospf_packet.c (ospf_make_db_desc): Only master can clear more + flag. + +1999-08-29 Kunihiro Ishiguro + + * ospf_packet.c (ospf_read): Add check of IP src address. + +1999-08-28 Alex Zinin + * ospf_neighbor.h + added ospf_nbr_lookup_by_routerid() + +1999-08-28 Alex Zinin + * ospfd.h + added ABR/ASBR flag definitions and fields; + added iflist field to area structure; + summary_lsa_self and summary_lsa_asbr_self are changed + to be route tables; + added ranges field---configured area ranges; + A separate Routers RT added; + area range config commands and config write added + + +1999-08-28 Alex Zinin + * ospf_route.c : + ospf_route_free()--added code to free the list of paths; + The following functions added: + ospf_intra_add_router(); + ospf_intra_add_transit(); + ospf_intra_add_stub(); + the last function uses new ospf_int_lookup_by_prefix(); + show_ip_ospf_route_cmd()--changed to support new RT structure; + added ospf_cmp_routes()--general route comparision function; + added ospf_route_copy_nexthops() and ospf_route_copy_nexthops_from_vertex() + they are used in ASE and IA routing; + added ospf_subst_route() and ospf_add_route(); + +1999-08-28 Alex Zinin + * ospf_route.h : + changed struct ospf_path to include output interface, + changed struct ospf_route to support IA and ASE routing. + added prototypes of the function used in IA and ASE modules. + +1999-08-28 Alex Zinin + * ospf_lsa.h ospf_lsa.c : + added ospf_my_lsa(), an interface independent version of + ospf_lsa_is_self_originated(), it will be used in ASE and IA-routing. + +1999-08-27 Kunihiro Ishiguro + + * ospf_interface.c (interface_config_write): Add check for + oi->nbr_self. + +1999-08-25 Toshiaki Takada + + * ospf_lsa.c (ospf_lsa_dup): New function added. + + * ospf_packet.c (ospf_write), (ospf_read): Print send/recv + interface in debug message. + +1999-08-25 Toshiaki Takada + + * ospf_packet.c (ospf_ls_ack_send): The name is changed from + `ospf_ls_ack_send'. + (ospf_ls_ack_send_delayed) (ospf_ls_ack_timer): New function added. + Delayed Link State Acknowledgment is scheduled by timer. + +1999-08-25 Alex Zinin + + * ospf_lsa.c (ospf_router_lsa): Incorrectly included link to + a stub network instead of link to a transit network into + originated router-LSA, bug fixed. + +1999-08-24 Toshiaki Takada + + * ospfd.c (ospf_update_router_id): New function added. + + * ospf_network.c (ospf_write): Create new socket per transmission. + And select outgoing interface whether dst is unicast or multicast. + + * ospf_packet.c: LSA flooding will work. + +1999-08-24 VOP + + * ospf_route.c: Include "sockunion.h" + +1999-08-24 Kunihiro Ishiguro + + * ospf_network.c (ospf_serv_sock_init): Enclose + IPTOS_PREC_INTERNETCONTROL setting with #ifdef for OS which does + not have the definition. + +1999-08-23 Toshiaki Takada + + * ospf_packet.c: Fix bug of DD processing. + +1999-08-18 Toshiaki Takada + + * ospf_lsa.c (show_ip_ospf_database): Show actual `LS age'. + +1999-08-17 Toshiaki Takada + + * ospf_lsa.h (OSPF_MAX_LSA): The value of OSPF_MAX_LSA is + corrected. The bug of `mes_lookup' is fixed. + This had been reported by Poul-Henning Kamp . + + * ospf_lsa.c (ospf_router_lsa_install): The name is changed from + `ospf_add_router_lsa'. + (ospf_network_lsa_install): The name is changed from + `ospf_add_network_lsa'. + + * ospf_interface.h (ospf_interface): Add member `nbr_self'. + + * ospf_interface.c (ospf_if_is_enable): New function added. + +1999-08-16 Toshiaki Takada + + * ospf_lsa.h (struct lsa_header): The name is changed from + `struct ospf_lsa'. + (struct ospf_lsa): New struct added to control each LSA's aging + and timers. + + * ospf_lsa.c (ospf_lsa_data_free): The name is change from + `ospf_lsa_free'. + (ospf_lsa_data_new), (ospf_lsa_new), (ospf_lsa_free), + (ospf_lsa_different), (ospf_lsa_install): New function added. + + * ospf_packet.c (ospf_ls_upd_list_lsa): New function added. + +1999-08-12 Toshiaki Takada + + * ospf_nsm.c (nsm_reset_nbr): New function added. + KillNbr and LLDown neighbor event call this function. + +1999-08-10 Toshiaki Takada + + * ospf_packet.c (ospf_ls_retransmit) + (ospf_ls_upd_timer): New function added. + Set retransmission timer for Link State Update. + +1999-07-29 Toshiaki Takada + + * ospf_ism.c (ospf_dr_election): Fix bug of DR election. + +1999-07-28 Toshiaki Takada + + * ospf_network.c (ospf_serv_sock_init): Set IP precedence field + with IPTOS_PREC_INTERNET_CONTROL. + + * ospf_nsm.c (nsm_change_status): Schedule NeighborChange event + if NSM status change. + + * ospf_packet.c (ospf_make_hello): Never include a neighbor in + Hello packet, when the neighbor goes down. + +1999-07-26 Kunihiro Ishiguro + + * Makefile.am (noinst_HEADERS): Add ospf_route.h. + + * ospf_route.c (show_ip_ospf_route): Add `show ip ospf route' + command. + +1999-07-25 Toshiaki Takada + + * ospf_lsa.c (ospf_router_lsa): Fix bug of LS sequence number + assignement. + +1999-07-25 Kunihiro Ishiguro + + * ospf_route.c (ospf_route_table_free): New function added. + + * ospf_spf.c (ospf_spf_next): Free vertex w when cw's and w's + distance is same. + + * ospfd.h (struct ospf): Add old_table. + + * ospf_main.c (sighup): Call of log_rotate () removed. + + * ospf_lsa.c (ospf_lsa_is_self_originated): Fix bug of checking + area->lsa as self LSA. This should be area->lsa_self. + +1999-07-24 Kunihiro Ishiguro + + * ospf_zebra.c (ospf_zebra_add): ospf_zebra_add + (),ospf_zebra_delete () added. + + * ospf_spf.c (ospf_spf_calculate): Call ospf_intra_route_add (). + +1999-07-24 Toshiaki Takada + + * ospf_lsa.c: Change LS sequence number treatment. + (ospf_lsa_is_self_originated): New function added. + (show_ip_ospf_database_self_originated): New DEFUN added. + +1999-07-23 Kunihiro Ishiguro + + * ospf_interface.c (ospf_if_lookup_by_addr): Add loopback check. + +1999-07-22 Toshiaki Takada + + * ospf_spf.c (ospf_nexthop_new), (ospf_nexthop_free), + (ospf_nexthop_dup): function added. + (ospf_nexthop_calculation): function changed. + + * ospf_interface.c (ospf_if_lookup_by_addr): function added. + +1999-07-21 Toshiaki Takada + + * ospf_spf.c (ospf_spf_closest_vertex): function removed. + +1999-07-21 Kunihiro Ishiguro + + * ospf_spf.c (ospf_spf_next): Apply ntohs for fetching metric. + +1999-07-21 Toshiaki Takada + + * ospf_neighbor.c (ospf_nbr_lookup_by_router_id): fundtion removed. + + * ospf_lsa.c (show_ip_ospf_database_router): describe each + connected link. + +1999-07-21 Kunihiro Ishiguro + + * ospf_spf.c (ospf_spf_next): V is router LSA or network LSA so + change behavior according to LSA type. + (ospf_lsa_has_link): Link check function is added. + +1999-07-20 Kunihiro Ishiguro + + * ospf_spf.c (ospf_spf_calculate_schedule): Add new function for + SPF calcultion schedule addtition. + (ospf_spf_calculate_timer_add): Rough 30 sec interval SPF calc + timer is added. + (ospf_spf_next_router): Delete ospf_spf_next_network (). + + * ospf_lsa.c (show_ip_ospf_database_all): Network-LSA display + header typo correction. Display of router LSA's #link added. + +1999-07-19 Toshiaki Takada + + * ospf_packet.c (ospf_check_network_mask): Added new function for + receiving Raw IP packet on an appropriate interface. + +1999-07-16 Toshiaki Takada + + * ospfd.c (ospf_router_id): new DEFUN added. + +1999-07-15 Toshiaki Takada + + * ospf_spf.c (ospf_spf_init), (ospf_spf_free), + (ospf_spf_has_vertex), (ospf_vertex_lookup), + (ospf_spf_next_router), (ospf_spf_next_network), + (ospf_spf_closest_vertex), (ospf_spf_calculate): + function added. + +1999-07-13 Toshiaki Takada + + * ospf_ism.c: fix bug of DR Election. + + * ospf_nsm.c: fix bug of adjacency forming. + +1999-07-05 Kunihiro Ishiguro + + * ospfd.c (ospf_init): Change to use install_default. + +1999-07-01 Rick Payne + + * ospf_zebra.c (zebra_init): Install standard commands to + ZEBRA_NODE. + +1999-06-30 Toshiaki Takada + + * ospf_dump.c: Whole debug command is improved. + (ISM|NSM) (events|status|timers) debug option added. + (show_debugging_ospf): new DEFUN added. + +1999-06-30 Kunihiro Ishiguro + + * ospf_lsa.c (ospf_lsa_lookup_from_list): Change !IPV4_ADDR_CMP to + IPV4_ADDR_SAME. + +1999-06-29 Toshiaki Takada + + * ospf_dump.c (ospf_summary_lsa_dump): Add summary-LSA dump routine. + (ospf_as_external_lsa_dump): Add AS-external-LSA dump routine. + + * ospf_nsm.c (nsm_twoway_received): fix condtion of adjacnet. + + * ospf_ism.c (ospf_dr_election): fix DR Election. + + * ospf_dump.c (ospf_nbr_state_message): fix `show ip ospf neighbor' + command's state. + +1999-06-29 Kunihiro Ishiguro + + * ospf_dump.c (ospf_router_lsa_dump): Add router-LSA dump routine. + +1999-06-28 Toshiaki Takada + + * ospf_lsa.c (show_ip_ospf_database_network): fix bug of + `show ip ospf database network' command output. + + * ospf_nsm.c (nsm_inactivity_timer): Clear list of Link State + Retransmission, Database Summary and Link State Request. + + * ospf_packet.c (ospf_ls_req_timer): New function added. + Set Link State Request retransmission timer. + +1999-06-27 Kunihiro Ishiguro + + * ospf_main.c (main): Change default output from ZLOG_SYSLOG to + ZLOG_STDOUT. + + * ospfd.c (ospf_init): Register show_ip_ospf_interface_cmd and + show_ip_ospf_neighbor_cmd to VIEW_NODE. + + * ospf_lsa.c (ospf_lsa_init): Register show_ip_ospf_database_cmd + and show_ip_ospf_database_type_cmd to VIEW_NODE. + +1999-06-25 Toshiaki Takada + + * ospf_packet.c: fix bug of DD making. + fix bug of LS-Update reading. + +1999-06-23 Toshiaki Takada + + * ospf_packet.c: All type of packets are changed to use + fifo queue structure. + (ospf_fill_header) function added. + +1999-06-22 Toshiaki Takada + + * ospf_packet.c (ospf_packet_new): New function added to handle + sending ospf packet by fifo queue structure. + (ospf_packet_free), (ospf_fifo_new), (ospf_fifo_push), + (ospf_fifo_pop), (ospf_fifo_head), (ospf_fifo_flush), + (ospf_fifo_free): Likewise. + +1999-06-21 Toshiaki Takada + + * ospf_nsm.c (ospf_db_desc_timer): function added. + (nsm_timer_set) function added. + * ospf_dump.c (ospf_option_dump): function added. + * ospf_packet.c (ospf_ls_req) (ospf_make_ls_req): function added. + +1999-06-20 Toshiaki Takada + + * ospf_lsa.c (ospf_lsa_more_recent): function added. + * ospf_neighbor.h (struct ospf_neighbor): Change member ms_flag + to dd_flags. + +1999-06-19 Toshiaki Takada + + * ospf_lsa.c: DEFUN (show_ip_ospf_database) Added. + * ospf_interface.c (if_ospf_cost), (if_ospf_dead_interval), + (if_ospf_hello_interval), (if_ospf_priority), + (if_ospf_retransmit_interval), (if_ospf_transmit_delay) + argument changed from NUMBER to . + DEFUN (if_ospf_network_broadcast), + DEFUN (if_ospf_network_non_broadcast), + DEFUN (if_ospf_network_point_to_multipoint), + DEFUN (if_ospf_network_point_to_point) functions are combined to + DEFUN (if_ospf_network). + +1999-06-18 Toshiaki Takada + + * ospf_lsa.c: ospf_add_router_lsa (), ospf_add_network_lsa (), + ospf_lsa_lookup (), ospf_lsa_count () Added. + +1999-06-15 Toshiaki Takada + + * DEFUN (ospf_debug_ism), DEFUN (ospf_debug_nsm), + DEFUN (no_ospf_debug_ism), DEFUN (no_ospf_debug_nsm) Added. + `debug ospf ism' command shows debug message. + `debuf ospf nsm' command shows debug message. + +1999-06-14 Toshiaki Takada + + * ospf_lsa.c: ospf_network_lsa () Added. + ospf_lsa_checksum () Added. + * DEFUN (ospf_debug_packet), DEFUN (no_ospf_debug_packet) Added. + `debug ospf packet' command shows debug message. + +1999-06-13 Toshiaki Takada + + * ospf_packet.h: Remove struct ospf_ls_req {}, ospf_ls_upd {}, + ospf_ls_ack {}. + +1999-06-11 Toshiaki Takada + + * ospf_dump.c: fix IP packet length treatment. + +1999-06-10 Toshiaki Takada + + * ospf_ism.h: Add OSPF_ISM_EVENT_EXECUTE() Macro Added. + * ospf_nsm.h: Add OSPF_NSM_EVENT_EXECUTE() Macro Added. + + * ospf_packet.c: ospf_db_desc (), ospf_db_desc_send () Added. + ospf_make_hello (), ospf_make_db_desc () Added. + ospf_db_desc_proc () Added.n + + * Database Description packet can be processed. + +1999-06-08 Toshiaki Takada + + * ospf_lsa.c: New file. + +1999-06-07 Toshiaki Takada + + * ospf_neighbor.c: ospf_fully_adjacent_count () Added. + +1999-06-07 Kunihiro Ishiguro + + * ospf_spf.[ch]: New file. + +1999-05-30 Kunihiro Ishiguro + + * ospf_zebra.c: Changed to use lib/zclient.c routines. + + * ospf_zebra.h (zebra_start): Remove struct zebra. + +1999-05-29 Kunihiro Ishiguro + + * ospfd.c (ospf_config_write): Add cast (unsigned long int) to + ntohl for sprintf warning. + +1999-05-19 Toshiaki Takada + + * ospf_ism.c (ospf_dr_election): Join AllDRouters Multicast group + if interface state changes to DR or BDR. + +1999-05-14 Stephen R. van den Berg + + * ospf_main.c (signal_init): SIGTERM call sigint. + (sigint): Logging more better message. + +1999-05-12 Toshiaki Takada + + * ospfd.c: Fix bug of `no router ospf' statement, it will work. + +1999-05-11 Toshiaki Takada + + * ospf_neighbor.c: ospf_nbr_free () Added. + +1999-05-10 Toshiaki Takada + + * ospfd.h: struct ospf_area { }, struct ospf_network { } Changed. + * Fix bug of `no network' statement, it will work. + +1999-05-07 Toshiaki Takada + + * ospf_interface.c, ospf_zebra.c: Fix bug of last interface is not + updated by ospf_if_update (). + +1999-04-30 Kunihiro Ishiguro + + * Makefile.am (noinst_HEADERS): Add ospf_lsa.h for distribution. + +1999-04-25 Toshiaki Takada + + * ospf_interface.c: DEFUN (no_if_ospf_cost), + DEFUN (no_if_ospf_dead_interval), + DEFUN (no_if_ospf_hello_interval), + DEFUN (no_if_ospf_priority), + DEFUN (no_if_ospf_retransmit_interval), + DEFUN (no_if_ospf_transmit_delay) Added. + + interface_config_write () suppress showing interface + default values. + +1999-04-25 Kunihiro Ishiguro + + * ospf_dump.c (ospf_timer_dump): If thread is NULL return "inactive". + + * ospfd.c (ospf_if_update): Fix bug of using ospf_area { } instead + of ospf_network { }. So `router ospf' statement in ospfd.conf + works again. + (ospf_if_update): Call ospf_get_router_id for updating router ID. + +1999-04-25 Toshiaki Takada + + * ospf_interface.c: DEFUN (if_ospf_network) deleted. + DEFUN (if_ospf_network_broadcast), + DEFUN (if_ospf_network_non_broadcast), + DEFUN (if_ospf_network_point_to_multipoint), + DEFUN (if_ospf_network_point_to_point), + DEFUN (no_if_ospf_network) Added. + +1999-04-23 Toshiaki Takada + + * ospfd.h: struct area { } changed to struct ospf_network { }. + Add struct ospf_area { }. + * ospfd.c: Add ospf_area_lookup_by_area_id (), ospf_network_new (), + and ospf_network_free (). + DEFUN (area_authentication), DEFUN (no_area_authentication) Added. + +1999-04-22 Toshiaki Takada + + * ospf_lsa.h: New file. + * ospf_packet.h: LSA related struct definition are moved to + ospf_lsa.h. + * ospf_packet.c: ospf_verify_header () Added. + +1999-04-21 Toshiaki Takada + + * ospf_ism.c: ospf_elect_dr () and related function is changed. + DR Election bug fixed. + * ospf_dump.c: ospf_nbr_state_message (), ospf_timer_dump () Added. + * ospfd.c: DEFUN (show_ip_ospf_neighbor) Added. + +1999-04-19 Kunihiro Ishiguro + + * ospf_main.c (main): access_list_init () is added for vty + connection filtering. + +1999-04-16 Toshiaki Takada + + * ospfd.c: DEFUN (show_ip_ospf_interface) Added. + * ospf_neighbor.c: ospf_nbr_count () Added. + +1999-04-15 Toshiaki Takada + + * ospfd.h: struct ospf { } Changed. + * ospfd.c: ospf_lookup_by_process_id () Deleted. + * ospf_ism.c: ospf_wait_timer () Added. WaitTimer will work. + +1999-04-14 Toshiaki Takada + + * ospf_ism.c: ospf_elect_dr () Added. + * ospf_network.c: ospf_if_ipmulticast () Added. + +1999-04-11 Toshiaki Takada + + * ospf_interface.c: interface_config_write (), + DEFUN (if_ip_ospf_cost), + DEFUN (if_ip_ospf_dead_interval), + DEFUN (if_ip_ospf_hello_interval), + DEFUN (if_ip_ospf_priority), + DEFUN (if_ip_ospf_retransmit_interval) and + DEFUN (if_ip_ospf_transmit_delay) Added. + +1999-04-08 Toshiaki Takada + + * ospf_dump.c: ospf_packet_db_desc_dump () Added. + * ospf_neighbor.c: ospf_nbr_bidirectional () Added. + * ospf_nsm.c: nsm_twoway_received () Added. + +1999-04-02 Toshiaki Takada + + * ospf_neighbor.c: New file. + * ospf_neighbor.h: New file. + * ospf_nsm.c: New file. + * ospf_nsm.h: New file. + * ospf_packet.c: Add ospf_make_header (), ospf_hello () and + ospf_hello_send (). Now OSPFd can receive Hello and send Hello. + +1999-03-27 Kunihiro Ishiguro + + * ospf_packet.c: Add ospf_recv_packet (). Now OSPF Hello can receive. + +1999-03-19 Toshiaki Takada + + * ospf_packet.c: New file. + * ospf_packet.h: New file. + * ospf_network.c: New file. + * ospf_network.h: New file. + * ospfd.h: move OSPF message structure has moved to ospf_packet.h. + +1999-03-17 Kunihiro Ishiguro + + * ospf_zebra.c (ospf_zebra_get_interface): Fix for IPv6 interface + address. + + * Makefile.am (install-sysconfDATA): Overwrite install-sysconfDATA + for install ospfd.conf.sample as owner read only file. + + * ospf_main.c (usage): Change to use ZEBRA_BUG_ADDRESS. + +1999-03-15 Toshiaki Takada + + * ospf_ism.c: New file. + * ospf_ism.h: New file. + * ospf_dump.c: New file. + * ospf_dump.h: New file. + + * ospfd.h: Add (struct ospf), (struct config_network), + (struct message) structure. + + * ospf_interface.c: Add ospf_if_match_network (). + * ospf_interface.h (struct ospf_interface): Change struct members. + + * ospfd.c: ospf_lookup_by_process_id (), ospf_network_new (), + DEFUN (network_area): Added. + + * ospfd.conf.sample: Change sample configuration. + +1999-03-05 Toshiaki Takada + + * ospf_interface.c: New file. + * ospf_interface.h: New file. + * ospf_zebra.h: New file. + * ospf_zebra.c: Add interface function for zebra daemon. + * ospfd.c: New file. + +1999-02-23 Kunihiro Ishiguro + + * Move IPv6 codes and files to ospf6d directory. + +1999-02-18 Peter Galbavy + + * syslog support added + +1998-12-22 Toshiaki Takada + + * ospfd.h: New file. + * ospf_lsa.h: New file. + +1998-12-15 Kunihiro Ishiguro + + * Makefile.am: New file. + * ospf_main.c: New file. + diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am new file mode 100644 index 00000000..1ced11cc --- /dev/null +++ b/ospfd/Makefile.am @@ -0,0 +1,44 @@ +## Process this file with automake to produce Makefile.in. + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 + +noinst_LIBRARIES = libospf.a +sbin_PROGRAMS = ospfd + +libospf_a_SOURCES = \ + ospfd.c ospf_zebra.c ospf_interface.c ospf_ism.c ospf_neighbor.c \ + ospf_nsm.c ospf_dump.c ospf_network.c ospf_packet.c ospf_lsa.c \ + ospf_spf.c ospf_route.c ospf_ase.c ospf_abr.c ospf_ia.c ospf_flood.c \ + ospf_lsdb.c ospf_asbr.c ospf_routemap.c ospf_snmp.c \ + ospf_opaque.c ospf_te.c ospf_vty.c + +noinst_HEADERS = \ + ospf_dump.h ospf_interface.h ospf_ism.h ospf_neighbor.h \ + ospf_network.h ospf_nsm.h ospf_packet.h ospf_zebra.h ospfd.h \ + ospf_lsa.h ospf_spf.h ospf_route.h ospf_ase.h ospf_abr.h ospf_ia.h \ + ospf_flood.h ospf_lsdb.h ospf_asbr.h ospf_snmp.h ospf_opaque.h \ + ospf_te.h ospf_vty.h + +ospfd_SOURCES = \ + ospf_main.c $(libospf_a_SOURCES) + +ospfd_LDADD = ../lib/libzebra.a + +sysconf_DATA = ospfd.conf.sample + +EXTRA_DIST = $(sysconf_DATA) OSPF-MIB.txt OSPF-TRAP-MIB.txt + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done diff --git a/ospfd/Makefile.in b/ospfd/Makefile.in new file mode 100644 index 00000000..8472535e --- /dev/null +++ b/ospfd/Makefile.in @@ -0,0 +1,532 @@ +# Makefile.in generated by automake 1.7 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_triplet = @host@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BGPD = @BGPD@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CURSES = @CURSES@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +IF_METHOD = @IF_METHOD@ +IF_PROC = @IF_PROC@ + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPFORWARD = @IPFORWARD@ +KERNEL_METHOD = @KERNEL_METHOD@ +LDFLAGS = @LDFLAGS@ +LIBPAM = @LIBPAM@ +LIBS = @LIBS@ +LIB_IPV6 = @LIB_IPV6@ +LIB_REGEX = @LIB_REGEX@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MULTIPATH_NUM = @MULTIPATH_NUM@ +OBJEXT = @OBJEXT@ +OSPF6D = @OSPF6D@ +OSPFD = @OSPFD@ +OTHER_METHOD = @OTHER_METHOD@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +RIPD = @RIPD@ +RIPNGD = @RIPNGD@ +RTREAD_METHOD = @RTREAD_METHOD@ +RT_METHOD = @RT_METHOD@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VTYSH = @VTYSH@ +ZEBRA = @ZEBRA@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__quote = @am__quote@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +INSTALL_SDATA = @INSTALL@ -m 600 + +noinst_LIBRARIES = libospf.a +sbin_PROGRAMS = ospfd + +libospf_a_SOURCES = \ + ospfd.c ospf_zebra.c ospf_interface.c ospf_ism.c ospf_neighbor.c \ + ospf_nsm.c ospf_dump.c ospf_network.c ospf_packet.c ospf_lsa.c \ + ospf_spf.c ospf_route.c ospf_ase.c ospf_abr.c ospf_ia.c ospf_flood.c \ + ospf_lsdb.c ospf_asbr.c ospf_routemap.c ospf_snmp.c \ + ospf_opaque.c ospf_te.c ospf_vty.c + + +noinst_HEADERS = \ + ospf_dump.h ospf_interface.h ospf_ism.h ospf_neighbor.h \ + ospf_network.h ospf_nsm.h ospf_packet.h ospf_zebra.h ospfd.h \ + ospf_lsa.h ospf_spf.h ospf_route.h ospf_ase.h ospf_abr.h ospf_ia.h \ + ospf_flood.h ospf_lsdb.h ospf_asbr.h ospf_snmp.h ospf_opaque.h \ + ospf_te.h ospf_vty.h + + +ospfd_SOURCES = \ + ospf_main.c $(libospf_a_SOURCES) + + +ospfd_LDADD = ../lib/libzebra.a + +sysconf_DATA = ospfd.conf.sample + +EXTRA_DIST = $(sysconf_DATA) OSPF-MIB.txt OSPF-TRAP-MIB.txt +subdir = ospfd +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +libospf_a_AR = $(AR) cru +libospf_a_LIBADD = +am_libospf_a_OBJECTS = ospfd.$(OBJEXT) ospf_zebra.$(OBJEXT) \ + ospf_interface.$(OBJEXT) ospf_ism.$(OBJEXT) \ + ospf_neighbor.$(OBJEXT) ospf_nsm.$(OBJEXT) ospf_dump.$(OBJEXT) \ + ospf_network.$(OBJEXT) ospf_packet.$(OBJEXT) ospf_lsa.$(OBJEXT) \ + ospf_spf.$(OBJEXT) ospf_route.$(OBJEXT) ospf_ase.$(OBJEXT) \ + ospf_abr.$(OBJEXT) ospf_ia.$(OBJEXT) ospf_flood.$(OBJEXT) \ + ospf_lsdb.$(OBJEXT) ospf_asbr.$(OBJEXT) ospf_routemap.$(OBJEXT) \ + ospf_snmp.$(OBJEXT) ospf_opaque.$(OBJEXT) ospf_te.$(OBJEXT) \ + ospf_vty.$(OBJEXT) +libospf_a_OBJECTS = $(am_libospf_a_OBJECTS) +sbin_PROGRAMS = ospfd$(EXEEXT) +PROGRAMS = $(sbin_PROGRAMS) + +am__objects_1 = ospfd.$(OBJEXT) ospf_zebra.$(OBJEXT) \ + ospf_interface.$(OBJEXT) ospf_ism.$(OBJEXT) \ + ospf_neighbor.$(OBJEXT) ospf_nsm.$(OBJEXT) ospf_dump.$(OBJEXT) \ + ospf_network.$(OBJEXT) ospf_packet.$(OBJEXT) ospf_lsa.$(OBJEXT) \ + ospf_spf.$(OBJEXT) ospf_route.$(OBJEXT) ospf_ase.$(OBJEXT) \ + ospf_abr.$(OBJEXT) ospf_ia.$(OBJEXT) ospf_flood.$(OBJEXT) \ + ospf_lsdb.$(OBJEXT) ospf_asbr.$(OBJEXT) ospf_routemap.$(OBJEXT) \ + ospf_snmp.$(OBJEXT) ospf_opaque.$(OBJEXT) ospf_te.$(OBJEXT) \ + ospf_vty.$(OBJEXT) +am_ospfd_OBJECTS = ospf_main.$(OBJEXT) $(am__objects_1) +ospfd_OBJECTS = $(am_ospfd_OBJECTS) +ospfd_DEPENDENCIES = ../lib/libzebra.a +ospfd_LDFLAGS = + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/ospf_abr.Po ./$(DEPDIR)/ospf_asbr.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_ase.Po ./$(DEPDIR)/ospf_dump.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_flood.Po ./$(DEPDIR)/ospf_ia.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_interface.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_ism.Po ./$(DEPDIR)/ospf_lsa.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_lsdb.Po ./$(DEPDIR)/ospf_main.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_neighbor.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_network.Po ./$(DEPDIR)/ospf_nsm.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_opaque.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_packet.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_route.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_routemap.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_snmp.Po ./$(DEPDIR)/ospf_spf.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_te.Po ./$(DEPDIR)/ospf_vty.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_zebra.Po ./$(DEPDIR)/ospfd.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libospf_a_SOURCES) $(ospfd_SOURCES) +DATA = $(sysconf_DATA) + +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in +SOURCES = $(libospf_a_SOURCES) $(ospfd_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign ospfd/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libospf.a: $(libospf_a_OBJECTS) $(libospf_a_DEPENDENCIES) + -rm -f libospf.a + $(libospf_a_AR) libospf.a $(libospf_a_OBJECTS) $(libospf_a_LIBADD) + $(RANLIB) libospf.a +sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f || exit 1; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \ + rm -f $(DESTDIR)$(sbindir)/$$f; \ + done + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) +ospfd$(EXEEXT): $(ospfd_OBJECTS) $(ospfd_DEPENDENCIES) + @rm -f ospfd$(EXEEXT) + $(LINK) $(ospfd_LDFLAGS) $(ospfd_OBJECTS) $(ospfd_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_abr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_asbr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_ase.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_dump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_flood.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_ia.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_interface.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_ism.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_lsa.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_lsdb.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_neighbor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_network.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_nsm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_opaque.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_packet.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_route.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_routemap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_snmp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_spf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_te.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_vty.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_zebra.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospfd.Po@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCC_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCC_TRUE@ then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCC_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`; \ +@am__fastdepCC_TRUE@ then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'` +uninstall-info-am: +sysconfDATA_INSTALL = $(INSTALL_DATA) + +uninstall-sysconfDATA: + @$(NORMAL_UNINSTALL) + @list='$(sysconf_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(sysconfdir)/$$f"; \ + rm -f $(DESTDIR)$(sysconfdir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(sysconfdir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES clean-sbinPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-sbinPROGRAMS install-sysconfDATA + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \ + uninstall-sysconfDATA + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES clean-sbinPROGRAMS ctags distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-tags distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-sbinPROGRAMS install-strip install-sysconfDATA \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am uninstall-sbinPROGRAMS \ + uninstall-sysconfDATA + + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/ospfd/OSPF-MIB.txt b/ospfd/OSPF-MIB.txt new file mode 100644 index 00000000..de7d03f5 --- /dev/null +++ b/ospfd/OSPF-MIB.txt @@ -0,0 +1,2723 @@ +OSPF-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, Counter32, Gauge32, + Integer32, IpAddress + FROM SNMPv2-SMI + TEXTUAL-CONVENTION, TruthValue, RowStatus + FROM SNMPv2-TC + MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF + mib-2 FROM RFC1213-MIB; + +-- This MIB module uses the extended OBJECT-TYPE macro as +-- defined in [9]. + +ospf MODULE-IDENTITY + LAST-UPDATED "9501201225Z" -- Fri Jan 20 12:25:50 PST 1995 + ORGANIZATION "IETF OSPF Working Group" + CONTACT-INFO + " Fred Baker + Postal: Cisco Systems + 519 Lado Drive + Santa Barbara, California 93111 + Tel: +1 805 681 0115 + E-Mail: fred@cisco.com + + Rob Coltun + Postal: RainbowBridge Communications + Tel: (301) 340-9416 + E-Mail: rcoltun@rainbow-bridge.com" + DESCRIPTION + "The MIB module to describe the OSPF Version 2 + Protocol" + ::= { mib-2 14 } + +-- The Area ID, in OSPF, has the same format as an IP Address, +-- but has the function of defining a summarization point for +-- Link State Advertisements + +AreaID ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "An OSPF Area Identifier." + SYNTAX IpAddress + + +-- The Router ID, in OSPF, has the same format as an IP Address, +-- but identifies the router independent of its IP Address. + +RouterID ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "A OSPF Router Identifier." + SYNTAX IpAddress + + +-- The OSPF Metric is defined as an unsigned value in the range + +Metric ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The OSPF Internal Metric." + SYNTAX Integer32 (0..'FFFF'h) + +BigMetric ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The OSPF External Metric." + SYNTAX Integer32 (0..'FFFFFF'h) + +-- Status Values + +Status ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The status of an interface: 'enabled' indicates that + it is willing to communicate with other OSPF Routers, + while 'disabled' indicates that it is not." + SYNTAX INTEGER { enabled (1), disabled (2) } + +-- Time Durations measured in seconds + +PositiveInteger ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "A positive integer. Values in excess are precluded as + unnecessary and prone to interoperability issues." + SYNTAX Integer32 (0..'7FFFFFFF'h) + +HelloRange ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The range of intervals on which hello messages are + exchanged." + SYNTAX Integer32 (1..'FFFF'h) + +UpToMaxAge ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The values that one might find or configure for + variables bounded by the maximum age of an LSA." + SYNTAX Integer32 (0..3600) + + +-- The range of ifIndex + +InterfaceIndex ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The range of ifIndex." + SYNTAX Integer32 + + +-- Potential Priorities for the Designated Router Election + +DesignatedRouterPriority ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The values defined for the priority of a system for + becoming the designated router." + SYNTAX Integer32 (0..'FF'h) + +TOSType ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Type of Service is defined as a mapping to the IP Type of + Service Flags as defined in the IP Forwarding Table MIB + + +-----+-----+-----+-----+-----+-----+-----+-----+ + | | | | + | PRECEDENCE | TYPE OF SERVICE | 0 | + | | | | + +-----+-----+-----+-----+-----+-----+-----+-----+ + + IP TOS IP TOS + Field Policy Field Policy + + Contents Code Contents Code + 0 0 0 0 ==> 0 0 0 0 1 ==> 2 + 0 0 1 0 ==> 4 0 0 1 1 ==> 6 + 0 1 0 0 ==> 8 0 1 0 1 ==> 10 + 0 1 1 0 ==> 12 0 1 1 1 ==> 14 + 1 0 0 0 ==> 16 1 0 0 1 ==> 18 + 1 0 1 0 ==> 20 1 0 1 1 ==> 22 + 1 1 0 0 ==> 24 1 1 0 1 ==> 26 + 1 1 1 0 ==> 28 1 1 1 1 ==> 30 + + The remaining values are left for future definition." + SYNTAX Integer32 (0..30) + + +-- OSPF General Variables + +-- These parameters apply globally to the Router's +-- OSPF Process. + +ospfGeneralGroup OBJECT IDENTIFIER ::= { ospf 1 } + + + ospfRouterId OBJECT-TYPE + SYNTAX RouterID + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "A 32-bit integer uniquely identifying the + router in the Autonomous System. + + By convention, to ensure uniqueness, this + should default to the value of one of the + router's IP interface addresses." + REFERENCE + "OSPF Version 2, C.1 Global parameters" + ::= { ospfGeneralGroup 1 } + + + ospfAdminStat OBJECT-TYPE + SYNTAX Status + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The administrative status of OSPF in the + router. The value 'enabled' denotes that the + OSPF Process is active on at least one inter- + face; 'disabled' disables it on all inter- + faces." + ::= { ospfGeneralGroup 2 } + + ospfVersionNumber OBJECT-TYPE + SYNTAX INTEGER { version2 (2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The current version number of the OSPF proto- + col is 2." + REFERENCE + "OSPF Version 2, Title" + ::= { ospfGeneralGroup 3 } + + + ospfAreaBdrRtrStatus OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A flag to note whether this router is an area + border router." + REFERENCE + "OSPF Version 2, Section 3 Splitting the AS into + Areas" + ::= { ospfGeneralGroup 4 } + + + ospfASBdrRtrStatus OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "A flag to note whether this router is config- + ured as an Autonomous System border router." + REFERENCE + "OSPF Version 2, Section 3.3 Classification of + routers" + ::= { ospfGeneralGroup 5 } + + ospfExternLsaCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of external (LS type 5) link-state + advertisements in the link-state database." + REFERENCE + "OSPF Version 2, Appendix A.4.5 AS external link + advertisements" + ::= { ospfGeneralGroup 6 } + + + ospfExternLsaCksumSum OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32-bit unsigned sum of the LS checksums of + the external link-state advertisements con- + tained in the link-state database. This sum + can be used to determine if there has been a + change in a router's link state database, and + to compare the link-state database of two + routers." + ::= { ospfGeneralGroup 7 } + + + ospfTOSSupport OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The router's support for type-of-service rout- + ing." + REFERENCE + "OSPF Version 2, Appendix F.1.2 Optional TOS + support" + ::= { ospfGeneralGroup 8 } + + ospfOriginateNewLsas OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of new link-state advertisements + that have been originated. This number is in- + cremented each time the router originates a new + LSA." + ::= { ospfGeneralGroup 9 } + + + ospfRxNewLsas OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of link-state advertisements re- + ceived determined to be new instantiations. + This number does not include newer instantia- + tions of self-originated link-state advertise- + ments." + ::= { ospfGeneralGroup 10 } + + ospfExtLsdbLimit OBJECT-TYPE + SYNTAX Integer32 (-1..'7FFFFFFF'h) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The maximum number of non-default AS- + external-LSAs entries that can be stored in the + link-state database. If the value is -1, then + there is no limit. + + When the number of non-default AS-external-LSAs + in a router's link-state database reaches + ospfExtLsdbLimit, the router enters Overflow- + State. The router never holds more than + ospfExtLsdbLimit non-default AS-external-LSAs + in its database. OspfExtLsdbLimit MUST be set + identically in all routers attached to the OSPF + backbone and/or any regular OSPF area. (i.e., + OSPF stub areas and NSSAs are excluded)." + DEFVAL { -1 } + ::= { ospfGeneralGroup 11 } + + ospfMulticastExtensions OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "A Bit Mask indicating whether the router is + forwarding IP multicast (Class D) datagrams + based on the algorithms defined in the Multi- + cast Extensions to OSPF. + + Bit 0, if set, indicates that the router can + forward IP multicast datagrams in the router's + directly attached areas (called intra-area mul- + ticast routing). + + Bit 1, if set, indicates that the router can + forward IP multicast datagrams between OSPF + areas (called inter-area multicast routing). + + Bit 2, if set, indicates that the router can + forward IP multicast datagrams between Auto- + nomous Systems (called inter-AS multicast rout- + ing). + + Only certain combinations of bit settings are + allowed, namely: 0 (no multicast forwarding is + enabled), 1 (intra-area multicasting only), 3 + (intra-area and inter-area multicasting), 5 + (intra-area and inter-AS multicasting) and 7 + (multicasting everywhere). By default, no mul- + ticast forwarding is enabled." + DEFVAL { 0 } + ::= { ospfGeneralGroup 12 } + + ospfExitOverflowInterval OBJECT-TYPE + SYNTAX PositiveInteger + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The number of seconds that, after entering + OverflowState, a router will attempt to leave + OverflowState. This allows the router to again + originate non-default AS-external-LSAs. When + set to 0, the router will not leave Overflow- + State until restarted." + DEFVAL { 0 } + ::= { ospfGeneralGroup 13 } + + + ospfDemandExtensions OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The router's support for demand routing." + REFERENCE + "OSPF Version 2, Appendix on Demand Routing" + ::= { ospfGeneralGroup 14 } + + +-- The OSPF Area Data Structure contains information +-- regarding the various areas. The interfaces and +-- virtual links are configured as part of these areas. +-- Area 0.0.0.0, by definition, is the Backbone Area + + + ospfAreaTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfAreaEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information describing the configured parame- + ters and cumulative statistics of the router's + attached areas." + REFERENCE + "OSPF Version 2, Section 6 The Area Data Struc- + ture" + ::= { ospf 2 } + + + ospfAreaEntry OBJECT-TYPE + SYNTAX OspfAreaEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information describing the configured parame- + ters and cumulative statistics of one of the + router's attached areas." + INDEX { ospfAreaId } + ::= { ospfAreaTable 1 } + +OspfAreaEntry ::= + SEQUENCE { + ospfAreaId + AreaID, + ospfAuthType + Integer32, + ospfImportAsExtern + INTEGER, + ospfSpfRuns + Counter32, + ospfAreaBdrRtrCount + Gauge32, + ospfAsBdrRtrCount + Gauge32, + ospfAreaLsaCount + Gauge32, + ospfAreaLsaCksumSum + Integer32, + ospfAreaSummary + INTEGER, + ospfAreaStatus + RowStatus + } + + ospfAreaId OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A 32-bit integer uniquely identifying an area. + Area ID 0.0.0.0 is used for the OSPF backbone." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaEntry 1 } + + + ospfAuthType OBJECT-TYPE + SYNTAX Integer32 + -- none (0), + -- simplePassword (1) + -- md5 (2) + -- reserved for specification by IANA (> 2) + MAX-ACCESS read-create + STATUS obsolete + DESCRIPTION + "The authentication type specified for an area. + Additional authentication types may be assigned + locally on a per Area basis." + REFERENCE + "OSPF Version 2, Appendix E Authentication" + DEFVAL { 0 } -- no authentication, by default + ::= { ospfAreaEntry 2 } + + ospfImportAsExtern OBJECT-TYPE + SYNTAX INTEGER { + importExternal (1), + importNoExternal (2), + importNssa (3) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The area's support for importing AS external + link- state advertisements." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + DEFVAL { importExternal } + ::= { ospfAreaEntry 3 } + + + ospfSpfRuns OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times that the intra-area route + table has been calculated using this area's + link-state database. This is typically done + using Dijkstra's algorithm." + ::= { ospfAreaEntry 4 } + + + ospfAreaBdrRtrCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of area border routers reach- + able within this area. This is initially zero, + and is calculated in each SPF Pass." + ::= { ospfAreaEntry 5 } + + ospfAsBdrRtrCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of Autonomous System border + routers reachable within this area. This is + initially zero, and is calculated in each SPF + Pass." + ::= { ospfAreaEntry 6 } + + + ospfAreaLsaCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of link-state advertisements + in this area's link-state database, excluding + AS External LSA's." + ::= { ospfAreaEntry 7 } + + + ospfAreaLsaCksumSum OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32-bit unsigned sum of the link-state ad- + vertisements' LS checksums contained in this + area's link-state database. This sum excludes + external (LS type 5) link-state advertisements. + The sum can be used to determine if there has + been a change in a router's link state data- + base, and to compare the link-state database of + two routers." + DEFVAL { 0 } + ::= { ospfAreaEntry 8 } + + ospfAreaSummary OBJECT-TYPE + SYNTAX INTEGER { + noAreaSummary (1), + sendAreaSummary (2) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The variable ospfAreaSummary controls the im- + port of summary LSAs into stub areas. It has + no effect on other areas. + + If it is noAreaSummary, the router will neither + originate nor propagate summary LSAs into the + stub area. It will rely entirely on its de- + fault route. + + If it is sendAreaSummary, the router will both + summarize and propagate summary LSAs." + DEFVAL { noAreaSummary } + ::= { ospfAreaEntry 9 } + + + ospfAreaStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfAreaEntry 10 } + + +-- OSPF Area Default Metric Table + +-- The OSPF Area Default Metric Table describes the metrics +-- that a default Area Border Router will advertise into a +-- Stub area. + + + ospfStubAreaTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfStubAreaEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The set of metrics that will be advertised by + a default Area Border Router into a stub area." + REFERENCE + "OSPF Version 2, Appendix C.2, Area Parameters" + ::= { ospf 3 } + + + ospfStubAreaEntry OBJECT-TYPE + SYNTAX OspfStubAreaEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The metric for a given Type of Service that + will be advertised by a default Area Border + Router into a stub area." + REFERENCE + "OSPF Version 2, Appendix C.2, Area Parameters" + INDEX { ospfStubAreaId, ospfStubTOS } + ::= { ospfStubAreaTable 1 } + +OspfStubAreaEntry ::= + SEQUENCE { + ospfStubAreaId + AreaID, + ospfStubTOS + TOSType, + ospfStubMetric + BigMetric, + ospfStubStatus + RowStatus, + ospfStubMetricType + INTEGER + } + + ospfStubAreaId OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32 bit identifier for the Stub Area. On + creation, this can be derived from the in- + stance." + ::= { ospfStubAreaEntry 1 } + + + ospfStubTOS OBJECT-TYPE + SYNTAX TOSType + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Type of Service associated with the + metric. On creation, this can be derived from + the instance." + ::= { ospfStubAreaEntry 2 } + + + ospfStubMetric OBJECT-TYPE + SYNTAX BigMetric + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The metric value applied at the indicated type + of service. By default, this equals the least + metric at the type of service among the inter- + faces to other areas." + ::= { ospfStubAreaEntry 3 } + + + ospfStubStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfStubAreaEntry 4 } + + ospfStubMetricType OBJECT-TYPE + SYNTAX INTEGER { + ospfMetric (1), -- OSPF Metric + comparableCost (2), -- external type 1 + nonComparable (3) -- external type 2 + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the type of metric ad- + vertised as a default route." + DEFVAL { ospfMetric } + ::= { ospfStubAreaEntry 5 } + +-- OSPF Link State Database + +-- The Link State Database contains the Link State +-- Advertisements from throughout the areas that the +-- device is attached to. + + + ospfLsdbTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The OSPF Process's Link State Database." + REFERENCE + "OSPF Version 2, Section 12 Link State Adver- + tisements" + ::= { ospf 4 } + + + ospfLsdbEntry OBJECT-TYPE + SYNTAX OspfLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A single Link State Advertisement." + INDEX { ospfLsdbAreaId, ospfLsdbType, + ospfLsdbLsid, ospfLsdbRouterId } + ::= { ospfLsdbTable 1 } + +OspfLsdbEntry ::= + SEQUENCE { + ospfLsdbAreaId + AreaID, + ospfLsdbType + INTEGER, + ospfLsdbLsid + IpAddress, + ospfLsdbRouterId + RouterID, + ospfLsdbSequence + Integer32, + ospfLsdbAge + Integer32, + ospfLsdbChecksum + Integer32, + ospfLsdbAdvertisement + OCTET STRING + } + ospfLsdbAreaId OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32 bit identifier of the Area from which + the LSA was received." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfLsdbEntry 1 } + +-- External Link State Advertisements are permitted +-- for backward compatibility, but should be displayed in +-- the ospfExtLsdbTable rather than here. + + ospfLsdbType OBJECT-TYPE + SYNTAX INTEGER { + routerLink (1), + networkLink (2), + summaryLink (3), + asSummaryLink (4), + asExternalLink (5), -- but see ospfExtLsdbTable + multicastLink (6), + nssaExternalLink (7) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The type of the link state advertisement. + Each link state type has a separate advertise- + ment format." + REFERENCE + "OSPF Version 2, Appendix A.4.1 The Link State + Advertisement header" + ::= { ospfLsdbEntry 2 } + + ospfLsdbLsid OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Link State ID is an LS Type Specific field + containing either a Router ID or an IP Address; + it identifies the piece of the routing domain + that is being described by the advertisement." + REFERENCE + "OSPF Version 2, Section 12.1.4 Link State ID" + ::= { ospfLsdbEntry 3 } + ospfLsdbRouterId OBJECT-TYPE + SYNTAX RouterID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32 bit number that uniquely identifies the + originating router in the Autonomous System." + REFERENCE + "OSPF Version 2, Appendix C.1 Global parameters" + ::= { ospfLsdbEntry 4 } + +-- Note that the OSPF Sequence Number is a 32 bit signed +-- integer. It starts with the value '80000001'h, +-- or -'7FFFFFFF'h, and increments until '7FFFFFFF'h +-- Thus, a typical sequence number will be very negative. + + ospfLsdbSequence OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The sequence number field is a signed 32-bit + integer. It is used to detect old and dupli- + cate link state advertisements. The space of + sequence numbers is linearly ordered. The + larger the sequence number the more recent the + advertisement." + REFERENCE + "OSPF Version 2, Section 12.1.6 LS sequence + number" + ::= { ospfLsdbEntry 5 } + + + ospfLsdbAge OBJECT-TYPE + SYNTAX Integer32 -- Should be 0..MaxAge + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the age of the link state adver- + tisement in seconds." + REFERENCE + "OSPF Version 2, Section 12.1.1 LS age" + ::= { ospfLsdbEntry 6 } + + ospfLsdbChecksum OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the checksum of the complete + contents of the advertisement, excepting the + age field. The age field is excepted so that + an advertisement's age can be incremented + without updating the checksum. The checksum + used is the same that is used for ISO connec- + tionless datagrams; it is commonly referred to + as the Fletcher checksum." + REFERENCE + "OSPF Version 2, Section 12.1.7 LS checksum" + ::= { ospfLsdbEntry 7 } + + + ospfLsdbAdvertisement OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (1..65535)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The entire Link State Advertisement, including + its header." + REFERENCE + "OSPF Version 2, Section 12 Link State Adver- + tisements" + ::= { ospfLsdbEntry 8 } + + +-- Address Range Table + +-- The Address Range Table acts as an adjunct to the Area +-- Table; It describes those Address Range Summaries that +-- are configured to be propagated from an Area to reduce +-- the amount of information about it which is known beyond +-- its borders. + + ospfAreaRangeTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfAreaRangeEntry + MAX-ACCESS not-accessible + STATUS obsolete + DESCRIPTION + "A range if IP addresses specified by an IP + address/IP network mask pair. For example, + class B address range of X.X.X.X with a network + mask of 255.255.0.0 includes all IP addresses + from X.X.0.0 to X.X.255.255" + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospf 5 } + ospfAreaRangeEntry OBJECT-TYPE + SYNTAX OspfAreaRangeEntry + MAX-ACCESS not-accessible + STATUS obsolete + DESCRIPTION + "A range if IP addresses specified by an IP + address/IP network mask pair. For example, + class B address range of X.X.X.X with a network + mask of 255.255.0.0 includes all IP addresses + from X.X.0.0 to X.X.255.255" + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + INDEX { ospfAreaRangeAreaId, ospfAreaRangeNet } + ::= { ospfAreaRangeTable 1 } + +OspfAreaRangeEntry ::= + SEQUENCE { + ospfAreaRangeAreaId + AreaID, + ospfAreaRangeNet + IpAddress, + ospfAreaRangeMask + IpAddress, + ospfAreaRangeStatus + RowStatus, + ospfAreaRangeEffect + INTEGER + } + + ospfAreaRangeAreaId OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The Area the Address Range is to be found + within." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaRangeEntry 1 } + + + ospfAreaRangeNet OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The IP Address of the Net or Subnet indicated + by the range." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaRangeEntry 2 } + + + ospfAreaRangeMask OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-create + STATUS obsolete + DESCRIPTION + "The Subnet Mask that pertains to the Net or + Subnet." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaRangeEntry 3 } + + ospfAreaRangeStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS obsolete + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfAreaRangeEntry 4 } + + + ospfAreaRangeEffect OBJECT-TYPE + SYNTAX INTEGER { + advertiseMatching (1), + doNotAdvertiseMatching (2) + } + MAX-ACCESS read-create + STATUS obsolete + DESCRIPTION + "Subnets subsumed by ranges either trigger the + advertisement of the indicated summary (adver- + tiseMatching), or result in the subnet's not + being advertised at all outside the area." + DEFVAL { advertiseMatching } + ::= { ospfAreaRangeEntry 5 } + + + +-- OSPF Host Table + +-- The Host/Metric Table indicates what hosts are directly +-- attached to the Router, and what metrics and types of +-- service should be advertised for them. + + ospfHostTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfHostEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The list of Hosts, and their metrics, that the + router will advertise as host routes." + REFERENCE + "OSPF Version 2, Appendix C.6 Host route param- + eters" + ::= { ospf 6 } + + + ospfHostEntry OBJECT-TYPE + SYNTAX OspfHostEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A metric to be advertised, for a given type of + service, when a given host is reachable." + INDEX { ospfHostIpAddress, ospfHostTOS } + ::= { ospfHostTable 1 } + +OspfHostEntry ::= + SEQUENCE { + ospfHostIpAddress + IpAddress, + ospfHostTOS + TOSType, + ospfHostMetric + Metric, + ospfHostStatus + RowStatus, + ospfHostAreaID + AreaID + } + + ospfHostIpAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of the Host." + REFERENCE + "OSPF Version 2, Appendix C.6 Host route parame- + ters" + ::= { ospfHostEntry 1 } + + + ospfHostTOS OBJECT-TYPE + SYNTAX TOSType + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Type of Service of the route being config- + ured." + REFERENCE + "OSPF Version 2, Appendix C.6 Host route parame- + ters" + ::= { ospfHostEntry 2 } + + + ospfHostMetric OBJECT-TYPE + SYNTAX Metric + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The Metric to be advertised." + REFERENCE + "OSPF Version 2, Appendix C.6 Host route parame- + ters" + ::= { ospfHostEntry 3 } + + ospfHostStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfHostEntry 4 } + + + ospfHostAreaID OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Area the Host Entry is to be found within. + By default, the area that a subsuming OSPF in- + terface is in, or 0.0.0.0" + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfHostEntry 5 } + + +-- OSPF Interface Table + +-- The OSPF Interface Table augments the ipAddrTable +-- with OSPF specific information. + + ospfIfTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfIfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The OSPF Interface Table describes the inter- + faces from the viewpoint of OSPF." + REFERENCE + "OSPF Version 2, Appendix C.3 Router interface + parameters" + ::= { ospf 7 } + + + ospfIfEntry OBJECT-TYPE + SYNTAX OspfIfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The OSPF Interface Entry describes one inter- + face from the viewpoint of OSPF." + INDEX { ospfIfIpAddress, ospfAddressLessIf } + ::= { ospfIfTable 1 } + +OspfIfEntry ::= + SEQUENCE { + ospfIfIpAddress + IpAddress, + ospfAddressLessIf + Integer32, + ospfIfAreaId + AreaID, + ospfIfType + INTEGER, + ospfIfAdminStat + Status, + ospfIfRtrPriority + DesignatedRouterPriority, + ospfIfTransitDelay + UpToMaxAge, + ospfIfRetransInterval + UpToMaxAge, + ospfIfHelloInterval + HelloRange, + ospfIfRtrDeadInterval + PositiveInteger, + ospfIfPollInterval + PositiveInteger, + ospfIfState + INTEGER, + ospfIfDesignatedRouter + IpAddress, + ospfIfBackupDesignatedRouter + IpAddress, + ospfIfEvents + Counter32, + ospfIfAuthType + INTEGER, + ospfIfAuthKey + OCTET STRING, + ospfIfStatus + RowStatus, + ospfIfMulticastForwarding + INTEGER, + ospfIfDemand + TruthValue + } + + ospfIfIpAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address of this OSPF interface." + ::= { ospfIfEntry 1 } + + ospfAddressLessIf OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "For the purpose of easing the instancing of + addressed and addressless interfaces; This + variable takes the value 0 on interfaces with + IP Addresses, and the corresponding value of + ifIndex for interfaces having no IP Address." + ::= { ospfIfEntry 2 } + ospfIfAreaId OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "A 32-bit integer uniquely identifying the area + to which the interface connects. Area ID + 0.0.0.0 is used for the OSPF backbone." + DEFVAL { '00000000'H } -- 0.0.0.0 + ::= { ospfIfEntry 3 } + + ospfIfType OBJECT-TYPE + SYNTAX INTEGER { + broadcast (1), + nbma (2), + pointToPoint (3), + pointToMultipoint (5) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The OSPF interface type. + + By way of a default, this field may be intuited + from the corresponding value of ifType. Broad- + cast LANs, such as Ethernet and IEEE 802.5, + take the value 'broadcast', X.25 and similar + technologies take the value 'nbma', and links + that are definitively point to point take the + value 'pointToPoint'." + ::= { ospfIfEntry 4 } + + + ospfIfAdminStat OBJECT-TYPE + SYNTAX Status + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The OSPF interface's administrative status. + The value formed on the interface, and the in- + terface will be advertised as an internal route + to some area. The value 'disabled' denotes + that the interface is external to OSPF." + DEFVAL { enabled } + ::= { ospfIfEntry 5 } + + ospfIfRtrPriority OBJECT-TYPE + SYNTAX DesignatedRouterPriority + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The priority of this interface. Used in + multi-access networks, this field is used in + the designated router election algorithm. The + value 0 signifies that the router is not eligi- + ble to become the designated router on this + particular network. In the event of a tie in + this value, routers will use their Router ID as + a tie breaker." + DEFVAL { 1 } + ::= { ospfIfEntry 6 } + + + ospfIfTransitDelay OBJECT-TYPE + SYNTAX UpToMaxAge + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The estimated number of seconds it takes to + transmit a link state update packet over this + interface." + DEFVAL { 1 } + ::= { ospfIfEntry 7 } + + + ospfIfRetransInterval OBJECT-TYPE + SYNTAX UpToMaxAge + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The number of seconds between link-state ad- + vertisement retransmissions, for adjacencies + belonging to this interface. This value is + also used when retransmitting database descrip- + tion and link-state request packets." + DEFVAL { 5 } + ::= { ospfIfEntry 8 } + + + ospfIfHelloInterval OBJECT-TYPE + SYNTAX HelloRange + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The length of time, in seconds, between the + Hello packets that the router sends on the in- + terface. This value must be the same for all + routers attached to a common network." + DEFVAL { 10 } + ::= { ospfIfEntry 9 } + + + ospfIfRtrDeadInterval OBJECT-TYPE + SYNTAX PositiveInteger + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The number of seconds that a router's Hello + packets have not been seen before it's neigh- + bors declare the router down. This should be + some multiple of the Hello interval. This + value must be the same for all routers attached + to a common network." + DEFVAL { 40 } + ::= { ospfIfEntry 10 } + + + ospfIfPollInterval OBJECT-TYPE + SYNTAX PositiveInteger + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The larger time interval, in seconds, between + the Hello packets sent to an inactive non- + broadcast multi- access neighbor." + DEFVAL { 120 } + ::= { ospfIfEntry 11 } + + + ospfIfState OBJECT-TYPE + SYNTAX INTEGER { + down (1), + loopback (2), + waiting (3), + pointToPoint (4), + designatedRouter (5), + backupDesignatedRouter (6), + otherDesignatedRouter (7) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The OSPF Interface State." + DEFVAL { down } + ::= { ospfIfEntry 12 } + + + ospfIfDesignatedRouter OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of the Designated Router." + DEFVAL { '00000000'H } -- 0.0.0.0 + ::= { ospfIfEntry 13 } + + + ospfIfBackupDesignatedRouter OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of the Backup Designated + Router." + DEFVAL { '00000000'H } -- 0.0.0.0 + ::= { ospfIfEntry 14 } + + ospfIfEvents OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times this OSPF interface has + changed its state, or an error has occurred." + ::= { ospfIfEntry 15 } + + + ospfIfAuthKey OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (0..256)) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The Authentication Key. If the Area's Author- + ization Type is simplePassword, and the key + length is shorter than 8 octets, the agent will + left adjust and zero fill to 8 octets. + + Note that unauthenticated interfaces need no + authentication key, and simple password authen- + tication cannot use a key of more than 8 oc- + tets. Larger keys are useful only with authen- + tication mechanisms not specified in this docu- + ment. + + When read, ospfIfAuthKey always returns an Oc- + tet String of length zero." + REFERENCE + "OSPF Version 2, Section 9 The Interface Data + Structure" + DEFVAL { '0000000000000000'H } -- 0.0.0.0.0.0.0.0 + ::= { ospfIfEntry 16 } + + ospfIfStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfIfEntry 17 } + + + ospfIfMulticastForwarding OBJECT-TYPE + SYNTAX INTEGER { + blocked (1), -- no multicast forwarding + multicast (2), -- using multicast address + unicast (3) -- to each OSPF neighbor + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The way multicasts should forwarded on this + interface; not forwarded, forwarded as data + link multicasts, or forwarded as data link uni- + casts. Data link multicasting is not meaning- + ful on point to point and NBMA interfaces, and + setting ospfMulticastForwarding to 0 effective- + ly disables all multicast forwarding." + DEFVAL { blocked } + ::= { ospfIfEntry 18 } + + + ospfIfDemand OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Indicates whether Demand OSPF procedures (hel- + lo supression to FULL neighbors and setting the + DoNotAge flag on proogated LSAs) should be per- + formed on this interface." + DEFVAL { false } + ::= { ospfIfEntry 19 } + + + ospfIfAuthType OBJECT-TYPE + SYNTAX INTEGER (0..255) + -- none (0), + -- simplePassword (1) + -- md5 (2) + -- reserved for specification by IANA (> 2) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The authentication type specified for an in- + terface. Additional authentication types may + be assigned locally." + REFERENCE + "OSPF Version 2, Appendix E Authentication" + DEFVAL { 0 } -- no authentication, by default + ::= { ospfIfEntry 20 } + + +-- OSPF Interface Metric Table + +-- The Metric Table describes the metrics to be advertised +-- for a specified interface at the various types of service. +-- As such, this table is an adjunct of the OSPF Interface +-- Table. + +-- Types of service, as defined by RFC 791, have the ability +-- to request low delay, high bandwidth, or reliable linkage. + +-- For the purposes of this specification, the measure of +-- bandwidth + +-- Metric = 10^8 / ifSpeed + +-- is the default value. For multiple link interfaces, note +-- that ifSpeed is the sum of the individual link speeds. +-- This yields a number having the following typical values: + +-- Network Type/bit rate Metric + +-- >= 100 MBPS 1 +-- Ethernet/802.3 10 +-- E1 48 +-- T1 (ESF) 65 +-- 64 KBPS 1562 +-- 56 KBPS 1785 +-- 19.2 KBPS 5208 +-- 9.6 KBPS 10416 + +-- Routes that are not specified use the default (TOS 0) metric + + ospfIfMetricTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfIfMetricEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The TOS metrics for a non-virtual interface + identified by the interface index." + REFERENCE + "OSPF Version 2, Appendix C.3 Router interface + parameters" + ::= { ospf 8 } + + ospfIfMetricEntry OBJECT-TYPE + SYNTAX OspfIfMetricEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A particular TOS metric for a non-virtual in- + terface identified by the interface index." + REFERENCE + "OSPF Version 2, Appendix C.3 Router interface + parameters" + INDEX { ospfIfMetricIpAddress, + ospfIfMetricAddressLessIf, + ospfIfMetricTOS } + ::= { ospfIfMetricTable 1 } + +OspfIfMetricEntry ::= + SEQUENCE { + ospfIfMetricIpAddress + IpAddress, + ospfIfMetricAddressLessIf + Integer32, + ospfIfMetricTOS + TOSType, + ospfIfMetricValue + Metric, + ospfIfMetricStatus + RowStatus + } + + ospfIfMetricIpAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address of this OSPF interface. On row + creation, this can be derived from the in- + stance." + ::= { ospfIfMetricEntry 1 } + + ospfIfMetricAddressLessIf OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "For the purpose of easing the instancing of + addressed and addressless interfaces; This + variable takes the value 0 on interfaces with + IP Addresses, and the value of ifIndex for in- + terfaces having no IP Address. On row crea- + tion, this can be derived from the instance." + ::= { ospfIfMetricEntry 2 } + + + ospfIfMetricTOS OBJECT-TYPE + SYNTAX TOSType + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The type of service metric being referenced. + On row creation, this can be derived from the + instance." + ::= { ospfIfMetricEntry 3 } + + + ospfIfMetricValue OBJECT-TYPE + SYNTAX Metric + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The metric of using this type of service on + this interface. The default value of the TOS 0 + Metric is 10^8 / ifSpeed." + ::= { ospfIfMetricEntry 4 } + + ospfIfMetricStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfIfMetricEntry 5 } + + +-- OSPF Virtual Interface Table + +-- The Virtual Interface Table describes the virtual +-- links that the OSPF Process is configured to +-- carry on. + + ospfVirtIfTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfVirtIfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information about this router's virtual inter- + faces." + REFERENCE + "OSPF Version 2, Appendix C.4 Virtual link + parameters" + ::= { ospf 9 } + + + ospfVirtIfEntry OBJECT-TYPE + SYNTAX OspfVirtIfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information about a single Virtual Interface." + INDEX { ospfVirtIfAreaId, ospfVirtIfNeighbor } + ::= { ospfVirtIfTable 1 } + +OspfVirtIfEntry ::= + SEQUENCE { + ospfVirtIfAreaId + AreaID, + ospfVirtIfNeighbor + RouterID, + ospfVirtIfTransitDelay + UpToMaxAge, + ospfVirtIfRetransInterval + UpToMaxAge, + ospfVirtIfHelloInterval + HelloRange, + ospfVirtIfRtrDeadInterval + PositiveInteger, + ospfVirtIfState + INTEGER, + ospfVirtIfEvents + Counter32, + ospfVirtIfAuthType + INTEGER, + ospfVirtIfAuthKey + OCTET STRING, + ospfVirtIfStatus + RowStatus + } + + ospfVirtIfAreaId OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Transit Area that the Virtual Link + traverses. By definition, this is not 0.0.0.0" + ::= { ospfVirtIfEntry 1 } + + + ospfVirtIfNeighbor OBJECT-TYPE + SYNTAX RouterID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Router ID of the Virtual Neighbor." + ::= { ospfVirtIfEntry 2 } + + + ospfVirtIfTransitDelay OBJECT-TYPE + SYNTAX UpToMaxAge + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The estimated number of seconds it takes to + transmit a link- state update packet over this + interface." + DEFVAL { 1 } + ::= { ospfVirtIfEntry 3 } + + + ospfVirtIfRetransInterval OBJECT-TYPE + SYNTAX UpToMaxAge + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The number of seconds between link-state ad- + vertisement retransmissions, for adjacencies + belonging to this interface. This value is + also used when retransmitting database descrip- + tion and link-state request packets. This + value should be well over the expected round- + trip time." + DEFVAL { 5 } + ::= { ospfVirtIfEntry 4 } + + + ospfVirtIfHelloInterval OBJECT-TYPE + SYNTAX HelloRange + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The length of time, in seconds, between the + Hello packets that the router sends on the in- + terface. This value must be the same for the + virtual neighbor." + DEFVAL { 10 } + ::= { ospfVirtIfEntry 5 } + + + ospfVirtIfRtrDeadInterval OBJECT-TYPE + SYNTAX PositiveInteger + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The number of seconds that a router's Hello + packets have not been seen before it's neigh- + bors declare the router down. This should be + some multiple of the Hello interval. This + value must be the same for the virtual neigh- + bor." + DEFVAL { 60 } + ::= { ospfVirtIfEntry 6 } + + + ospfVirtIfState OBJECT-TYPE + SYNTAX INTEGER { + down (1), -- these use the same encoding + pointToPoint (4) -- as the ospfIfTable + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "OSPF virtual interface states." + DEFVAL { down } + ::= { ospfVirtIfEntry 7 } + + + ospfVirtIfEvents OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of state changes or error events on + this Virtual Link" + ::= { ospfVirtIfEntry 8 } + + + ospfVirtIfAuthKey OBJECT-TYPE + SYNTAX OCTET STRING (SIZE(0..256)) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "If Authentication Type is simplePassword, the + device will left adjust and zero fill to 8 oc- + tets. + + Note that unauthenticated interfaces need no + authentication key, and simple password authen- + tication cannot use a key of more than 8 oc- + tets. Larger keys are useful only with authen- + tication mechanisms not specified in this docu- + ment. + + When read, ospfVifAuthKey always returns a + string of length zero." + REFERENCE + "OSPF Version 2, Section 9 The Interface Data + Structure" + DEFVAL { '0000000000000000'H } -- 0.0.0.0.0.0.0.0 + ::= { ospfVirtIfEntry 9 } + + + ospfVirtIfStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfVirtIfEntry 10 } + + + ospfVirtIfAuthType OBJECT-TYPE + SYNTAX INTEGER (0..255) + -- none (0), + -- simplePassword (1) + -- md5 (2) + -- reserved for specification by IANA (> 2) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The authentication type specified for a virtu- + al interface. Additional authentication types + may be assigned locally." + REFERENCE + "OSPF Version 2, Appendix E Authentication" + DEFVAL { 0 } -- no authentication, by default + ::= { ospfVirtIfEntry 11 } + + +-- OSPF Neighbor Table + +-- The OSPF Neighbor Table describes all neighbors in +-- the locality of the subject router. + + ospfNbrTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfNbrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table of non-virtual neighbor information." + REFERENCE + "OSPF Version 2, Section 10 The Neighbor Data + Structure" + ::= { ospf 10 } + + + ospfNbrEntry OBJECT-TYPE + SYNTAX OspfNbrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The information regarding a single neighbor." + REFERENCE + "OSPF Version 2, Section 10 The Neighbor Data + Structure" + INDEX { ospfNbrIpAddr, ospfNbrAddressLessIndex } + ::= { ospfNbrTable 1 } + +OspfNbrEntry ::= + SEQUENCE { + ospfNbrIpAddr + IpAddress, + ospfNbrAddressLessIndex + InterfaceIndex, + ospfNbrRtrId + RouterID, + ospfNbrOptions + Integer32, + ospfNbrPriority + DesignatedRouterPriority, + ospfNbrState + INTEGER, + ospfNbrEvents + Counter32, + ospfNbrLsRetransQLen + Gauge32, + ospfNbmaNbrStatus + RowStatus, + ospfNbmaNbrPermanence + INTEGER, + ospfNbrHelloSuppressed + TruthValue + } + + ospfNbrIpAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address this neighbor is using in its + IP Source Address. Note that, on addressless + links, this will not be 0.0.0.0, but the ad- + dress of another of the neighbor's interfaces." + ::= { ospfNbrEntry 1 } + + + ospfNbrAddressLessIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "On an interface having an IP Address, zero. + On addressless interfaces, the corresponding + value of ifIndex in the Internet Standard MIB. + On row creation, this can be derived from the + instance." + ::= { ospfNbrEntry 2 } + + + ospfNbrRtrId OBJECT-TYPE + SYNTAX RouterID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A 32-bit integer (represented as a type IpAd- + dress) uniquely identifying the neighboring + router in the Autonomous System." + DEFVAL { '00000000'H } -- 0.0.0.0 + ::= { ospfNbrEntry 3 } + + + ospfNbrOptions OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A Bit Mask corresponding to the neighbor's op- + tions field. + + Bit 0, if set, indicates that the system will + operate on Type of Service metrics other than + TOS 0. If zero, the neighbor will ignore all + metrics except the TOS 0 metric. + + Bit 1, if set, indicates that the associated + area accepts and operates on external informa- + tion; if zero, it is a stub area. + + Bit 2, if set, indicates that the system is ca- + pable of routing IP Multicast datagrams; i.e., + that it implements the Multicast Extensions to + OSPF. + + Bit 3, if set, indicates that the associated + area is an NSSA. These areas are capable of + carrying type 7 external advertisements, which + are translated into type 5 external advertise- + ments at NSSA borders." + REFERENCE + "OSPF Version 2, Section 12.1.2 Options" + DEFVAL { 0 } + ::= { ospfNbrEntry 4 } + + + ospfNbrPriority OBJECT-TYPE + SYNTAX DesignatedRouterPriority + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The priority of this neighbor in the designat- + ed router election algorithm. The value 0 sig- + nifies that the neighbor is not eligible to be- + come the designated router on this particular + network." + DEFVAL { 1 } + ::= { ospfNbrEntry 5 } + + + ospfNbrState OBJECT-TYPE + SYNTAX INTEGER { + down (1), + attempt (2), + init (3), + twoWay (4), + exchangeStart (5), + exchange (6), + loading (7), + full (8) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The State of the relationship with this Neigh- + bor." + REFERENCE + "OSPF Version 2, Section 10.1 Neighbor States" + DEFVAL { down } + ::= { ospfNbrEntry 6 } + + + ospfNbrEvents OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times this neighbor relationship + has changed state, or an error has occurred." + ::= { ospfNbrEntry 7 } + + + ospfNbrLsRetransQLen OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The current length of the retransmission + queue." + ::= { ospfNbrEntry 8 } + + + ospfNbmaNbrStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfNbrEntry 9 } + + + ospfNbmaNbrPermanence OBJECT-TYPE + SYNTAX INTEGER { + dynamic (1), -- learned through protocol + permanent (2) -- configured address + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. 'dynamic' and 'permanent' refer to how + the neighbor became known." + DEFVAL { permanent } + ::= { ospfNbrEntry 10 } + + + ospfNbrHelloSuppressed OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Indicates whether Hellos are being suppressed + to the neighbor" + ::= { ospfNbrEntry 11 } + + +-- OSPF Virtual Neighbor Table + +-- This table describes all virtual neighbors. +-- Since Virtual Links are configured in the +-- virtual interface table, this table is read-only. + + ospfVirtNbrTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfVirtNbrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table of virtual neighbor information." + REFERENCE + "OSPF Version 2, Section 15 Virtual Links" + ::= { ospf 11 } + + + ospfVirtNbrEntry OBJECT-TYPE + SYNTAX OspfVirtNbrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Virtual neighbor information." + INDEX { ospfVirtNbrArea, ospfVirtNbrRtrId } + ::= { ospfVirtNbrTable 1 } + +OspfVirtNbrEntry ::= + SEQUENCE { + ospfVirtNbrArea + AreaID, + ospfVirtNbrRtrId + RouterID, + ospfVirtNbrIpAddr + IpAddress, + ospfVirtNbrOptions + Integer32, + ospfVirtNbrState + INTEGER, + ospfVirtNbrEvents + Counter32, + ospfVirtNbrLsRetransQLen + Gauge32, + ospfVirtNbrHelloSuppressed + TruthValue + } + + ospfVirtNbrArea OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Transit Area Identifier." + ::= { ospfVirtNbrEntry 1 } + + + ospfVirtNbrRtrId OBJECT-TYPE + SYNTAX RouterID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A 32-bit integer uniquely identifying the + neighboring router in the Autonomous System." + ::= { ospfVirtNbrEntry 2 } + + + ospfVirtNbrIpAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address this Virtual Neighbor is us- + ing." + ::= { ospfVirtNbrEntry 3 } + + + ospfVirtNbrOptions OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A Bit Mask corresponding to the neighbor's op- + tions field. + + Bit 1, if set, indicates that the system will + operate on Type of Service metrics other than + TOS 0. If zero, the neighbor will ignore all + metrics except the TOS 0 metric. + + Bit 2, if set, indicates that the system is + Network Multicast capable; ie, that it imple- + ments OSPF Multicast Routing." + ::= { ospfVirtNbrEntry 4 } + ospfVirtNbrState OBJECT-TYPE + SYNTAX INTEGER { + down (1), + attempt (2), + init (3), + twoWay (4), + exchangeStart (5), + exchange (6), + loading (7), + full (8) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The state of the Virtual Neighbor Relation- + ship." + ::= { ospfVirtNbrEntry 5 } + + + ospfVirtNbrEvents OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times this virtual link has + changed its state, or an error has occurred." + ::= { ospfVirtNbrEntry 6 } + + + ospfVirtNbrLsRetransQLen OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The current length of the retransmission + queue." + ::= { ospfVirtNbrEntry 7 } + + + ospfVirtNbrHelloSuppressed OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Indicates whether Hellos are being suppressed + to the neighbor" + ::= { ospfVirtNbrEntry 8 } + +-- OSPF Link State Database, External + +-- The Link State Database contains the Link State +-- Advertisements from throughout the areas that the +-- device is attached to. + +-- This table is identical to the OSPF LSDB Table in +-- format, but contains only External Link State +-- Advertisements. The purpose is to allow external +-- LSAs to be displayed once for the router rather +-- than once in each non-stub area. + + ospfExtLsdbTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfExtLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The OSPF Process's Links State Database." + REFERENCE + "OSPF Version 2, Section 12 Link State Adver- + tisements" + ::= { ospf 12 } + + + ospfExtLsdbEntry OBJECT-TYPE + SYNTAX OspfExtLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A single Link State Advertisement." + INDEX { ospfExtLsdbType, ospfExtLsdbLsid, ospfExtLsdbRouterId } + ::= { ospfExtLsdbTable 1 } + +OspfExtLsdbEntry ::= + SEQUENCE { + ospfExtLsdbType + INTEGER, + ospfExtLsdbLsid + IpAddress, + ospfExtLsdbRouterId + RouterID, + ospfExtLsdbSequence + Integer32, + ospfExtLsdbAge + Integer32, + ospfExtLsdbChecksum + Integer32, + ospfExtLsdbAdvertisement + OCTET STRING + } + + ospfExtLsdbType OBJECT-TYPE + SYNTAX INTEGER { + asExternalLink (5) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The type of the link state advertisement. + Each link state type has a separate advertise- + ment format." + REFERENCE + "OSPF Version 2, Appendix A.4.1 The Link State + Advertisement header" + ::= { ospfExtLsdbEntry 1 } + + + ospfExtLsdbLsid OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Link State ID is an LS Type Specific field + containing either a Router ID or an IP Address; + it identifies the piece of the routing domain + that is being described by the advertisement." + REFERENCE + "OSPF Version 2, Section 12.1.4 Link State ID" + ::= { ospfExtLsdbEntry 2 } + + + ospfExtLsdbRouterId OBJECT-TYPE + SYNTAX RouterID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32 bit number that uniquely identifies the + originating router in the Autonomous System." + REFERENCE + "OSPF Version 2, Appendix C.1 Global parameters" + ::= { ospfExtLsdbEntry 3 } + +-- Note that the OSPF Sequence Number is a 32 bit signed +-- integer. It starts with the value '80000001'h, +-- or -'7FFFFFFF'h, and increments until '7FFFFFFF'h +-- Thus, a typical sequence number will be very negative. + ospfExtLsdbSequence OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The sequence number field is a signed 32-bit + integer. It is used to detect old and dupli- + cate link state advertisements. The space of + sequence numbers is linearly ordered. The + larger the sequence number the more recent the + advertisement." + REFERENCE + "OSPF Version 2, Section 12.1.6 LS sequence + number" + ::= { ospfExtLsdbEntry 4 } + + + ospfExtLsdbAge OBJECT-TYPE + SYNTAX Integer32 -- Should be 0..MaxAge + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the age of the link state adver- + tisement in seconds." + REFERENCE + "OSPF Version 2, Section 12.1.1 LS age" + ::= { ospfExtLsdbEntry 5 } + + + ospfExtLsdbChecksum OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the checksum of the complete + contents of the advertisement, excepting the + age field. The age field is excepted so that + an advertisement's age can be incremented + without updating the checksum. The checksum + used is the same that is used for ISO connec- + tionless datagrams; it is commonly referred to + as the Fletcher checksum." + REFERENCE + "OSPF Version 2, Section 12.1.7 LS checksum" + ::= { ospfExtLsdbEntry 6 } + + + ospfExtLsdbAdvertisement OBJECT-TYPE + SYNTAX OCTET STRING (SIZE(36)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The entire Link State Advertisement, including + its header." + REFERENCE + "OSPF Version 2, Section 12 Link State Adver- + tisements" + ::= { ospfExtLsdbEntry 7 } + + +-- OSPF Use of the CIDR Route Table + +ospfRouteGroup OBJECT IDENTIFIER ::= { ospf 13 } + +-- The IP Forwarding Table defines a number of objects for use by +-- the routing protocol to externalize its information. Most of +-- the variables (ipForwardDest, ipForwardMask, ipForwardPolicy, +-- ipForwardNextHop, ipForwardIfIndex, ipForwardType, +-- ipForwardProto, ipForwardAge, and ipForwardNextHopAS) are +-- defined there. + +-- Those that leave some discretion are defined here. + +-- ipCidrRouteProto is, of course, ospf (13). + +-- ipCidrRouteAge is the time since the route was first calculated, +-- as opposed to the time since the last SPF run. + +-- ipCidrRouteInfo is an OBJECT IDENTIFIER for use by the routing +-- protocol. The following values shall be found there depending +-- on the way the route was calculated. + +ospfIntraArea OBJECT IDENTIFIER ::= { ospfRouteGroup 1 } +ospfInterArea OBJECT IDENTIFIER ::= { ospfRouteGroup 2 } +ospfExternalType1 OBJECT IDENTIFIER ::= { ospfRouteGroup 3 } +ospfExternalType2 OBJECT IDENTIFIER ::= { ospfRouteGroup 4 } + +-- ipCidrRouteMetric1 is, by definition, the primary routing +-- metric. Therefore, it should be the metric that route +-- selection is based on. For intra-area and inter-area routes, +-- it is an OSPF metric. For External Type 1 (comparable value) +-- routes, it is an OSPF metric plus the External Metric. For +-- external Type 2 (non-comparable value) routes, it is the +-- external metric. + +-- ipCidrRouteMetric2 is, by definition, a secondary routing +-- metric. Therefore, it should be the metric that breaks a tie +-- among routes having equal metric1 values and the same +-- calculation rule. For intra-area, inter-area routes, and +-- External Type 1 (comparable value) routes, it is unused. For +-- external Type 2 (non-comparable value) routes, it is the metric +-- to the AS border router. + +-- ipCidrRouteMetric3, ipCidrRouteMetric4, and ipCidrRouteMetric5 are +-- unused. + +-- +-- The OSPF Area Aggregate Table +-- +-- This table replaces the OSPF Area Summary Table, being an +-- extension of that for CIDR routers. + + ospfAreaAggregateTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfAreaAggregateEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A range of IP addresses specified by an IP + address/IP network mask pair. For example, + class B address range of X.X.X.X with a network + mask of 255.255.0.0 includes all IP addresses + from X.X.0.0 to X.X.255.255. Note that if + ranges are configured such that one range sub- + sumes another range (e.g., 10.0.0.0 mask + 255.0.0.0 and 10.1.0.0 mask 255.255.0.0), the + most specific match is the preferred one." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospf 14 } + + + ospfAreaAggregateEntry OBJECT-TYPE + SYNTAX OspfAreaAggregateEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A range of IP addresses specified by an IP + address/IP network mask pair. For example, + class B address range of X.X.X.X with a network + mask of 255.255.0.0 includes all IP addresses + from X.X.0.0 to X.X.255.255. Note that if + ranges are range configured such that one range + subsumes another range (e.g., 10.0.0.0 mask + 255.0.0.0 and 10.1.0.0 mask 255.255.0.0), the + most specific match is the preferred one." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + INDEX { ospfAreaAggregateAreaID, ospfAreaAggregateLsdbType, + ospfAreaAggregateNet, ospfAreaAggregateMask } + ::= { ospfAreaAggregateTable 1 } + + +OspfAreaAggregateEntry ::= + SEQUENCE { + ospfAreaAggregateAreaID + AreaID, + ospfAreaAggregateLsdbType + INTEGER, + ospfAreaAggregateNet + IpAddress, + ospfAreaAggregateMask + IpAddress, + ospfAreaAggregateStatus + RowStatus, + ospfAreaAggregateEffect + INTEGER + } + + ospfAreaAggregateAreaID OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Area the Address Aggregate is to be found + within." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaAggregateEntry 1 } + + + ospfAreaAggregateLsdbType OBJECT-TYPE + SYNTAX INTEGER { + summaryLink (3), + nssaExternalLink (7) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The type of the Address Aggregate. This field + specifies the Lsdb type that this Address Ag- + gregate applies to." + REFERENCE + "OSPF Version 2, Appendix A.4.1 The Link State + Advertisement header" + ::= { ospfAreaAggregateEntry 2 } + + + ospfAreaAggregateNet OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of the Net or Subnet indicated + by the range." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaAggregateEntry 3 } + + + ospfAreaAggregateMask OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Subnet Mask that pertains to the Net or + Subnet." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaAggregateEntry 4 } + + + ospfAreaAggregateStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfAreaAggregateEntry 5 } + + + ospfAreaAggregateEffect OBJECT-TYPE + SYNTAX INTEGER { + advertiseMatching (1), + doNotAdvertiseMatching (2) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Subnets subsumed by ranges either trigger the + advertisement of the indicated aggregate (ad- + vertiseMatching), or result in the subnet's not + being advertised at all outside the area." + DEFVAL { advertiseMatching } + ::= { ospfAreaAggregateEntry 6 } + + +-- conformance information + +ospfConformance OBJECT IDENTIFIER ::= { ospf 15 } + +ospfGroups OBJECT IDENTIFIER ::= { ospfConformance 1 } +ospfCompliances OBJECT IDENTIFIER ::= { ospfConformance 2 } + +-- compliance statements + + ospfCompliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement " + MODULE -- this module + MANDATORY-GROUPS { + ospfBasicGroup, + ospfAreaGroup, + ospfStubAreaGroup, + ospfIfGroup, + ospfIfMetricGroup, + ospfVirtIfGroup, + ospfNbrGroup, + ospfVirtNbrGroup, + ospfAreaAggregateGroup + } + ::= { ospfCompliances 1 } + + +-- units of conformance + + ospfBasicGroup OBJECT-GROUP + OBJECTS { + ospfRouterId, + ospfAdminStat, + ospfVersionNumber, + ospfAreaBdrRtrStatus, + ospfASBdrRtrStatus, + ospfExternLsaCount, + ospfExternLsaCksumSum, + ospfTOSSupport, + ospfOriginateNewLsas, + ospfRxNewLsas, + ospfExtLsdbLimit, + ospfMulticastExtensions, + ospfExitOverflowInterval, + ospfDemandExtensions + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 1 } + + + ospfAreaGroup OBJECT-GROUP + OBJECTS { + ospfAreaId, + ospfImportAsExtern, + ospfSpfRuns, + ospfAreaBdrRtrCount, + ospfAsBdrRtrCount, + ospfAreaLsaCount, + ospfAreaLsaCksumSum, + ospfAreaSummary, + ospfAreaStatus + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems + supporting areas." + ::= { ospfGroups 2 } + + + ospfStubAreaGroup OBJECT-GROUP + OBJECTS { + ospfStubAreaId, + ospfStubTOS, + ospfStubMetric, + ospfStubStatus, + ospfStubMetricType + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems + supporting stub areas." + ::= { ospfGroups 3 } + + + ospfLsdbGroup OBJECT-GROUP + OBJECTS { + ospfLsdbAreaId, + ospfLsdbType, + ospfLsdbLsid, + ospfLsdbRouterId, + ospfLsdbSequence, + ospfLsdbAge, + ospfLsdbChecksum, + ospfLsdbAdvertisement + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems + that display their link state database." + ::= { ospfGroups 4 } + + + ospfAreaRangeGroup OBJECT-GROUP + OBJECTS { + ospfAreaRangeAreaId, + ospfAreaRangeNet, + ospfAreaRangeMask, + ospfAreaRangeStatus, + ospfAreaRangeEffect + } + STATUS obsolete + DESCRIPTION + "These objects are required for non-CIDR OSPF + systems that support multiple areas." + ::= { ospfGroups 5 } + + + ospfHostGroup OBJECT-GROUP + OBJECTS { + ospfHostIpAddress, + ospfHostTOS, + ospfHostMetric, + ospfHostStatus, + ospfHostAreaID + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems + that support attached hosts." + ::= { ospfGroups 6 } + + + ospfIfGroup OBJECT-GROUP + OBJECTS { + ospfIfIpAddress, + ospfAddressLessIf, + ospfIfAreaId, + ospfIfType, + ospfIfAdminStat, + ospfIfRtrPriority, + ospfIfTransitDelay, + ospfIfRetransInterval, + ospfIfHelloInterval, + ospfIfRtrDeadInterval, + ospfIfPollInterval, + ospfIfState, + ospfIfDesignatedRouter, + ospfIfBackupDesignatedRouter, + ospfIfEvents, + ospfIfAuthType, + ospfIfAuthKey, + ospfIfStatus, + ospfIfMulticastForwarding, + ospfIfDemand + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 7 } + + + ospfIfMetricGroup OBJECT-GROUP + OBJECTS { + ospfIfMetricIpAddress, + ospfIfMetricAddressLessIf, + ospfIfMetricTOS, + ospfIfMetricValue, + ospfIfMetricStatus + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 8 } + + + ospfVirtIfGroup OBJECT-GROUP + OBJECTS { + ospfVirtIfAreaId, + ospfVirtIfNeighbor, + ospfVirtIfTransitDelay, + ospfVirtIfRetransInterval, + ospfVirtIfHelloInterval, + ospfVirtIfRtrDeadInterval, + ospfVirtIfState, + ospfVirtIfEvents, + ospfVirtIfAuthType, + ospfVirtIfAuthKey, + ospfVirtIfStatus + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 9 } + + + ospfNbrGroup OBJECT-GROUP + OBJECTS { + ospfNbrIpAddr, + ospfNbrAddressLessIndex, + ospfNbrRtrId, + ospfNbrOptions, + ospfNbrPriority, + ospfNbrState, + ospfNbrEvents, + ospfNbrLsRetransQLen, + ospfNbmaNbrStatus, + ospfNbmaNbrPermanence, + ospfNbrHelloSuppressed + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 10 } + + + ospfVirtNbrGroup OBJECT-GROUP + OBJECTS { + ospfVirtNbrArea, + ospfVirtNbrRtrId, + ospfVirtNbrIpAddr, + ospfVirtNbrOptions, + ospfVirtNbrState, + ospfVirtNbrEvents, + ospfVirtNbrLsRetransQLen, + ospfVirtNbrHelloSuppressed + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 11 } + + + ospfExtLsdbGroup OBJECT-GROUP + OBJECTS { + ospfExtLsdbType, + ospfExtLsdbLsid, + ospfExtLsdbRouterId, + ospfExtLsdbSequence, + ospfExtLsdbAge, + ospfExtLsdbChecksum, + ospfExtLsdbAdvertisement + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems + that display their link state database." + ::= { ospfGroups 12 } + + + ospfAreaAggregateGroup OBJECT-GROUP + OBJECTS { + ospfAreaAggregateAreaID, + ospfAreaAggregateLsdbType, + ospfAreaAggregateNet, + ospfAreaAggregateMask, + ospfAreaAggregateStatus, + ospfAreaAggregateEffect + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 13 } + +END diff --git a/ospfd/OSPF-TRAP-MIB.txt b/ospfd/OSPF-TRAP-MIB.txt new file mode 100644 index 00000000..8a3ab990 --- /dev/null +++ b/ospfd/OSPF-TRAP-MIB.txt @@ -0,0 +1,443 @@ +OSPF-TRAP-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE, IpAddress + FROM SNMPv2-SMI + MODULE-COMPLIANCE, OBJECT-GROUP + FROM SNMPv2-CONF + ospfRouterId, ospfIfIpAddress, ospfAddressLessIf, ospfIfState, + ospfVirtIfAreaId, ospfVirtIfNeighbor, ospfVirtIfState, + ospfNbrIpAddr, ospfNbrAddressLessIndex, ospfNbrRtrId, + ospfNbrState, ospfVirtNbrArea, ospfVirtNbrRtrId, ospfVirtNbrState, + ospfLsdbType, ospfLsdbLsid, ospfLsdbRouterId, ospfLsdbAreaId, + ospfExtLsdbLimit, ospf + FROM OSPF-MIB; + + ospfTrap MODULE-IDENTITY + LAST-UPDATED "9501201225Z" -- Fri Jan 20 12:25:50 PST 1995 + ORGANIZATION "IETF OSPF Working Group" + CONTACT-INFO + " Fred Baker + Postal: Cisco Systems + 519 Lado Drive + Santa Barbara, California 93111 + Tel: +1 805 681 0115 + E-Mail: fred@cisco.com + + Rob Coltun + Postal: RainbowBridge Communications + Tel: (301) 340-9416 + E-Mail: rcoltun@rainbow-bridge.com" + DESCRIPTION + "The MIB module to describe traps for the OSPF + Version 2 Protocol." + ::= { ospf 16 } + +-- Trap Support Objects + +-- The following are support objects for the OSPF traps. + +ospfTrapControl OBJECT IDENTIFIER ::= { ospfTrap 1 } +ospfTraps OBJECT IDENTIFIER ::= { ospfTrap 2 } + + ospfSetTrap OBJECT-TYPE + SYNTAX OCTET STRING (SIZE(4)) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "A four-octet string serving as a bit map for + the trap events defined by the OSPF traps. This + object is used to enable and disable specific + OSPF traps where a 1 in the bit field + represents enabled. The right-most bit (least + significant) represents trap 0." + ::= { ospfTrapControl 1 } + + + ospfConfigErrorType OBJECT-TYPE + SYNTAX INTEGER { + badVersion (1), + areaMismatch (2), + unknownNbmaNbr (3), -- Router is Dr eligible + unknownVirtualNbr (4), + authTypeMismatch(5), + authFailure (6), + netMaskMismatch (7), + helloIntervalMismatch (8), + deadIntervalMismatch (9), + optionMismatch (10) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Potential types of configuration conflicts. + Used by the ospfConfigError and ospfConfigVir- + tError traps." + ::= { ospfTrapControl 2 } + + + ospfPacketType OBJECT-TYPE + SYNTAX INTEGER { + hello (1), + dbDescript (2), + lsReq (3), + lsUpdate (4), + lsAck (5) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "OSPF packet types." + ::= { ospfTrapControl 3 } + + + ospfPacketSrc OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address of an inbound packet that can- + not be identified by a neighbor instance." + ::= { ospfTrapControl 4 } + + +-- Traps + + + ospfIfStateChange NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfIfIpAddress, + ospfAddressLessIf, + ospfIfState -- The new state + } + STATUS current + DESCRIPTION + "An ospfIfStateChange trap signifies that there + has been a change in the state of a non-virtual + OSPF interface. This trap should be generated + when the interface state regresses (e.g., goes + from Dr to Down) or progresses to a terminal + state (i.e., Point-to-Point, DR Other, Dr, or + Backup)." + ::= { ospfTraps 16 } + + + ospfVirtIfStateChange NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfVirtIfAreaId, + ospfVirtIfNeighbor, + ospfVirtIfState -- The new state + } + STATUS current + DESCRIPTION + "An ospfIfStateChange trap signifies that there + has been a change in the state of an OSPF vir- + tual interface. + This trap should be generated when the inter- + face state regresses (e.g., goes from Point- + to-Point to Down) or progresses to a terminal + state (i.e., Point-to-Point)." + ::= { ospfTraps 1 } + + + ospfNbrStateChange NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfNbrIpAddr, + ospfNbrAddressLessIndex, + ospfNbrRtrId, + ospfNbrState -- The new state + } + STATUS current + DESCRIPTION + "An ospfNbrStateChange trap signifies that + there has been a change in the state of a non- + virtual OSPF neighbor. This trap should be + generated when the neighbor state regresses + (e.g., goes from Attempt or Full to 1-Way or + Down) or progresses to a terminal state (e.g., + 2-Way or Full). When an neighbor transitions + from or to Full on non-broadcast multi-access + and broadcast networks, the trap should be gen- + erated by the designated router. A designated + router transitioning to Down will be noted by + ospfIfStateChange." + ::= { ospfTraps 2 } + + + ospfVirtNbrStateChange NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfVirtNbrArea, + ospfVirtNbrRtrId, + ospfVirtNbrState -- The new state + } + STATUS current + DESCRIPTION + "An ospfIfStateChange trap signifies that there + has been a change in the state of an OSPF vir- + tual neighbor. This trap should be generated + when the neighbor state regresses (e.g., goes + from Attempt or Full to 1-Way or Down) or + progresses to a terminal state (e.g., Full)." + ::= { ospfTraps 3 } + ospfIfConfigError NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfIfIpAddress, + ospfAddressLessIf, + ospfPacketSrc, -- The source IP address + ospfConfigErrorType, -- Type of error + ospfPacketType + } + STATUS current + DESCRIPTION + "An ospfIfConfigError trap signifies that a + packet has been received on a non-virtual in- + terface from a router whose configuration + parameters conflict with this router's confi- + guration parameters. Note that the event op- + tionMismatch should cause a trap only if it + prevents an adjacency from forming." + ::= { ospfTraps 4 } + + + ospfVirtIfConfigError NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfVirtIfAreaId, + ospfVirtIfNeighbor, + ospfConfigErrorType, -- Type of error + ospfPacketType + } + STATUS current + DESCRIPTION + "An ospfConfigError trap signifies that a pack- + et has been received on a virtual interface + from a router whose configuration parameters + conflict with this router's configuration + parameters. Note that the event optionMismatch + should cause a trap only if it prevents an ad- + jacency from forming." + ::= { ospfTraps 5 } + + + ospfIfAuthFailure NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfIfIpAddress, + ospfAddressLessIf, + ospfPacketSrc, -- The source IP address + ospfConfigErrorType, -- authTypeMismatch or + -- authFailure + ospfPacketType + } + STATUS current + DESCRIPTION + "An ospfIfAuthFailure trap signifies that a + packet has been received on a non-virtual in- + terface from a router whose authentication key + or authentication type conflicts with this + router's authentication key or authentication + type." + ::= { ospfTraps 6 } + + + ospfVirtIfAuthFailure NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfVirtIfAreaId, + ospfVirtIfNeighbor, + ospfConfigErrorType, -- authTypeMismatch or + -- authFailure + ospfPacketType + } + STATUS current + DESCRIPTION + "An ospfVirtIfAuthFailure trap signifies that a + packet has been received on a virtual interface + from a router whose authentication key or au- + thentication type conflicts with this router's + authentication key or authentication type." + ::= { ospfTraps 7 } + + + ospfIfRxBadPacket NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfIfIpAddress, + ospfAddressLessIf, + ospfPacketSrc, -- The source IP address + ospfPacketType + } + STATUS current + DESCRIPTION + "An ospfIfRxBadPacket trap signifies that an + OSPF packet has been received on a non-virtual + interface that cannot be parsed." + ::= { ospfTraps 8 } + + ospfVirtIfRxBadPacket NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfVirtIfAreaId, + ospfVirtIfNeighbor, + ospfPacketType + } + STATUS current + DESCRIPTION + "An ospfRxBadPacket trap signifies that an OSPF + packet has been received on a virtual interface + that cannot be parsed." + ::= { ospfTraps 9 } + + + ospfTxRetransmit NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfIfIpAddress, + ospfAddressLessIf, + ospfNbrRtrId, -- Destination + ospfPacketType, + ospfLsdbType, + ospfLsdbLsid, + ospfLsdbRouterId + } + STATUS current + DESCRIPTION + "An ospfTxRetransmit trap signifies than an + OSPF packet has been retransmitted on a non- + virtual interface. All packets that may be re- + transmitted are associated with an LSDB entry. + The LS type, LS ID, and Router ID are used to + identify the LSDB entry." + ::= { ospfTraps 10 } + + + ospfVirtIfTxRetransmit NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfVirtIfAreaId, + ospfVirtIfNeighbor, + ospfPacketType, + ospfLsdbType, + ospfLsdbLsid, + ospfLsdbRouterId + } + STATUS current + DESCRIPTION + "An ospfTxRetransmit trap signifies than an + OSPF packet has been retransmitted on a virtual + interface. All packets that may be retransmit- + ted are associated with an LSDB entry. The LS + type, LS ID, and Router ID are used to identify + the LSDB entry." + ::= { ospfTraps 11 } + + + ospfOriginateLsa NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfLsdbAreaId, -- 0.0.0.0 for AS Externals + ospfLsdbType, + ospfLsdbLsid, + ospfLsdbRouterId + } + STATUS current + DESCRIPTION + "An ospfOriginateLsa trap signifies that a new + LSA has been originated by this router. This + trap should not be invoked for simple refreshes + of LSAs (which happesn every 30 minutes), but + instead will only be invoked when an LSA is + (re)originated due to a topology change. Addi- + tionally, this trap does not include LSAs that + are being flushed because they have reached + MaxAge." + ::= { ospfTraps 12 } + + + ospfMaxAgeLsa NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfLsdbAreaId, -- 0.0.0.0 for AS Externals + ospfLsdbType, + ospfLsdbLsid, + ospfLsdbRouterId + } + STATUS current + DESCRIPTION + "An ospfMaxAgeLsa trap signifies that one of + the LSA in the router's link-state database has + aged to MaxAge." + ::= { ospfTraps 13 } + + + ospfLsdbOverflow NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfExtLsdbLimit + } + STATUS current + DESCRIPTION + "An ospfLsdbOverflow trap signifies that the + number of LSAs in the router's link-state data- + base has exceeded ospfExtLsdbLimit." + ::= { ospfTraps 14 } + + + ospfLsdbApproachingOverflow NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfExtLsdbLimit + } + STATUS current + DESCRIPTION + "An ospfLsdbApproachingOverflow trap signifies + that the number of LSAs in the router's link- + state database has exceeded ninety percent of + ospfExtLsdbLimit." + ::= { ospfTraps 15 } + + +-- conformance information + +ospfTrapConformance OBJECT IDENTIFIER ::= { ospfTrap 3 } + +ospfTrapGroups OBJECT IDENTIFIER ::= { ospfTrapConformance 1 } +ospfTrapCompliances OBJECT IDENTIFIER ::= { ospfTrapConformance 2 } + +-- compliance statements + + ospfTrapCompliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement " + MODULE -- this module + MANDATORY-GROUPS { ospfTrapControlGroup } + + + GROUP ospfTrapControlGroup + DESCRIPTION + "This group is optional but recommended for all + OSPF systems" + ::= { ospfTrapCompliances 1 } + + +-- units of conformance + + ospfTrapControlGroup OBJECT-GROUP + OBJECTS { + ospfSetTrap, + ospfConfigErrorType, + ospfPacketType, + ospfPacketSrc + } + STATUS current + DESCRIPTION + "These objects are required to control traps + from OSPF systems." + ::= { ospfTrapGroups 1 } + + +END diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c new file mode 100644 index 00000000..ec3b153c --- /dev/null +++ b/ospfd/ospf_abr.c @@ -0,0 +1,1741 @@ +/* + * OSPF ABR functions. + * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + + +#include + +#include "thread.h" +#include "memory.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "vty.h" +#include "filter.h" +#include "plist.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ia.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_dump.h" + + +struct ospf_area_range * +ospf_area_range_new (struct prefix_ipv4 *p) +{ + struct ospf_area_range *range; + + range = XCALLOC (MTYPE_OSPF_AREA_RANGE, sizeof (struct ospf_area_range)); + range->addr = p->prefix; + range->masklen = p->prefixlen; + range->cost_config = OSPF_AREA_RANGE_COST_UNSPEC; + + return range; +} + +void +ospf_area_range_free (struct ospf_area_range *range) +{ + XFREE (MTYPE_OSPF_AREA_RANGE, range); +} + +void +ospf_area_range_add (struct ospf_area *area, struct ospf_area_range *range) +{ + struct route_node *rn; + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefixlen = range->masklen; + p.prefix = range->addr; + + rn = route_node_get (area->ranges, (struct prefix *)&p); + if (rn->info) + route_unlock_node (rn); + else + rn->info = range; +} + +void +ospf_area_range_delete (struct ospf_area *area, struct ospf_area_range *range) +{ + struct route_node *rn; + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefixlen = range->masklen; + p.prefix = range->addr; + + rn = route_node_lookup (area->ranges, (struct prefix *)&p); + if (rn) + { + ospf_area_range_free (rn->info); + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + } +} + +struct ospf_area_range * +ospf_area_range_lookup (struct ospf_area *area, struct prefix_ipv4 *p) +{ + struct route_node *rn; + + rn = route_node_lookup (area->ranges, (struct prefix *)p); + if (rn) + { + route_unlock_node (rn); + return rn->info; + } + return NULL; +} + +struct ospf_area_range * +ospf_area_range_lookup_next (struct ospf_area *area, struct in_addr *range_net, + int first) +{ + struct route_node *rn; + struct prefix_ipv4 p; + struct ospf_area_range *find; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.prefix = *range_net; + + if (first) + rn = route_top (area->ranges); + else + { + rn = route_node_get (area->ranges, (struct prefix *) &p); + rn = route_next (rn); + } + + for (; rn; rn = route_next (rn)) + if (rn->info) + break; + + if (rn && rn->info) + { + find = rn->info; + *range_net = rn->p.u.prefix4; + route_unlock_node (rn); + return find; + } + return NULL; +} + +struct ospf_area_range * +ospf_area_range_match (struct ospf_area *area, struct prefix_ipv4 *p) +{ + struct route_node *node; + + node = route_node_match (area->ranges, (struct prefix *) p); + if (node) + { + route_unlock_node (node); + return node->info; + } + return NULL; +} + +struct ospf_area_range * +ospf_area_range_match_any (struct ospf *ospf, struct prefix_ipv4 *p) +{ + struct ospf_area_range *range; + listnode node; + + for (node = listhead (ospf->areas); node; nextnode (node)) + if ((range = ospf_area_range_match (node->data, p))) + return range; + + return NULL; +} + +int +ospf_area_range_active (struct ospf_area_range *range) +{ + return range->specifics; +} + +int +ospf_area_actively_attached (struct ospf_area *area) +{ + return area->act_ints; +} + +int +ospf_area_range_set (struct ospf *ospf, struct in_addr area_id, + struct prefix_ipv4 *p, int advertise) +{ + struct ospf_area *area; + struct ospf_area_range *range; + int ret = OSPF_AREA_ID_FORMAT_DECIMAL; + + area = ospf_area_get (area_id, ret); + if (area == NULL) + return 0; + + range = ospf_area_range_lookup (area, p); + if (range != NULL) + { + if ((CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE) + && !CHECK_FLAG (advertise, OSPF_AREA_RANGE_ADVERTISE)) + || (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE) + && CHECK_FLAG (advertise, OSPF_AREA_RANGE_ADVERTISE))) + ospf_schedule_abr_task (); + } + else + { + range = ospf_area_range_new (p); + ospf_area_range_add (area, range); + ospf_schedule_abr_task (); + } + + if (CHECK_FLAG (advertise, OSPF_AREA_RANGE_ADVERTISE)) + SET_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE); + else + UNSET_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE); + + return 1; +} + +int +ospf_area_range_cost_set (struct ospf *ospf, struct in_addr area_id, + struct prefix_ipv4 *p, u_int32_t cost) +{ + struct ospf_area *area; + struct ospf_area_range *range; + int ret = OSPF_AREA_ID_FORMAT_DECIMAL; + + area = ospf_area_get (area_id, ret); + if (area == NULL) + return 0; + + range = ospf_area_range_new (p); + if (range == NULL) + return 0; + + if (range->cost_config != cost) + { + range->cost_config = cost; + if (ospf_area_range_active (range)) + ospf_schedule_abr_task (); + } + + return 1; +} + +int +ospf_area_range_unset (struct ospf *ospf, struct in_addr area_id, + struct prefix_ipv4 *p) +{ + struct ospf_area *area; + struct ospf_area_range *range; + + area = ospf_area_lookup_by_area_id (area_id); + if (area == NULL) + return 0; + + range = ospf_area_range_lookup (area, p); + if (range == NULL) + return 0; + + if (ospf_area_range_active (range)) + ospf_schedule_abr_task (); + + ospf_area_range_delete (area, range); + + return 1; +} + +int +ospf_area_range_substitute_set (struct ospf *ospf, struct in_addr area_id, + struct prefix_ipv4 *p, struct prefix_ipv4 *s) +{ + struct ospf_area *area; + struct ospf_area_range *range; + int ret = OSPF_AREA_ID_FORMAT_DECIMAL; + + area = ospf_area_get (area_id, ret); + range = ospf_area_range_lookup (area, p); + + if (range != NULL) + { + if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE) || + !CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) + ospf_schedule_abr_task (); + } + else + { + range = ospf_area_range_new (p); + ospf_area_range_add (area, range); + ospf_schedule_abr_task (); + } + + SET_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE); + SET_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE); + range->subst_addr = s->prefix; + range->subst_masklen = s->prefixlen; + + return 1; +} + +int +ospf_area_range_substitute_unset (struct ospf *ospf, struct in_addr area_id, + struct prefix_ipv4 *p) +{ + struct ospf_area *area; + struct ospf_area_range *range; + + area = ospf_area_lookup_by_area_id (area_id); + if (area == NULL) + return 0; + + range = ospf_area_range_lookup (area, p); + if (range == NULL) + return 0; + + if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) + if (ospf_area_range_active (range)) + ospf_schedule_abr_task (); + + UNSET_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE); + range->subst_addr.s_addr = 0; + range->subst_masklen = 0; + + return 1; +} + +int +ospf_act_bb_connection () +{ + if (ospf_top->backbone == NULL) + return 0; + + return ospf_top->backbone->full_nbrs; +} + +/* Check area border router status. */ +void +ospf_check_abr_status () +{ + struct ospf_area *area; + listnode node; + int bb_configured = 0; + int bb_act_attached = 0; + int areas_configured = 0; + int areas_act_attached = 0; + + u_char new_flags = ospf_top->flags; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_check_abr_status(): Start"); + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + area = getdata (node); + + if (listcount (area->oiflist)) + { + areas_configured++; + + if (OSPF_IS_AREA_BACKBONE (area)) + bb_configured = 1; + } + + if (ospf_area_actively_attached (area)) + { + areas_act_attached++; + + if (OSPF_IS_AREA_BACKBONE (area)) + bb_act_attached = 1; + } + } + + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("ospf_check_abr_status(): looked through areas"); + zlog_info ("ospf_check_abr_status(): bb_configured: %d", bb_configured); + zlog_info ("ospf_check_abr_status(): bb_act_attached: %d", + bb_act_attached); + zlog_info ("ospf_check_abr_status(): areas_configured: %d", + areas_configured); + zlog_info ("ospf_check_abr_status(): areas_act_attached: %d", + areas_act_attached); + } + + switch (ospf_top->abr_type) + { + case OSPF_ABR_SHORTCUT: + case OSPF_ABR_STAND: + if (areas_act_attached > 1) + SET_FLAG (new_flags, OSPF_FLAG_ABR); + else + UNSET_FLAG (new_flags, OSPF_FLAG_ABR); + break; + + case OSPF_ABR_IBM: + if ((areas_act_attached > 1) && bb_configured) + SET_FLAG (new_flags, OSPF_FLAG_ABR); + else + UNSET_FLAG (new_flags, OSPF_FLAG_ABR); + break; + + case OSPF_ABR_CISCO: + if ((areas_configured > 1) && bb_act_attached) + SET_FLAG (new_flags, OSPF_FLAG_ABR); + else + UNSET_FLAG (new_flags, OSPF_FLAG_ABR); + break; + default: + break; + } + + if (new_flags != ospf_top->flags) + { + ospf_spf_calculate_schedule (); + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_check_abr_status(): new router flags: %x",new_flags); + ospf_top->flags = new_flags; + OSPF_TIMER_ON (ospf_top->t_router_lsa_update, + ospf_router_lsa_update_timer, OSPF_LSA_UPDATE_DELAY); + } +} + +void +ospf_abr_update_aggregate (struct ospf_area_range *range, + struct ospf_route *or) +{ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_update_aggregate(): Start"); + + if (range->cost_config != -1) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_update_aggregate(): use configured cost %d", + range->cost_config); + + range->cost = range->cost_config; + } + else + { + if (range->specifics == 0) + range->cost = or->cost; /* 1st time get 1st cost */ + + if (or->cost < range->cost) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_update_aggregate(): lowest cost, update"); + + range->cost = or->cost; + } + } + + range->specifics++; +} + +static void +set_metric (struct ospf_lsa *lsa, u_int32_t metric) +{ + struct summary_lsa *header; + u_char *mp; + metric = htonl (metric); + mp = (char *) &metric; + mp++; + header = (struct summary_lsa *) lsa->data; + memcpy(header->metric, mp, 3); +} + +#ifdef HAVE_NSSA +int +ospf_abr_check_nssa_range (struct prefix_ipv4 *p, u_int32_t cost, + struct ospf_area *area) +{ + /* The Type-7 is tested against the aggregated prefix and forwarded + for lsa installation and flooding */ + return 0; +} + +/* ospf_abr_translate_nssa */ +int +ospf_abr_translate_nssa (struct ospf_lsa *lsa, void *p_arg, int int_arg) +{ + /* Incoming Type-7 or later aggregated Type-7 + + LSA is skipped if P-bit is off. + LSA is aggregated if within range. + + The Type-7 is translated, Installed/Approved as a Type-5 into + global LSDB, then Flooded through AS + + Later, any Unapproved Translated Type-5's are flushed/discarded */ + + struct ospf_lsa *dup; + + if (! CHECK_FLAG (lsa->data->options, OSPF_OPTION_NP)) + { + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_nssa(): P-bit off, NO Translation"); + return 0; + } + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_nssa(): TRANSLATING 7 to 5"); + + /* No more P-bit. */ + /* UNSET_FLAG (lsa->data->options, OSPF_OPTION_NP); */ + + /* Area where Aggregate testing will be inserted, just like summary + advertisements */ + /* ospf_abr_check_nssa_range (p_arg, lsa-> cost, lsa -> area); */ + + /* Follow thru here means no aggregation */ + dup = ospf_lsa_dup (lsa); /* keep LSDB intact, lock = 1 */ + + SET_FLAG (dup->flags, OSPF_LSA_LOCAL_XLT); /* Translated from 7 */ + SET_FLAG (dup->flags, OSPF_LSA_APPROVED); /* So, do not remove it */ + + dup->data->type = OSPF_AS_EXTERNAL_LSA; /* make Type-5 */ + + ospf_lsa_checksum (dup->data); + + ospf_lsa_install (NULL, dup); /* Install this Type-5 into LSDB, Lock = 2. */ + + ospf_flood_through_as (NULL, dup); /* flood non-NSSA/STUB areas */ + + /* This translated Type-5 will go to all non-NSSA areas connected to + this ABR; The Type-5 could come from any of the NSSA's connected + to this ABR. */ + + return 0; +} + +void +ospf_abr_translate_nssa_range (struct prefix_ipv4 *p, u_int32_t cost) +{ + /* The Type-7 is created from the aggregated prefix and forwarded + for lsa installation and flooding... to be added... */ +} +#endif /* HAVE_NSSA */ + +void +ospf_abr_announce_network_to_area (struct prefix_ipv4 *p, u_int32_t cost, + struct ospf_area *area) +{ + struct ospf_lsa *lsa, *old = NULL; + struct summary_lsa *sl = NULL; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network_to_area(): Start"); + + old = OSPF_SUMMARY_LSA_SELF_FIND_BY_PREFIX (area, p); + + if (old) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network_to_area(): old summary found"); + sl = (struct summary_lsa *) old->data; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network_to_area(): " + "old metric: %d, new metric: %d", + GET_METRIC (sl->metric), cost); + } + + if (old && (GET_METRIC (sl->metric) == cost)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network_to_area(): " + "old summary approved"); + SET_FLAG (old->flags, OSPF_LSA_APPROVED); + } + else + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network_to_area(): " + "creating new summary"); + if (old) + { + + set_metric (old, cost); + lsa = ospf_summary_lsa_refresh (old); + /* This will flood through area. */ + } + else + { + lsa = ospf_summary_lsa_originate (p, cost, area); + /* This will flood through area. */ + } + + + SET_FLAG (lsa->flags, OSPF_LSA_APPROVED); + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network_to_area(): " + "flooding new version of summary"); + +#ifndef HAVE_NSSA + ospf_flood_through_area (area, NULL, lsa); +#endif /* ! HAVE_NSSA */ + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network_to_area(): Stop"); +} + +int +ospf_abr_nexthops_belong_to_area (struct ospf_route *or, + struct ospf_area *area) +{ + listnode node; + + for (node = listhead (or->path); node; nextnode (node)) + { + struct ospf_path *path = node->data; + struct ospf_interface *oi = path->oi; + + if (oi != NULL) + if (oi->area == area) + return 1; + } + + return 0; +} + +int +ospf_abr_should_accept (struct prefix *p, struct ospf_area *area) +{ + if (IMPORT_NAME (area)) + { + if (IMPORT_LIST (area) == NULL) + IMPORT_LIST (area) = access_list_lookup (AFI_IP, IMPORT_NAME (area)); + + if (IMPORT_LIST (area)) + if (access_list_apply (IMPORT_LIST (area), p) == FILTER_DENY) + return 0; + } + + return 1; +} + +int +ospf_abr_plist_in_check (struct ospf_area *area, struct ospf_route *or, + struct prefix *p) +{ + if (PREFIX_NAME_IN (area)) + { + if (PREFIX_LIST_IN (area) == NULL) + PREFIX_LIST_IN (area) = prefix_list_lookup (AFI_IP, + PREFIX_NAME_IN (area)); + if (PREFIX_LIST_IN (area)) + if (prefix_list_apply (PREFIX_LIST_IN (area), p) != PREFIX_PERMIT) + return 0; + } + return 1; +} + +int +ospf_abr_plist_out_check (struct ospf_area *area, struct ospf_route *or, + struct prefix *p) +{ + if (PREFIX_NAME_OUT (area)) + { + if (PREFIX_LIST_OUT (area) == NULL) + PREFIX_LIST_OUT (area) = prefix_list_lookup (AFI_IP, + PREFIX_NAME_OUT (area)); + if (PREFIX_LIST_OUT (area)) + if (prefix_list_apply (PREFIX_LIST_OUT (area), p) != PREFIX_PERMIT) + return 0; + } + return 1; +} + +void +ospf_abr_announce_network (struct route_node *n, struct ospf_route *or) +{ + listnode node; + struct ospf_area_range *range; + struct prefix_ipv4 *p; + struct ospf_area *area, *or_area; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network(): Start"); + p = (struct prefix_ipv4 *) &n->p; + + or_area = ospf_area_lookup_by_area_id (or->u.std.area_id); + assert (or_area); + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + area = getdata (node); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network(): looking at area %s", + inet_ntoa (area->area_id)); + + if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id)) + continue; + + if (ospf_abr_nexthops_belong_to_area (or, area)) + continue; + + if (!ospf_abr_should_accept (&n->p, area)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network(): " + "prefix %s/%d was denied by import-list", + inet_ntoa (p->prefix), p->prefixlen); + continue; + } + + if (!ospf_abr_plist_in_check (area, or, &n->p)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network(): " + "prefix %s/%d was denied by prefix-list", + inet_ntoa (p->prefix), p->prefixlen); + continue; + } + + if (area->external_routing != OSPF_AREA_DEFAULT && area->no_summary) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network(): " + "area %s is stub and no_summary", + inet_ntoa (area->area_id)); + continue; + } + + if (or->path_type == OSPF_PATH_INTER_AREA) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network(): this is " + "inter-area route to %s/%d", + inet_ntoa (p->prefix), p->prefixlen); + + if (!OSPF_IS_AREA_BACKBONE (area)) + ospf_abr_announce_network_to_area (p, or->cost, area); + } + + if (or->path_type == OSPF_PATH_INTRA_AREA) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network(): " + "this is intra-area route to %s/%d", + inet_ntoa (p->prefix), p->prefixlen); + if ((range = ospf_area_range_match (or_area, p)) && + !ospf_area_is_transit (area)) + ospf_abr_update_aggregate (range, or); + else + ospf_abr_announce_network_to_area (p, or->cost, area); + } + } +} + +int +ospf_abr_should_announce (struct prefix *p, struct ospf_route *or) +{ + struct ospf_area *area = ospf_area_lookup_by_area_id (or->u.std.area_id); + + assert (area); + + if (EXPORT_NAME (area)) + { + if (EXPORT_LIST (area) == NULL) + EXPORT_LIST (area) = access_list_lookup (AFI_IP, EXPORT_NAME (area)); + + if (EXPORT_LIST (area)) + if (access_list_apply (EXPORT_LIST (area), p) == FILTER_DENY) + return 0; + } + + return 1; +} + +#ifdef HAVE_NSSA +void +ospf_abr_process_nssa_translates () +{ + /* Scan through all NSSA_LSDB records for all areas; + + If P-bit is on, translate all Type-7's to 5's and aggregate or + flood install as approved in Type-5 LSDB with XLATE Flag on + later, do same for all aggregates... At end, DISCARD all + remaining UNAPPROVED Type-5's (Aggregate is for future ) */ + listnode node; + struct ospf_area *area; + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_process_nssa_translates(): Start"); + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + area = getdata (node); + + if (! area->NSSATranslator) + continue; /* skip if not translator */ + + if (area->external_routing != OSPF_AREA_NSSA) + continue; /* skip if not Nssa Area */ + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_process_nssa_translates(): " + "looking at area %s", inet_ntoa (area->area_id)); + + foreach_lsa (NSSA_LSDB (area), area, 0, ospf_abr_translate_nssa); + } + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_process_nssa_translates(): Stop"); + +} +#endif /* HAVE_NSSA */ + +void +ospf_abr_process_network_rt (struct route_table *rt) +{ + struct route_node *rn; + struct ospf_route *or; + struct ospf_area *area; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt(): Start"); + + for (rn = route_top (rt); rn; rn = route_next (rn)) + { + if ((or = rn->info) == NULL) + continue; + + if (!(area = ospf_area_lookup_by_area_id (or->u.std.area_id))) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt(): area %s no longer exists", + inet_ntoa (or->u.std.area_id)); + continue; + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt(): this is a route to %s/%d", + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); + if (or->path_type >= OSPF_PATH_TYPE1_EXTERNAL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt(): " + "this is an External router, skipping"); + continue; + } + + if (or->cost >= OSPF_LS_INFINITY) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt():" + " this route's cost is infinity, skipping"); + continue; + } + + if (or->type == OSPF_DESTINATION_DISCARD) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt():" + " this is a discard entry, skipping"); + continue; + } + + if (or->path_type == OSPF_PATH_INTRA_AREA && + !ospf_abr_should_announce (&rn->p, or)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info("ospf_abr_process_network_rt(): denied by export-list"); + continue; + } + + if (or->path_type == OSPF_PATH_INTRA_AREA && + !ospf_abr_plist_out_check (area, or, &rn->p)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info("ospf_abr_process_network_rt(): denied by prefix-list"); + continue; + } + + if ((or->path_type == OSPF_PATH_INTER_AREA) && + !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt():" + " this is route is not backbone one, skipping"); + continue; + } + + + if ((ospf_top->abr_type == OSPF_ABR_CISCO) || + (ospf_top->abr_type == OSPF_ABR_IBM)) + + if (!ospf_act_bb_connection () && + or->path_type != OSPF_PATH_INTRA_AREA) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt(): ALT ABR: " + "No BB connection, skip not intra-area routes"); + continue; + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt(): announcing"); + ospf_abr_announce_network (rn, or); + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt(): Stop"); +} + +void +ospf_abr_announce_rtr_to_area (struct prefix_ipv4 *p, u_int32_t cost, + struct ospf_area *area) +{ + struct ospf_lsa *lsa, *old = NULL; + struct summary_lsa *slsa = NULL; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr_to_area(): Start"); + + old = OSPF_SUMMARY_ASBR_LSA_SELF_FIND_BY_PREFIX (area, p); + /* old = ospf_find_self_summary_asbr_lsa_by_prefix (area, p); */ + + if (old) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr_to_area(): old summary found"); + slsa = (struct summary_lsa *) old->data; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network_to_area(): " + "old metric: %d, new metric: %d", + GET_METRIC (slsa->metric), cost); + } + + if (old && (GET_METRIC (slsa->metric) == cost)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr_to_area(): old summary approved"); + SET_FLAG (old->flags, OSPF_LSA_APPROVED); + } + else + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr_to_area(): 2.2"); + + if (old) + { + set_metric (old, cost); + lsa = ospf_summary_asbr_lsa_refresh (old); + } + else + lsa = ospf_summary_asbr_lsa_originate (p, cost, area); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr_to_area(): " + "flooding new version of summary"); + /* + zlog_info ("ospf_abr_announce_rtr_to_area(): creating new summary"); + lsa = ospf_summary_asbr_lsa (p, cost, area, old); */ + + SET_FLAG (lsa->flags, OSPF_LSA_APPROVED); + /* ospf_flood_through_area (area, NULL, lsa);*/ + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr_to_area(): Stop"); +} + + +void +ospf_abr_announce_rtr (struct prefix_ipv4 *p, struct ospf_route *or) +{ + listnode node; + struct ospf_area *area; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr(): Start"); + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + area = getdata (node); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr(): looking at area %s", + inet_ntoa (area->area_id)); + + if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id)) + continue; + + if (ospf_abr_nexthops_belong_to_area (or, area)) + continue; + + if (area->external_routing != OSPF_AREA_DEFAULT) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network(): " + "area %s doesn't support external routing", + inet_ntoa(area->area_id)); + continue; + } + + if (or->path_type == OSPF_PATH_INTER_AREA) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr(): " + "this is inter-area route to %s", inet_ntoa (p->prefix)); + if (!OSPF_IS_AREA_BACKBONE (area)) + ospf_abr_announce_rtr_to_area (p, or->cost, area); + } + + if (or->path_type == OSPF_PATH_INTRA_AREA) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr(): " + "this is intra-area route to %s", inet_ntoa (p->prefix)); + ospf_abr_announce_rtr_to_area (p, or->cost, area); + } + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr(): Stop"); +} + +void +ospf_abr_process_router_rt (struct route_table *rt) +{ + struct route_node *rn; + struct ospf_route *or; + struct list *l; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_router_rt(): Start"); + + for (rn = route_top (rt); rn; rn = route_next (rn)) + { + listnode node; + char flag = 0; + struct ospf_route *best = NULL; + + if (rn->info == NULL) + continue; + + l = rn->info; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_router_rt(): this is a route to %s", + inet_ntoa (rn->p.u.prefix4)); + + for (node = listhead (l); node; nextnode (node)) + { + or = getdata (node); + if (or == NULL) + continue; + + if (!ospf_area_lookup_by_area_id (or->u.std.area_id)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_router_rt(): area %s no longer exists", + inet_ntoa (or->u.std.area_id)); + continue; + } + + + if (!CHECK_FLAG (or->u.std.flags, ROUTER_LSA_EXTERNAL)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_router_rt(): " + "This is not an ASBR, skipping"); + continue; + } + + if (!flag) + { + best = ospf_find_asbr_route (rt, (struct prefix_ipv4 *) &rn->p); + flag = 1; + } + + if (best == NULL) + continue; + + if (or != best) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_router_rt(): " + "This route is not the best among possible, skipping"); + continue; + } + + if (or->path_type == OSPF_PATH_INTER_AREA && + !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_router_rt(): " + "This route is not a backbone one, skipping"); + continue; + } + + if (or->cost >= OSPF_LS_INFINITY) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_router_rt(): " + "This route has LS_INFINITY metric, skipping"); + continue; + } + + if (ospf_top->abr_type == OSPF_ABR_CISCO || + ospf_top->abr_type == OSPF_ABR_IBM) + if (!ospf_act_bb_connection () && + or->path_type != OSPF_PATH_INTRA_AREA) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info("ospf_abr_process_network_rt(): ALT ABR: " + "No BB connection, skip not intra-area routes"); + continue; + } + + ospf_abr_announce_rtr ((struct prefix_ipv4 *) &rn->p, or); + + } + + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_router_rt(): Stop"); +} + +#ifdef HAVE_NSSA +int +ospf_abr_unapprove_translates_apply (struct ospf_lsa *lsa, void *p_arg, + int int_arg) +{ + /* Could be a mix of Normal Type-5's, self-originated, or Type-7s + that are Locally ABR Translated */ + + if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) + UNSET_FLAG (lsa->flags, OSPF_LSA_APPROVED); + + return 0; +} + +void +ospf_abr_unapprove_translates () /* For NSSA Translations */ +{ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_unapprove_translates(): Start"); + + /* NSSA Translator is not checked, because it may have gone away, + and we would want to flush any residuals anyway */ + + foreach_lsa (EXTERNAL_LSDB (ospf_top), NULL, 0, + ospf_abr_unapprove_translates_apply); + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_unapprove_translates(): Stop"); +} +#endif /* HAVE_NSSA */ + +int +ospf_abr_unapprove_summaries_apply (struct ospf_lsa *lsa, void *p_arg, + int int_arg) +{ + if (ospf_lsa_is_self_originated (lsa)) + UNSET_FLAG (lsa->flags, OSPF_LSA_APPROVED); + + return 0; +} + +void +ospf_abr_unapprove_summaries () +{ + listnode node; + struct ospf_area *area; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_unapprove_summaries(): Start"); + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + area = getdata (node); + foreach_lsa (SUMMARY_LSDB (area), NULL, 0, + ospf_abr_unapprove_summaries_apply); + foreach_lsa (ASBR_SUMMARY_LSDB (area), NULL, 0, + ospf_abr_unapprove_summaries_apply); + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_unapprove_summaries(): Stop"); +} + +void +ospf_abr_prepare_aggregates () +{ + listnode node; + struct route_node *rn; + struct ospf_area_range *range; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_prepare_aggregates(): Start"); + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + struct ospf_area *area = getdata (node); + + for (rn = route_top (area->ranges); rn; rn = route_next (rn)) + if ((range = rn->info) != NULL) + { + range->cost = 0; + range->specifics = 0; + } + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_prepare_aggregates(): Stop"); +} + +void +ospf_abr_announce_aggregates () +{ + struct ospf_area *area, *ar; + struct ospf_area_range *range; + struct route_node *rn; + struct prefix_ipv4 p; + listnode node, n; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_aggregates(): Start"); + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + area = getdata (node); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_aggregates(): looking at area %s", + inet_ntoa (area->area_id)); + + for (rn = route_top (area->ranges); rn; rn = route_next (rn)) + if ((range = rn->info)) + { + if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_aggregates():" + " discarding suppress-ranges"); + continue; + } + + p.family = AF_INET; + p.prefix = range->addr; + p.prefixlen = range->masklen; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_aggregates():" + " this is range: %s/%d", + inet_ntoa (p.prefix), p.prefixlen); + + if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) + { + p.family = AF_INET; + p.prefix = range->subst_addr; + p.prefixlen = range->subst_masklen; + } + + if (range->specifics) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_aggregates(): active range"); + + for (n = listhead (ospf_top->areas); n; nextnode (n)) + { + ar = getdata (n); + if (ar == area) + continue; + + /* We do not check nexthops here, because + intra-area routes can be associated with + one area only */ + + /* backbone routes are not summarized + when announced into transit areas */ + + if (ospf_area_is_transit (ar) && + OSPF_IS_AREA_BACKBONE (area)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_aggregates(): Skipping " + "announcement of BB aggregate into" + " a transit area"); + continue; + } + ospf_abr_announce_network_to_area (&p, range->cost, ar); + } + } + } + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_aggregates(): Stop"); +} + +#ifdef HAVE_NSSA +void +ospf_abr_send_nssa_aggregates () /* temporarily turned off */ +{ + listnode node; /*, n; */ + struct ospf_area *area; /*, *ar; */ + struct route_node *rn; + struct ospf_area_range *range; + struct prefix_ipv4 p; + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_send_nssa_aggregates(): Start"); + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + area = getdata (node); + + if (! area->NSSATranslator) + continue; + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_send_nssa_aggregates(): looking at area %s", + inet_ntoa (area->area_id)); + + for (rn = route_top (area->ranges); rn; rn = route_next (rn)) + { + if (rn->info == NULL) + continue; + + range = rn->info; + + if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE)) + { + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_send_nssa_aggregates():" + " discarding suppress-ranges"); + continue; + } + + p.family = AF_INET; + p.prefix = range->addr; + p.prefixlen = range->masklen; + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_send_nssa_aggregates():" + " this is range: %s/%d", + inet_ntoa (p.prefix), p.prefixlen); + + if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) + { + p.family = AF_INET; + p.prefix = range->subst_addr; + p.prefixlen = range->subst_masklen; + } + + if (range->specifics) + { + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_send_nssa_aggregates(): active range"); + + /* Fetch LSA-Type-7 from aggregate prefix, and then + translate, Install (as Type-5), Approve, and Flood */ + ospf_abr_translate_nssa_range (&p, range->cost); + } /* if (range->specifics)*/ + } /* all area ranges*/ + } /* all areas */ + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_send_nssa_aggregates(): Stop"); +} + +void +ospf_abr_announce_nssa_defaults () /* By ABR-Translator */ +{ + listnode node; + struct ospf_area *area; + struct prefix_ipv4 p; + + if (! OSPF_IS_ABR) + return; + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_announce_stub_defaults(): Start"); + + p.family = AF_INET; + p.prefix.s_addr = OSPF_DEFAULT_DESTINATION; + p.prefixlen = 0; + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + area = getdata (node); + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_announce_nssa_defaults(): looking at area %s", + inet_ntoa (area->area_id)); + + if (area->external_routing != OSPF_AREA_NSSA) + continue; + + if (OSPF_IS_AREA_BACKBONE (area)) + continue; /* Sanity Check */ + + /* if (!TranslatorRole continue V 1.0 look for "always" conf */ + if (area->NSSATranslator) + { + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_announce_nssa_defaults(): " + "announcing 0.0.0.0/0 to this nssa"); + /* ospf_abr_announce_nssa_asbr_to_as (&p, area->default_cost, area); */ + } + } +} +#endif /* HAVE_NSSA */ + +void +ospf_abr_announce_stub_defaults () +{ + listnode node; + struct ospf_area *area; + struct prefix_ipv4 p; + + if (! OSPF_IS_ABR) + return; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_stub_defaults(): Start"); + + p.family = AF_INET; + p.prefix.s_addr = OSPF_DEFAULT_DESTINATION; + p.prefixlen = 0; + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + area = getdata (node); + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_stub_defaults(): looking at area %s", + inet_ntoa (area->area_id)); + +#ifdef HAVE_NSSA + if (area->external_routing != OSPF_AREA_STUB) +#else /* ! HAVE_NSSA */ + if (area->external_routing == OSPF_AREA_DEFAULT) +#endif /* HAVE_NSSA */ + continue; + + if (OSPF_IS_AREA_BACKBONE (area)) + continue; /* Sanity Check */ + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_stub_defaults(): " + "announcing 0.0.0.0/0 to this area"); + ospf_abr_announce_network_to_area (&p, area->default_cost, area); + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_stub_defaults(): Stop"); +} + +#ifdef HAVE_NSSA +int +ospf_abr_remove_unapproved_translates_apply (struct ospf_lsa *lsa, void *p_arg, + int int_arg) +{ + if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT) + && ! CHECK_FLAG (lsa->flags, OSPF_LSA_APPROVED)) + { + zlog_info ("ospf_abr_remove_unapproved_translates(): " + "removing unapproved translates, ID: %s", + inet_ntoa (lsa->data->id)); + + /* FLUSH THROUGHOUT AS */ + ospf_lsa_flush_as (lsa); + + /* DISCARD from LSDB */ + } + return 0; +} + +void +ospf_abr_remove_unapproved_translates () /* For NSSA Translations */ +{ + /* All AREA PROCESS should have APPROVED necessary LSAs */ + /* Remove any left over and not APPROVED */ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_remove_unapproved_translates(): Start"); + + foreach_lsa (EXTERNAL_LSDB (ospf_top), NULL, 0, + ospf_abr_remove_unapproved_translates_apply); + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_remove_unapproved_translates(): Stop"); +} +#endif /* HAVE_NSSA */ + +int +ospf_abr_remove_unapproved_summaries_apply (struct ospf_lsa *lsa, void *p_arg, + int int_arg) +{ + struct ospf_area *area; + + area = (struct ospf_area *) p_arg; + + if (ospf_lsa_is_self_originated (lsa) && + !CHECK_FLAG (lsa->flags, OSPF_LSA_APPROVED)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_remove_unapproved_summaries(): " + "removing unapproved summary, ID: %s", + inet_ntoa (lsa->data->id)); + ospf_lsa_flush_area (lsa, area); + } + return 0; +} + +void +ospf_abr_remove_unapproved_summaries () +{ + listnode node; + struct ospf_area *area; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_remove_unapproved_summaries(): Start"); + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + area = getdata (node); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_remove_unapproved_summaries(): " + "looking at area %s", inet_ntoa (area->area_id)); + + foreach_lsa (SUMMARY_LSDB (area), area, 0, + ospf_abr_remove_unapproved_summaries_apply); + foreach_lsa (ASBR_SUMMARY_LSDB (area), area, 0, + ospf_abr_remove_unapproved_summaries_apply); + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_remove_unapproved_summaries(): Stop"); +} + +void +ospf_abr_manage_discard_routes () +{ + listnode node; + struct route_node *rn; + struct ospf_area *area; + struct ospf_area_range *range; + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + if ((area = node->data) != NULL) + for (rn = route_top (area->ranges); rn; rn = route_next (rn)) + if ((range = rn->info) != NULL) + if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE)) + { + if (range->specifics) + ospf_add_discard_route (ospf_top->new_table, area, + (struct prefix_ipv4 *) &rn->p); + else + ospf_delete_discard_route ((struct prefix_ipv4 *) &rn->p); + } +} + +#ifdef HAVE_NSSA +/* This is the function taking care about ABR NSSA, i.e. NSSA + Translator, -LSA aggregation and flooding. For all NSSAs + + Any SELF-AS-LSA is in the Type-5 LSDB and Type-7 LSDB. These LSA's + are refreshed from the Type-5 LSDB, installed into the Type-7 LSDB + with the P-bit set. + + Any received Type-5s are legal for an ABR, else illegal for IR. + Received Type-7s are installed, by area, with incoming P-bit. They + are flooded; if the Elected NSSA Translator, then P-bit off. + + Additionally, this ABR will place "translated type-7's" into the + Type-5 LSDB in order to keep track of APPROVAL or not. + + It will scan through every area, looking for Type-7 LSAs with P-Bit + SET. The Type-7's are either AS-FLOODED & 5-INSTALLED or + AGGREGATED. Later, the AGGREGATED LSAs are AS-FLOODED & + 5-INSTALLED. + + 5-INSTALLED is into the Type-5 LSDB; Any UNAPPROVED Type-5 LSAs + left over are FLUSHED and DISCARDED. + + For External Calculations, any NSSA areas use the Type-7 AREA-LSDB, + any ABR-non-NSSA areas use the Type-5 GLOBAL-LSDB. */ + +void +ospf_abr_nssa_task () /* called only if any_nssa */ +{ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("Check for NSSA-ABR Tasks():"); + + if (! OSPF_IS_ABR) + return; + + if (! ospf_top->anyNSSA) + return; + + /* Each area must confirm TranslatorRole */ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_nssa_task(): Start"); + + /* For all Global Entries flagged "local-translate", unset APPROVED */ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_nssa_task(): unapprove translates"); + + ospf_abr_unapprove_translates (); + + /* RESET all Ranges in every Area, same as summaries */ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_nssa_task(): NSSA initialize aggregates"); + + /* ospf_abr_prepare_aggregates (); TURNED OFF just for now */ + + /* For all NSSAs, Type-7s, translate to 5's, INSTALL/FLOOD, or + Aggregate as Type-7 */ + /* Install or Approve in Type-5 Global LSDB */ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_nssa_task(): process translates"); + + ospf_abr_process_nssa_translates (ospf_top->new_table); + + /* Translate/Send any "ranged" aggregates, and also 5-Install and + Approve */ + /* Scan Type-7's for aggregates, translate to Type-5's, + Install/Flood/Approve */ + if (IS_DEBUG_OSPF_NSSA) + zlog_info("ospf_abr_nssa_task(): send NSSA aggregates"); + /* ospf_abr_send_nssa_aggregates (); TURNED OFF FOR NOW */ + + /* Send any NSSA defaults as Type-5 */ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_nssa_task(): announce nssa defaults"); + ospf_abr_announce_nssa_defaults (); + + /* Flush any unapproved previous translates from Global Data Base */ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_nssa_task(): remove unapproved translates"); + ospf_abr_remove_unapproved_translates (); + + ospf_abr_manage_discard_routes (); /* same as normal...discard */ + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_nssa_task(): Stop"); +} +#endif /* HAVE_NSSA */ + +/* This is the function taking care about ABR stuff, i.e. + summary-LSA origination and flooding. */ +void +ospf_abr_task () +{ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): Start"); + + if (ospf_top->new_table == NULL || ospf_top->new_rtrs == NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): Routing tables are not yet ready"); + return; + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): unapprove summaries"); + ospf_abr_unapprove_summaries (); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): prepare aggregates"); + ospf_abr_prepare_aggregates (); + + if (OSPF_IS_ABR) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): process network RT"); + ospf_abr_process_network_rt (ospf_top->new_table); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): process router RT"); + ospf_abr_process_router_rt (ospf_top->new_rtrs); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): announce aggregates"); + ospf_abr_announce_aggregates (); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): announce stub defaults"); + ospf_abr_announce_stub_defaults (); + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): remove unapproved summaries"); + ospf_abr_remove_unapproved_summaries (); + + ospf_abr_manage_discard_routes (); + +#ifdef HAVE_NSSA + ospf_abr_nssa_task(); /* if nssa-abr, then scan Type-7 LSDB */ +#endif /* HAVE_NSSA */ + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): Stop"); +} + + +int +ospf_abr_task_timer (struct thread *t) +{ + ospf_top->t_abr_task = 0; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Running ABR task on timer"); + + ospf_check_abr_status (); + + ospf_abr_task (); + + return 0; +} + +void +ospf_schedule_abr_task () +{ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Scheduling ABR task"); + if (! ospf_top->t_abr_task) + ospf_top->t_abr_task = thread_add_timer (master, ospf_abr_task_timer, + 0, OSPF_ABR_TASK_DELAY); +} diff --git a/ospfd/ospf_abr.h b/ospfd/ospf_abr.h new file mode 100644 index 00000000..3b385c32 --- /dev/null +++ b/ospfd/ospf_abr.h @@ -0,0 +1,84 @@ +/* + * OSPF ABR functions. + * Copyright (C) 1999 Alex Zinin + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_ABR_H +#define _ZEBRA_OSPF_ABR_H + +#define OSPF_ABR_TASK_DELAY 7 + +#define OSPF_AREA_RANGE_ADVERTISE (1 << 0) +#define OSPF_AREA_RANGE_SUBSTITUTE (1 << 1) + +/* Area range. */ +struct ospf_area_range +{ + /* Area range address. */ + struct in_addr addr; + + /* Area range masklen. */ + u_char masklen; + + /* Flags. */ + u_char flags; + + /* Number of more specific prefixes. */ + int specifics; + + /* Addr and masklen to substitute. */ + struct in_addr subst_addr; + u_char subst_masklen; + + /* Range cost. */ + u_int32_t cost; + + /* Configured range cost. */ + u_int32_t cost_config; +#define OSPF_AREA_RANGE_COST_UNSPEC -1 +}; + +/* Prototypes. */ +struct ospf_area_range *ospf_area_range_lookup (struct ospf_area *, + struct prefix_ipv4 *); +struct ospf_area_range *ospf_some_area_range_match (struct prefix_ipv4 *); +struct ospf_area_range *ospf_area_range_lookup_next (struct ospf_area *, + struct in_addr *, int); +int ospf_area_range_set (struct ospf *, struct in_addr, struct prefix_ipv4 *, + int); +int ospf_area_range_cost_set (struct ospf *, struct in_addr, + struct prefix_ipv4 *, u_int32_t); +int ospf_area_range_unset (struct ospf *, struct in_addr, + struct prefix_ipv4 *); +int ospf_area_range_substitute_set (struct ospf *, struct in_addr, + struct prefix_ipv4 *, + struct prefix_ipv4 *); +int ospf_area_range_substitute_unset (struct ospf *, struct in_addr, + struct prefix_ipv4 *); +struct ospf_area_range *ospf_area_range_match_any (struct ospf *, + struct prefix_ipv4 *); +int ospf_area_range_active (struct ospf_area_range *); +int ospf_act_bb_connection (); + +void ospf_check_abr_status (); +void ospf_abr_task (); +void ospf_schedule_abr_task (); + +#endif /* _ZEBRA_OSPF_ABR_H */ diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c new file mode 100644 index 00000000..d13bbc43 --- /dev/null +++ b/ospfd/ospf_asbr.c @@ -0,0 +1,287 @@ +/* + * OSPF AS Boundary Router functions. + * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "thread.h" +#include "memory.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "vty.h" +#include "filter.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_dump.h" + +/* Remove external route. */ +void +ospf_external_route_remove (struct prefix_ipv4 *p) +{ + struct route_node *rn; + struct ospf_route *or; + + rn = route_node_lookup (ospf_top->old_external_route, (struct prefix *) p); + if (rn) + if ((or = rn->info)) + { + zlog_info ("Route[%s/%d]: external path deleted", + inet_ntoa (p->prefix), p->prefixlen); + + /* Remove route from zebra. */ + if (or->type == OSPF_DESTINATION_NETWORK) + ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or); + + ospf_route_free (or); + rn->info = NULL; + + route_unlock_node (rn); + route_unlock_node (rn); + return; + } + + zlog_info ("Route[%s/%d]: no such external path", + inet_ntoa (p->prefix), p->prefixlen); +} + +/* Lookup external route. */ +struct ospf_route * +ospf_external_route_lookup (struct prefix_ipv4 *p) +{ + struct route_node *rn; + + rn = route_node_lookup (ospf_top->old_external_route, (struct prefix *) p); + if (rn) + { + route_unlock_node (rn); + if (rn->info) + return rn->info; + } + + zlog_warn ("Route[%s/%d]: lookup, no such prefix", + inet_ntoa (p->prefix), p->prefixlen); + + return NULL; +} + + +/* Add an External info for AS-external-LSA. */ +struct external_info * +ospf_external_info_new (u_char type) +{ + struct external_info *new; + + new = (struct external_info *) + XMALLOC (MTYPE_OSPF_EXTERNAL_INFO, sizeof (struct external_info)); + memset (new, 0, sizeof (struct external_info)); + new->type = type; + + ospf_reset_route_map_set_values (&new->route_map_set); + return new; +} + +void +ospf_external_info_free (struct external_info *ei) +{ + XFREE (MTYPE_OSPF_EXTERNAL_INFO, ei); +} + +void +ospf_reset_route_map_set_values (struct route_map_set_values *values) +{ + values->metric = -1; + values->metric_type = -1; +} + +int +ospf_route_map_set_compare (struct route_map_set_values *values1, + struct route_map_set_values *values2) +{ + return values1->metric == values2->metric && + values1->metric_type == values2->metric_type; +} + +/* Add an External info for AS-external-LSA. */ +struct external_info * +ospf_external_info_add (u_char type, struct prefix_ipv4 p, + unsigned int ifindex, struct in_addr nexthop) +{ + struct external_info *new; + struct route_node *rn; + + /* Initialize route table. */ + if (EXTERNAL_INFO (type) == NULL) + EXTERNAL_INFO (type) = route_table_init (); + + rn = route_node_get (EXTERNAL_INFO (type), (struct prefix *) &p); + /* If old info exists, -- discard new one or overwrite with new one? */ + if (rn) + if (rn->info) + { + route_unlock_node (rn); + zlog_warn ("Redistribute[%s]: %s/%d already exists, discard.", + LOOKUP (ospf_redistributed_proto, type), + inet_ntoa (p.prefix), p.prefixlen); + /* XFREE (MTYPE_OSPF_TMP, rn->info); */ + return rn->info; + } + + /* Create new External info instance. */ + new = ospf_external_info_new (type); + new->p = p; + new->ifindex = ifindex; + new->nexthop = nexthop; + new->tag = 0; + + rn->info = new; + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("Redistribute[%s]: %s/%d external info created.", + LOOKUP (ospf_redistributed_proto, type), + inet_ntoa (p.prefix), p.prefixlen); + return new; +} + +void +ospf_external_info_delete (u_char type, struct prefix_ipv4 p) +{ + struct route_node *rn; + + rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) &p); + if (rn) + { + ospf_external_info_free (rn->info); + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + } +} + +struct external_info * +ospf_external_info_lookup (u_char type, struct prefix_ipv4 *p) +{ + struct route_node *rn; + rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) p); + if (rn) + { + route_unlock_node (rn); + if (rn->info) + return rn->info; + } + + return NULL; +} + +struct ospf_lsa * +ospf_external_info_find_lsa (struct prefix_ipv4 *p) +{ + struct ospf_lsa *lsa; + struct as_external_lsa *al; + struct in_addr mask, id; + + lsa = ospf_lsdb_lookup_by_id (ospf_top->lsdb, OSPF_AS_EXTERNAL_LSA, + p->prefix, ospf_top->router_id); + + if (!lsa) + return NULL; + + al = (struct as_external_lsa *) lsa->data; + + masklen2ip (p->prefixlen, &mask); + + if (mask.s_addr != al->mask.s_addr) + { + id.s_addr = p->prefix.s_addr | (~mask.s_addr); + lsa = ospf_lsdb_lookup_by_id (ospf_top->lsdb, OSPF_AS_EXTERNAL_LSA, + id, ospf_top->router_id); + if (!lsa) + return NULL; + } + + return lsa; +} + + +/* Update ASBR status. */ +void +ospf_asbr_status_update (u_char status) +{ + zlog_info ("ASBR[Status:%d]: Update", status); + + /* ASBR on. */ + if (status) + { + /* Already ASBR. */ + if (OSPF_IS_ASBR) + { + zlog_info ("ASBR[Status:%d]: Already ASBR", status); + return; + } + SET_FLAG (ospf_top->flags, OSPF_FLAG_ASBR); + } + else + { + /* Already non ASBR. */ + if (! OSPF_IS_ASBR) + { + zlog_info ("ASBR[Status:%d]: Already non ASBR", status); + return; + } + UNSET_FLAG (ospf_top->flags, OSPF_FLAG_ASBR); + } + + /* Transition from/to status ASBR, schedule timer. */ + ospf_spf_calculate_schedule (); + OSPF_TIMER_ON (ospf_top->t_router_lsa_update, + ospf_router_lsa_update_timer, OSPF_LSA_UPDATE_DELAY); +} + +void +ospf_redistribute_withdraw (u_char type) +{ + struct route_node *rn; + struct external_info *ei; + + /* Delete external info for specified type. */ + if (EXTERNAL_INFO (type)) + for (rn = route_top (EXTERNAL_INFO (type)); rn; rn = route_next (rn)) + if ((ei = rn->info)) + if (ospf_external_info_find_lsa (&ei->p)) + { + if (is_prefix_default (&ei->p) && + ospf_top->default_originate != DEFAULT_ORIGINATE_NONE) + continue; + ospf_external_lsa_flush (type, &ei->p, ei->ifindex, ei->nexthop); + ospf_external_info_delete (type, ei->p); + } +} diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h new file mode 100644 index 00000000..f368246d --- /dev/null +++ b/ospfd/ospf_asbr.h @@ -0,0 +1,75 @@ +/* + * OSPF AS Boundary Router functions. + * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_ASBR_H +#define _ZEBRA_OSPF_ASBR_H + +struct route_map_set_values +{ + int32_t metric; + int32_t metric_type; +}; + +/* Redistributed external information. */ +struct external_info +{ + /* Type of source protocol. */ + u_char type; + + /* Prefix. */ + struct prefix_ipv4 p; + + /* Interface index. */ + unsigned int ifindex; + + /* Nexthop address. */ + struct in_addr nexthop; + + /* Additional Route tag. */ + u_int32_t tag; + + struct route_map_set_values route_map_set; +#define ROUTEMAP_METRIC(E) (E)->route_map_set.metric +#define ROUTEMAP_METRIC_TYPE(E) (E)->route_map_set.metric_type +}; + +#define OSPF_ASBR_CHECK_DELAY 30 + +void ospf_external_route_remove (struct prefix_ipv4 *p); +struct external_info *ospf_external_info_new (u_char); +void ospf_reset_route_map_set_values (struct route_map_set_values *values); +int ospf_route_map_set_compare (struct route_map_set_values *values1, + struct route_map_set_values *values2); +struct external_info *ospf_external_info_add (u_char, struct prefix_ipv4, + unsigned int, struct in_addr); +void ospf_external_info_delete (u_char, struct prefix_ipv4); +struct external_info *ospf_external_info_lookup (u_char, struct prefix_ipv4 *); + +void ospf_asbr_status_update (u_char); + +void ospf_redistribute_withdraw (u_char); +void ospf_asbr_check (); +void ospf_schedule_asbr_check (); +void ospf_asbr_route_install_lsa (struct ospf_lsa *); +struct ospf_lsa *ospf_external_info_find_lsa (struct prefix_ipv4 *p); + +#endif /* _ZEBRA_OSPF_ASBR_H */ diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c new file mode 100644 index 00000000..9194c566 --- /dev/null +++ b/ospfd/ospf_ase.c @@ -0,0 +1,838 @@ +/* + * OSPF AS external route calculation. + * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "thread.h" +#include "memory.h" +#include "hash.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "vty.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_dump.h" + +#define DEBUG + +struct ospf_route * +ospf_find_asbr_route (struct route_table *rtrs, struct prefix_ipv4 *asbr) +{ + struct route_node *rn; + struct ospf_route *or, *best = NULL; + listnode node; + list chosen; + + /* Sanity check. */ + if (rtrs == NULL) + return NULL; + + rn = route_node_lookup (rtrs, (struct prefix *) asbr); + if (! rn) + return NULL; + + route_unlock_node (rn); + + chosen = list_new (); + + /* First try to find intra-area non-bb paths. */ + if (!CHECK_FLAG (ospf_top->config, OSPF_RFC1583_COMPATIBLE)) + for (node = listhead ((list) rn->info); node; nextnode (node)) + if ((or = getdata (node)) != NULL) + if (or->cost < OSPF_LS_INFINITY) + if (!OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id) && + or->path_type == OSPF_PATH_INTRA_AREA) + listnode_add (chosen, or); + + /* If none is found -- look through all. */ + if (listcount (chosen) == 0) + { + list_free (chosen); + chosen = rn->info; + } + + /* Now find the route with least cost. */ + for (node = listhead (chosen); node; nextnode (node)) + if ((or = getdata (node)) != NULL) + if (or->cost < OSPF_LS_INFINITY) + { + if (best == NULL) + best = or; + else if (best->cost > or->cost) + best = or; + else if (best->cost == or->cost && + IPV4_ADDR_CMP (&best->u.std.area_id, + &or->u.std.area_id) < 0) + best = or; + } + + if (chosen != rn->info) + list_delete (chosen); + + return best; +} + +struct ospf_route * +ospf_find_asbr_route_through_area (struct route_table *rtrs, + struct prefix_ipv4 *asbr, + struct ospf_area *area) +{ + struct route_node *rn; + + /* Sanity check. */ + if (rtrs == NULL) + return NULL; + + rn = route_node_lookup (rtrs, (struct prefix *) asbr); + + if (rn) + { + listnode node; + struct ospf_route *or; + + route_unlock_node (rn); + + for (node = listhead ((list) rn->info); node; nextnode (node)) + if ((or = getdata (node)) != NULL) + if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id)) + return or; + } + + return NULL; +} + +void +ospf_ase_complete_direct_routes (struct ospf_route *ro, struct in_addr nexthop) +{ + listnode node; + struct ospf_path *op; + + for (node = listhead (ro->path); node; nextnode (node)) + if ((op = getdata (node)) != NULL) + if (op->nexthop.s_addr == 0) + op->nexthop.s_addr = nexthop.s_addr; +} + +int +ospf_ase_forward_address_check (struct in_addr fwd_addr) +{ + listnode ifn; + struct ospf_interface *oi; + + for (ifn = listhead (ospf_top->oiflist); ifn; nextnode (ifn)) + if ((oi = getdata (ifn)) != NULL) + if (if_is_up (oi->ifp)) + if (oi->type != OSPF_IFTYPE_VIRTUALLINK) + if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &fwd_addr)) + return 0; + + return 1; +} + +/* Calculate ASBR route. */ +struct ospf_route * +ospf_ase_calculate_asbr_route (struct route_table *rt_network, + struct route_table *rt_router, + struct as_external_lsa *al) +{ + struct prefix_ipv4 asbr; + struct ospf_route *asbr_route; + struct route_node *rn; + + /* Find ASBR route from Router routing table. */ + asbr.family = AF_INET; + asbr.prefix = al->header.adv_router; + asbr.prefixlen = IPV4_MAX_BITLEN; + apply_mask_ipv4 (&asbr); + + asbr_route = ospf_find_asbr_route (rt_router, &asbr); + + if (asbr_route == NULL) + { + zlog_info ("ospf_ase_calculate(): Route to ASBR %s not found", + inet_ntoa (asbr.prefix)); + return NULL; + } + + if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL)) + { + zlog_info ("ospf_ase_calculate(): Originating router is not an ASBR"); + return NULL; + } + + if (al->e[0].fwd_addr.s_addr != 0) + { + zlog_info ("ospf_ase_calculate(): " + "Forwarding address is not 0.0.0.0."); + + if (! ospf_ase_forward_address_check (al->e[0].fwd_addr)) + { + zlog_info ("ospf_ase_calculate(): " + "Forwarding address is one of our addresses, Ignore."); + return NULL; + } + + zlog_info ("ospf_ase_calculate(): " + "Looking up in the Network Routing Table."); + + /* Looking up the path to the fwd_addr from Network route. */ + asbr.family = AF_INET; + asbr.prefix = al->e[0].fwd_addr; + asbr.prefixlen = IPV4_MAX_BITLEN; + + rn = route_node_match (rt_network, (struct prefix *) &asbr); + + if (rn == NULL) + { + zlog_info ("ospf_ase_calculate(): " + "Couldn't find a route to the forwarding address."); + return NULL; + } + + route_unlock_node (rn); + + if ((asbr_route = rn->info) == NULL) + { + zlog_info ("ospf_ase_calculate(): " + "Somehow OSPF route to ASBR is lost"); + return NULL; + } + } + + return asbr_route; +} + +struct ospf_route * +ospf_ase_calculate_new_route (struct ospf_lsa *lsa, + struct ospf_route *asbr_route, u_int32_t metric) +{ + struct as_external_lsa *al; + struct ospf_route *new; + + al = (struct as_external_lsa *) lsa->data; + + new = ospf_route_new (); + + /* Set redistributed type -- does make sense? */ + /* new->type = type; */ + new->id = al->header.id; + new->mask = al->mask; + + if (!IS_EXTERNAL_METRIC (al->e[0].tos)) + { + zlog_info ("Route[External]: type-1 created."); + new->path_type = OSPF_PATH_TYPE1_EXTERNAL; + new->cost = asbr_route->cost + metric; /* X + Y */ + } + else + { + zlog_info ("Route[External]: type-2 created."); + new->path_type = OSPF_PATH_TYPE2_EXTERNAL; + new->cost = asbr_route->cost; /* X */ + new->u.ext.type2_cost = metric; /* Y */ + } + + new->type = OSPF_DESTINATION_NETWORK; + new->path = list_new (); + new->u.ext.origin = lsa; + new->u.ext.tag = ntohl (al->e[0].route_tag); + new->u.ext.asbr = asbr_route; + + assert (new != asbr_route); + + return new; +} + +#define OSPF_ASE_CALC_INTERVAL 1 + +int +ospf_ase_calculate_route (struct ospf_lsa * lsa, void * p_arg, int n_arg) +{ + u_int32_t metric; + struct as_external_lsa *al; + struct ospf_route *asbr_route; + struct prefix_ipv4 asbr, p; + struct route_node *rn; + struct ospf_route *new, *or; + int ret; + + assert (lsa); + al = (struct as_external_lsa *) lsa->data; + +#ifdef HAVE_NSSA + if (lsa->data->type == OSPF_AS_NSSA_LSA) + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_ase_calc(): Processing Type-7"); + + /* Stay away from any Local Translated Type-7 LSAs */ + if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) + { + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_ase_calc(): Rejecting Local Xlt'd"); + return 0; + } +#endif /* HAVE_NSSA */ + + zlog_info ("Route[External]: Calculate AS-external-LSA to %s/%d", + inet_ntoa (al->header.id), ip_masklen (al->mask)); + /* (1) If the cost specified by the LSA is LSInfinity, or if the + LSA's LS age is equal to MaxAge, then examine the next LSA. */ + if ((metric = GET_METRIC (al->e[0].metric)) >= OSPF_LS_INFINITY) + { + zlog_info ("Route[External]: Metric is OSPF_LS_INFINITY"); + return 0; + } + if (IS_LSA_MAXAGE (lsa)) + { + zlog_info ("Route[External]: AS-external-LSA is MAXAGE"); + return 0; + } + + /* (2) If the LSA was originated by the calculating router itself, + examine the next LSA. */ + if (IS_LSA_SELF (lsa)) + { + zlog_info ("Route[External]: AS-external-LSA is self originated"); + return 0; + } + + /* (3) Call the destination described by the LSA N. N's address is + obtained by masking the LSA's Link State ID with the + network/subnet mask contained in the body of the LSA. Look + up the routing table entries (potentially one per attached + area) for the AS boundary router (ASBR) that originated the + LSA. If no entries exist for router ASBR (i.e., ASBR is + unreachable), do nothing with this LSA and consider the next + in the list. */ + + asbr.family = AF_INET; + asbr.prefix = al->header.adv_router; + asbr.prefixlen = IPV4_MAX_BITLEN; + apply_mask_ipv4 (&asbr); + + asbr_route = ospf_find_asbr_route (ospf_top->new_rtrs, &asbr); + if (asbr_route == NULL) + { + zlog_info ("Route[External]: Can't find originating ASBR route"); + return 0; + } + if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL)) + { + zlog_info ("Route[External]: Originating router is not an ASBR"); + return 0; + } + + /* Else, this LSA describes an AS external path to destination + N. Examine the forwarding address specified in the AS- + external-LSA. This indicates the IP address to which + packets for the destination should be forwarded. */ + + if (al->e[0].fwd_addr.s_addr == 0) + { + /* If the forwarding address is set to 0.0.0.0, packets should + be sent to the ASBR itself. Among the multiple routing table + entries for the ASBR, select the preferred entry as follows. + If RFC1583Compatibility is set to "disabled", prune the set + of routing table entries for the ASBR as described in + Section 16.4.1. In any case, among the remaining routing + table entries, select the routing table entry with the least + cost; when there are multiple least cost routing table + entries the entry whose associated area has the largest OSPF + Area ID (when considered as an unsigned 32-bit integer) is + chosen. */ + + /* asbr_route already contains the requested route */ + } + else + { + /* If the forwarding address is non-zero, look up the + forwarding address in the routing table.[24] The matching + routing table entry must specify an intra-area or inter-area + path; if no such path exists, do nothing with the LSA and + consider the next in the list. */ + if (! ospf_ase_forward_address_check (al->e[0].fwd_addr)) + { + zlog_info ("Route[External]: Forwarding address is our router address"); + return 0; + } + + asbr.family = AF_INET; + asbr.prefix = al->e[0].fwd_addr; + asbr.prefixlen = IPV4_MAX_BITLEN; + + rn = route_node_match (ospf_top->new_table, (struct prefix *) &asbr); + + if (rn == NULL || (asbr_route = rn->info) == NULL) + { + zlog_info ("Route[External]: Can't find route to forwarding address"); + if (rn) + route_unlock_node (rn); + return 0; + } + + route_unlock_node (rn); + } + + /* (4) Let X be the cost specified by the preferred routing table + entry for the ASBR/forwarding address, and Y the cost + specified in the LSA. X is in terms of the link state + metric, and Y is a type 1 or 2 external metric. */ + + + /* (5) Look up the routing table entry for the destination N. If + no entry exists for N, install the AS external path to N, + with next hop equal to the list of next hops to the + forwarding address, and advertising router equal to ASBR. + If the external metric type is 1, then the path-type is set + to type 1 external and the cost is equal to X+Y. If the + external metric type is 2, the path-type is set to type 2 + external, the link state component of the route's cost is X, + and the type 2 cost is Y. */ + new = ospf_ase_calculate_new_route (lsa, asbr_route, metric); + + /* (6) Compare the AS external path described by the LSA with the + existing paths in N's routing table entry, as follows. If + the new path is preferred, it replaces the present paths in + N's routing table entry. If the new path is of equal + preference, it is added to N's routing table entry's list of + paths. */ + + /* Set prefix. */ + p.family = AF_INET; + p.prefix = al->header.id; + p.prefixlen = ip_masklen (al->mask); + + /* if there is a Intra/Inter area route to the N + do not install external route */ + if ((rn = route_node_lookup (ospf_top->new_table, + (struct prefix *) &p)) != NULL + && (rn->info != NULL)) + { + if (new) + ospf_route_free (new); + return 0; + } + + /* Find a route to the same dest */ + /* If there is no route, create new one. */ + if ((rn = route_node_lookup (ospf_top->new_external_route, + (struct prefix *) &p)) == NULL + || (or = rn->info) == NULL) + { + zlog_info ("Route[External]: Adding a new route %s/%d", + inet_ntoa (p.prefix), p.prefixlen); + + ospf_route_add (ospf_top->new_external_route, &p, new, asbr_route); + + if (al->e[0].fwd_addr.s_addr) + ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr); + return 0; + } + else + { + /* (a) Intra-area and inter-area paths are always preferred + over AS external paths. + + (b) Type 1 external paths are always preferred over type 2 + external paths. When all paths are type 2 external + paths, the paths with the smallest advertised type 2 + metric are always preferred. */ + ret = ospf_route_cmp (new, or); + + /* (c) If the new AS external path is still indistinguishable + from the current paths in the N's routing table entry, + and RFC1583Compatibility is set to "disabled", select + the preferred paths based on the intra-AS paths to the + ASBR/forwarding addresses, as specified in Section + 16.4.1. + + (d) If the new AS external path is still indistinguishable + from the current paths in the N's routing table entry, + select the preferred path based on a least cost + comparison. Type 1 external paths are compared by + looking at the sum of the distance to the forwarding + address and the advertised type 1 metric (X+Y). Type 2 + external paths advertising equal type 2 metrics are + compared by looking at the distance to the forwarding + addresses. + */ + /* New route is better */ + if (ret < 0) + { + zlog_info ("Route[External]: New route is better"); + ospf_route_subst (rn, new, asbr_route); + if (al->e[0].fwd_addr.s_addr) + ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr); + or = new; + new = NULL; + } + /* Old route is better */ + else if (ret > 0) + { + zlog_info ("Route[External]: Old route is better"); + /* do nothing */ + } + /* Routes are equal */ + else + { + zlog_info ("Route[External]: Routes are equal"); + ospf_route_copy_nexthops (or, asbr_route->path); + if (al->e[0].fwd_addr.s_addr) + ospf_ase_complete_direct_routes (or, al->e[0].fwd_addr); + } + } + /* Make sure setting newly calculated ASBR route.*/ + or->u.ext.asbr = asbr_route; + if (new) + ospf_route_free (new); + + lsa->route = or; + return 0; +} + +int +ospf_ase_route_match_same (struct route_table *rt, struct prefix *prefix, + struct ospf_route *newor) +{ + struct route_node *rn; + struct ospf_route *or; + struct ospf_path *op; + struct ospf_path *newop; + listnode n1; + listnode n2; + + if (! rt || ! prefix) + return 0; + + rn = route_node_lookup (rt, prefix); + if (! rn) + return 0; + + route_unlock_node (rn); + + or = rn->info; + if (or->path_type != newor->path_type) + return 0; + + switch (or->path_type) + { + case OSPF_PATH_TYPE1_EXTERNAL: + if (or->cost != newor->cost) + return 0; + break; + case OSPF_PATH_TYPE2_EXTERNAL: + if ((or->cost != newor->cost) || + (or->u.ext.type2_cost != newor->u.ext.type2_cost)) + return 0; + break; + default: + assert (0); + return 0; + } + + if (or->path->count != newor->path->count) + return 0; + + /* Check each path. */ + for (n1 = listhead (or->path), n2 = listhead (newor->path); + n1 && n2; nextnode (n1), nextnode (n2)) + { + op = getdata (n1); + newop = getdata (n2); + + if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop)) + return 0; + } + return 1; +} + +int +ospf_ase_compare_tables (struct route_table *new_external_route, + struct route_table *old_external_route) +{ + struct route_node *rn, *new_rn; + struct ospf_route *or; + + /* Remove deleted routes */ + for (rn = route_top (old_external_route); rn; rn = route_next (rn)) + if ((or = rn->info)) + { + if (! (new_rn = route_node_lookup (new_external_route, &rn->p))) + ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or); + else + route_unlock_node (new_rn); + } + + + /* Install new routes */ + for (rn = route_top (new_external_route); rn; rn = route_next (rn)) + if ((or = rn->info) != NULL) + if (! ospf_ase_route_match_same (old_external_route, &rn->p, or)) + ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or); + + return 0; +} + +int +ospf_ase_calculate_timer (struct thread *t) +{ + struct ospf *ospf; + +#ifdef HAVE_NSSA + listnode node; + struct ospf_area *area; +#endif /* HAVE_NSSA */ + + ospf = THREAD_ARG (t); + ospf->t_ase_calc = NULL; + + if (ospf->ase_calc) + { + ospf->ase_calc = 0; + + /* Calculate external route for each AS-external-LSA */ + foreach_lsa (EXTERNAL_LSDB (ospf_top), NULL, 0, + ospf_ase_calculate_route); + +#ifdef HAVE_NSSA + /* This version simple adds to the table all NSSA areas */ + if (ospf_top->anyNSSA) + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + area = getdata (node); + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_ase_calculate_timer(): looking at area %s", + inet_ntoa (area->area_id)); + + if (area->external_routing == OSPF_AREA_NSSA) + + foreach_lsa (NSSA_LSDB (area), NULL, 0, + ospf_ase_calculate_route); + } +#endif /* HAVE_NSSA */ + + /* Compare old and new external routing table and install the + difference info zebra/kernel */ + ospf_ase_compare_tables (ospf_top->new_external_route, + ospf_top->old_external_route); + + /* Delete old external routing table */ + ospf_route_table_free (ospf_top->old_external_route); + ospf_top->old_external_route = ospf_top->new_external_route; + ospf_top->new_external_route = route_table_init (); + } + return 0; +} + +void +ospf_ase_calculate_schedule () +{ + if (! ospf_top) + return; + + ospf_top->ase_calc = 1; +} + +void +ospf_ase_calculate_timer_add () +{ + if (! ospf_top) + return; + + if (! ospf_top->t_ase_calc) + ospf_top->t_ase_calc = thread_add_timer (master, ospf_ase_calculate_timer, + ospf_top, OSPF_ASE_CALC_INTERVAL); +} + +void +ospf_ase_register_external_lsa (struct ospf_lsa *lsa, struct ospf *top) +{ + struct route_node *rn; + struct prefix_ipv4 p; + list lst; + struct as_external_lsa *al; + + al = (struct as_external_lsa *) lsa->data; + p.family = AF_INET; + p.prefix = lsa->data->id; + p.prefixlen = ip_masklen (al->mask); + apply_mask_ipv4 (&p); + + rn = route_node_get (top->external_lsas, (struct prefix *) &p); + if ((lst = rn->info) == NULL) + rn->info = lst = list_new(); + + /* We assume that if LSA is deleted from DB + is is also deleted from this RT */ + + listnode_add (lst, ospf_lsa_lock (lsa)); +} + +void +ospf_ase_unregister_external_lsa (struct ospf_lsa *lsa, struct ospf *top) +{ + struct route_node *rn; + struct prefix_ipv4 p; + list lst; + struct as_external_lsa *al; + + al = (struct as_external_lsa *) lsa->data; + p.family = AF_INET; + p.prefix = lsa->data->id; + p.prefixlen = ip_masklen (al->mask); + apply_mask_ipv4 (&p); + + rn = route_node_get (top->external_lsas, (struct prefix *) &p); + lst = rn->info; +#ifdef ORIGINAL_CODING + assert (lst); + + listnode_delete (lst, lsa); + ospf_lsa_unlock (lsa); +#else /* ORIGINAL_CODING */ + /* XXX lst can be NULL */ + if (lst) { + listnode_delete (lst, lsa); + ospf_lsa_unlock (lsa); + } +#endif /* ORIGINAL_CODING */ +} + +void +ospf_ase_external_lsas_finish (struct route_table *rt) +{ + struct route_node *rn; + struct ospf_lsa *lsa; + list lst; + listnode node; + + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((lst = rn->info) != NULL) + { + for (node = listhead (lst); node; node = nextnode (node)) + if ((lsa = getdata (node)) != NULL) + ospf_lsa_unlock (lsa); + list_delete (lst); + } + + route_table_finish (rt); +} + +void +ospf_ase_incremental_update (struct ospf_lsa *lsa, struct ospf *top) +{ + list lsas; + listnode node; + struct route_node *rn, *rn2; + struct prefix_ipv4 p; + struct route_table *tmp_old; + struct as_external_lsa *al; + + al = (struct as_external_lsa *) lsa->data; + p.family = AF_INET; + p.prefix = lsa->data->id; + p.prefixlen = ip_masklen (al->mask); + apply_mask_ipv4 (&p); + + /* if new_table is NULL, there was no spf calculation, thus + incremental update is unneeded */ + if (!top->new_table) + return; + + /* If there is already an intra-area or inter-area route + to the destination, no recalculation is necessary + (internal routes take precedence). */ + + rn = route_node_lookup (top->new_table, (struct prefix *) &p); + if (rn && rn->info) + { + route_unlock_node (rn); + return; + } + + rn = route_node_lookup (top->external_lsas, (struct prefix *) &p); + assert (rn && rn->info); + lsas = rn->info; + + for (node = listhead (lsas); node; nextnode (node)) + if ((lsa = getdata (node)) != NULL) + ospf_ase_calculate_route (lsa, NULL, 0); + + /* prepare temporary old routing table for compare */ + tmp_old = route_table_init (); + rn = route_node_lookup (top->old_external_route, (struct prefix *) &p); + if (rn && rn->info) + { + rn2 = route_node_get (tmp_old, (struct prefix *) &p); + rn2->info = rn->info; + } + + /* install changes to zebra */ + ospf_ase_compare_tables (top->new_external_route, tmp_old); + + /* update top->old_external_route table */ + if (rn && rn->info) + ospf_route_free ((struct ospf_route *) rn->info); + + rn2 = route_node_lookup (top->new_external_route, (struct prefix *) &p); + /* if new route exists, install it to top->old_external_route */ + if (rn2 && rn2->info) + { + if (!rn) + rn = route_node_get (top->old_external_route, (struct prefix *) &p); + rn->info = rn2->info; + } + else + { + /* remove route node from top->old_external_route */ + if (rn) + { + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + } + } + + if (rn2) + { + /* rn2->info is stored in route node of top->old_external_route */ + rn2->info = NULL; + route_unlock_node (rn2); + route_unlock_node (rn2); + } + + route_table_finish (tmp_old); +} diff --git a/ospfd/ospf_ase.h b/ospfd/ospf_ase.h new file mode 100644 index 00000000..f403e26d --- /dev/null +++ b/ospfd/ospf_ase.h @@ -0,0 +1,42 @@ +/* + * OSPF AS External route calculation. + * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_ASE_H +#define _ZEBRA_OSPF_ASE_H + + +struct ospf_route *ospf_find_asbr_route (struct route_table *, + struct prefix_ipv4 *); +struct ospf_route *ospf_find_asbr_route_through_area(struct route_table *, + struct prefix_ipv4 *, + struct ospf_area *); + +int ospf_ase_calculate_route (struct ospf_lsa *, void *, int); +void ospf_ase_calculate_schedule (); +void ospf_ase_calculate_timer_add (); + +void ospf_ase_external_lsas_finish (struct route_table *); +void ospf_ase_incremental_update (struct ospf_lsa *, struct ospf *); +void ospf_ase_register_external_lsa (struct ospf_lsa *, struct ospf *); +void ospf_ase_unregister_external_lsa (struct ospf_lsa *, struct ospf *); + +#endif /* _ZEBRA_OSPF_ASE_H */ diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c new file mode 100644 index 00000000..da2e0973 --- /dev/null +++ b/ospfd/ospf_dump.c @@ -0,0 +1,1673 @@ +/* + * OSPFd dump routine. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "linklist.h" +#include "thread.h" +#include "prefix.h" +#include "command.h" +#include "stream.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_network.h" + +struct message ospf_ism_state_msg[] = +{ + { ISM_DependUpon, "DependUpon" }, + { ISM_Down, "Down" }, + { ISM_Loopback, "Loopback" }, + { ISM_Waiting, "Waiting" }, + { ISM_PointToPoint, "Point-To-Point" }, + { ISM_DROther, "DROther" }, + { ISM_Backup, "Backup" }, + { ISM_DR, "DR" }, +}; +int ospf_ism_state_msg_max = OSPF_ISM_STATE_MAX; + +struct message ospf_nsm_state_msg[] = +{ + { NSM_DependUpon, "DependUpon" }, + { NSM_Down, "Down" }, + { NSM_Attempt, "Attempt" }, + { NSM_Init, "Init" }, + { NSM_TwoWay, "2-Way" }, + { NSM_ExStart, "ExStart" }, + { NSM_Exchange, "Exchange" }, + { NSM_Loading, "Loading" }, + { NSM_Full, "Full" }, +}; +int ospf_nsm_state_msg_max = OSPF_NSM_STATE_MAX; + +struct message ospf_lsa_type_msg[] = +{ + { OSPF_UNKNOWN_LSA, "unknown" }, + { OSPF_ROUTER_LSA, "router-LSA" }, + { OSPF_NETWORK_LSA, "network-LSA" }, + { OSPF_SUMMARY_LSA, "summary-LSA" }, + { OSPF_ASBR_SUMMARY_LSA, "summary-LSA" }, + { OSPF_AS_EXTERNAL_LSA, "AS-external-LSA" }, + { OSPF_GROUP_MEMBER_LSA, "GROUP MEMBER LSA" }, + { OSPF_AS_NSSA_LSA, "NSSA-LSA" }, + { 8, "Type-8 LSA" }, + { OSPF_OPAQUE_LINK_LSA, "Link-Local Opaque-LSA" }, + { OSPF_OPAQUE_AREA_LSA, "Area-Local Opaque-LSA" }, + { OSPF_OPAQUE_AS_LSA, "AS-external Opaque-LSA" }, +}; +int ospf_lsa_type_msg_max = OSPF_MAX_LSA; + +struct message ospf_link_state_id_type_msg[] = +{ + { OSPF_UNKNOWN_LSA, "(unknown)" }, + { OSPF_ROUTER_LSA, "" }, + { OSPF_NETWORK_LSA, "(address of Designated Router)" }, + { OSPF_SUMMARY_LSA, "(summary Network Number)" }, + { OSPF_ASBR_SUMMARY_LSA, "(AS Boundary Router address)" }, + { OSPF_AS_EXTERNAL_LSA, "(External Network Number)" }, + { OSPF_GROUP_MEMBER_LSA, "(Group membership information)" }, + { OSPF_AS_NSSA_LSA, "(External Network Number for NSSA)" }, + { 8, "(Type-8 LSID)" }, + { OSPF_OPAQUE_LINK_LSA, "(Link-Local Opaque-Type/ID)" }, + { OSPF_OPAQUE_AREA_LSA, "(Area-Local Opaque-Type/ID)" }, + { OSPF_OPAQUE_AS_LSA, "(AS-external Opaque-Type/ID)" }, +}; +int ospf_link_state_id_type_msg_max = OSPF_MAX_LSA; + +struct message ospf_redistributed_proto[] = +{ + { ZEBRA_ROUTE_SYSTEM, "System" }, + { ZEBRA_ROUTE_KERNEL, "Kernel" }, + { ZEBRA_ROUTE_CONNECT, "Connected" }, + { ZEBRA_ROUTE_STATIC, "Static" }, + { ZEBRA_ROUTE_RIP, "RIP" }, + { ZEBRA_ROUTE_RIPNG, "RIPng" }, + { ZEBRA_ROUTE_OSPF, "OSPF" }, + { ZEBRA_ROUTE_OSPF6, "OSPFv3" }, + { ZEBRA_ROUTE_BGP, "BGP" }, + { ZEBRA_ROUTE_MAX, "Default" }, +}; +int ospf_redistributed_proto_max = ZEBRA_ROUTE_MAX + 1; + +struct message ospf_network_type_msg[] = +{ + { OSPF_IFTYPE_NONE, "NONE" }, + { OSPF_IFTYPE_POINTOPOINT, "Point-to-Point" }, + { OSPF_IFTYPE_BROADCAST, "Broadcast" }, + { OSPF_IFTYPE_NBMA, "NBMA" }, + { OSPF_IFTYPE_POINTOMULTIPOINT, "Point-to-MultiPoint" }, + { OSPF_IFTYPE_VIRTUALLINK, "Virtual-Link" }, +}; +int ospf_network_type_msg_max = OSPF_IFTYPE_MAX; + +/* Configuration debug option variables. */ +unsigned long conf_debug_ospf_packet[5] = {0, 0, 0, 0, 0}; +unsigned long conf_debug_ospf_event = 0; +unsigned long conf_debug_ospf_ism = 0; +unsigned long conf_debug_ospf_nsm = 0; +unsigned long conf_debug_ospf_lsa = 0; +unsigned long conf_debug_ospf_zebra = 0; +unsigned long conf_debug_ospf_nssa = 0; + +/* Enable debug option variables -- valid only session. */ +unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0}; +unsigned long term_debug_ospf_event = 0; +unsigned long term_debug_ospf_ism = 0; +unsigned long term_debug_ospf_nsm = 0; +unsigned long term_debug_ospf_lsa = 0; +unsigned long term_debug_ospf_zebra = 0; +unsigned long term_debug_ospf_nssa = 0; + + +#define OSPF_AREA_STRING_MAXLEN 16 +char * +ospf_area_name_string (struct ospf_area *area) +{ + static char buf[OSPF_AREA_STRING_MAXLEN] = ""; + u_int32_t area_id; + + if (!area) + return "-"; + + area_id = ntohl (area->area_id.s_addr); + snprintf (buf, OSPF_AREA_STRING_MAXLEN, "%d.%d.%d.%d", + (area_id >> 24) & 0xff, (area_id >> 16) & 0xff, + (area_id >> 8) & 0xff, area_id & 0xff); + return buf; +} + +#define OSPF_AREA_DESC_STRING_MAXLEN 23 +char * +ospf_area_desc_string (struct ospf_area *area) +{ + static char buf[OSPF_AREA_DESC_STRING_MAXLEN] = ""; + u_char type; + + if (!area) + return "(incomplete)"; + + type = area->external_routing; + switch (type) + { + case OSPF_AREA_NSSA: + snprintf (buf, OSPF_AREA_DESC_STRING_MAXLEN, "%s [NSSA]", + ospf_area_name_string (area)); + break; + case OSPF_AREA_STUB: + snprintf (buf, OSPF_AREA_DESC_STRING_MAXLEN, "%s [Stub]", + ospf_area_name_string (area)); + break; + default: + return ospf_area_name_string (area); + break; + } + + return buf; +} + +#define OSPF_IF_STRING_MAXLEN 40 +char * +ospf_if_name_string (struct ospf_interface *oi) +{ + static char buf[OSPF_IF_STRING_MAXLEN] = ""; + u_int32_t ifaddr; + + if (!oi) + return "inactive"; + + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + return oi->ifp->name; + + ifaddr = ntohl (oi->address->u.prefix4.s_addr); + snprintf (buf, OSPF_IF_STRING_MAXLEN, + "%s:%d.%d.%d.%d", oi->ifp->name, + (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff, + (ifaddr >> 8) & 0xff, ifaddr & 0xff); + return buf; +} + + +void +ospf_nbr_state_message (struct ospf_neighbor *nbr, char *buf, size_t size) +{ + int state; + struct ospf_interface *oi = nbr->oi; + + if (IPV4_ADDR_SAME (&DR (oi), &nbr->address.u.prefix4)) + state = ISM_DR; + else if (IPV4_ADDR_SAME (&BDR (oi), &nbr->address.u.prefix4)) + state = ISM_Backup; + else + state = ISM_DROther; + + memset (buf, 0, size); + + snprintf (buf, size, "%s/%s", + LOOKUP (ospf_nsm_state_msg, nbr->state), + LOOKUP (ospf_ism_state_msg, state)); +} + +char * +ospf_timer_dump (struct thread *t, char *buf, size_t size) +{ + struct timeval now; + unsigned long h, m, s; + + if (!t) + return "inactive"; + + h = m = s = 0; + memset (buf, 0, size); + + gettimeofday (&now, NULL); + + s = t->u.sands.tv_sec - now.tv_sec; + if (s >= 3600) + { + h = s / 3600; + s -= h * 3600; + } + + if (s >= 60) + { + m = s / 60; + s -= m * 60; + } + + snprintf (buf, size, "%02ld:%02ld:%02ld", h, m, s); + + return buf; +} + +#define OSPF_OPTION_STR_MAXLEN 24 + +char * +ospf_options_dump (u_char options) +{ + static char buf[OSPF_OPTION_STR_MAXLEN]; + + snprintf (buf, OSPF_OPTION_STR_MAXLEN, "*|%s|%s|%s|%s|%s|%s|*", + (options & OSPF_OPTION_O) ? "O" : "-", + (options & OSPF_OPTION_DC) ? "DC" : "-", + (options & OSPF_OPTION_EA) ? "EA" : "-", + (options & OSPF_OPTION_NP) ? "N/P" : "-", + (options & OSPF_OPTION_MC) ? "MC" : "-", + (options & OSPF_OPTION_E) ? "E" : "-"); + + return buf; +} + +void +ospf_packet_hello_dump (struct stream *s, u_int16_t length) +{ + struct ospf_hello *hello; + int i; + + hello = (struct ospf_hello *) STREAM_PNT (s); + + zlog_info ("Hello"); + zlog_info (" NetworkMask %s", inet_ntoa (hello->network_mask)); + zlog_info (" HelloInterval %d", ntohs (hello->hello_interval)); + zlog_info (" Options %d (%s)", hello->options, + ospf_options_dump (hello->options)); + zlog_info (" RtrPriority %d", hello->priority); + zlog_info (" RtrDeadInterval %ld", (u_long)ntohl (hello->dead_interval)); + zlog_info (" DRouter %s", inet_ntoa (hello->d_router)); + zlog_info (" BDRouter %s", inet_ntoa (hello->bd_router)); + + length -= OSPF_HEADER_SIZE + OSPF_HELLO_MIN_SIZE; + zlog_info (" # Neighbors %d", length / 4); + for (i = 0; length > 0; i++, length -= sizeof (struct in_addr)) + zlog_info (" Neighbor %s", inet_ntoa (hello->neighbors[i])); +} + +char * +ospf_dd_flags_dump (u_char flags, char *buf, size_t size) +{ + memset (buf, 0, size); + + snprintf (buf, size, "%s|%s|%s", + (flags & OSPF_DD_FLAG_I) ? "I" : "-", + (flags & OSPF_DD_FLAG_M) ? "M" : "-", + (flags & OSPF_DD_FLAG_MS) ? "MS" : "-"); + + return buf; +} + +void +ospf_lsa_header_dump (struct lsa_header *lsah) +{ + zlog_info (" LSA Header"); + zlog_info (" LS age %d", ntohs (lsah->ls_age)); + zlog_info (" Options %d (%s)", lsah->options, + ospf_options_dump (lsah->options)); + zlog_info (" LS type %d (%s)", lsah->type, + LOOKUP (ospf_lsa_type_msg, lsah->type)); + zlog_info (" Link State ID %s", inet_ntoa (lsah->id)); + zlog_info (" Advertising Router %s", inet_ntoa (lsah->adv_router)); + zlog_info (" LS sequence number 0x%lx", (u_long)ntohl (lsah->ls_seqnum)); + zlog_info (" LS checksum 0x%x", ntohs (lsah->checksum)); + zlog_info (" length %d", ntohs (lsah->length)); +} + +char * +ospf_router_lsa_flags_dump (u_char flags, char *buf, size_t size) +{ + memset (buf, 0, size); + + snprintf (buf, size, "%s|%s|%s", + (flags & ROUTER_LSA_VIRTUAL) ? "V" : "-", + (flags & ROUTER_LSA_EXTERNAL) ? "E" : "-", + (flags & ROUTER_LSA_BORDER) ? "B" : "-"); + + return buf; +} + +void +ospf_router_lsa_dump (struct stream *s, u_int16_t length) +{ + char buf[BUFSIZ]; + struct router_lsa *rl; + int i, len; + + rl = (struct router_lsa *) STREAM_PNT (s); + + zlog_info (" Router-LSA"); + zlog_info (" flags %s", + ospf_router_lsa_flags_dump (rl->flags, buf, BUFSIZ)); + zlog_info (" # links %d", ntohs (rl->links)); + + len = ntohs (rl->header.length) - OSPF_LSA_HEADER_SIZE - 4; + for (i = 0; len > 0; i++) + { + zlog_info (" Link ID %s", inet_ntoa (rl->link[i].link_id)); + zlog_info (" Link Data %s", inet_ntoa (rl->link[i].link_data)); + zlog_info (" Type %d", (u_char) rl->link[i].type); + zlog_info (" TOS %d", (u_char) rl->link[i].tos); + zlog_info (" metric %d", ntohs (rl->link[i].metric)); + + len -= 12; + } +} + +void +ospf_network_lsa_dump (struct stream *s, u_int16_t length) +{ + struct network_lsa *nl; + int i, cnt; + + nl = (struct network_lsa *) STREAM_PNT (s); + cnt = (ntohs (nl->header.length) - (OSPF_LSA_HEADER_SIZE + 4)) / 4; + + zlog_info (" Network-LSA"); + /* + zlog_info ("LSA total size %d", ntohs (nl->header.length)); + zlog_info ("Network-LSA size %d", + ntohs (nl->header.length) - OSPF_LSA_HEADER_SIZE); + */ + zlog_info (" Network Mask %s", inet_ntoa (nl->mask)); + zlog_info (" # Attached Routers %d", cnt); + for (i = 0; i < cnt; i++) + zlog_info (" Attached Router %s", inet_ntoa (nl->routers[i])); +} + +void +ospf_summary_lsa_dump (struct stream *s, u_int16_t length) +{ + struct summary_lsa *sl; + int size; + int i; + + sl = (struct summary_lsa *) STREAM_PNT (s); + + zlog_info (" Summary-LSA"); + zlog_info (" Network Mask %s", inet_ntoa (sl->mask)); + + size = ntohs (sl->header.length) - OSPF_LSA_HEADER_SIZE - 4; + for (i = 0; size > 0; size -= 4, i++) + zlog_info (" TOS=%d metric %d", sl->tos, + GET_METRIC (sl->metric)); +} + +void +ospf_as_external_lsa_dump (struct stream *s, u_int16_t length) +{ + struct as_external_lsa *al; + int size; + int i; + + al = (struct as_external_lsa *) STREAM_PNT (s); + + zlog_info (" AS-external-LSA"); + zlog_info (" Network Mask %s", inet_ntoa (al->mask)); + + size = ntohs (al->header.length) - OSPF_LSA_HEADER_SIZE -4; + for (i = 0; size > 0; size -= 12, i++) + { + zlog_info (" bit %s TOS=%d metric %d", + IS_EXTERNAL_METRIC (al->e[i].tos) ? "E" : "-", + al->e[i].tos & 0x7f, GET_METRIC (al->e[i].metric)); + zlog_info (" Forwarding address %s", inet_ntoa (al->e[i].fwd_addr)); + zlog_info (" External Route Tag %d", al->e[i].route_tag); + } +} + +void +ospf_lsa_header_list_dump (struct stream *s, u_int16_t length) +{ + struct lsa_header *lsa; + + zlog_info (" # LSA Headers %d", length / OSPF_LSA_HEADER_SIZE); + + /* LSA Headers. */ + while (length > 0) + { + lsa = (struct lsa_header *) STREAM_PNT (s); + ospf_lsa_header_dump (lsa); + + stream_forward (s, OSPF_LSA_HEADER_SIZE); + length -= OSPF_LSA_HEADER_SIZE; + } +} + +void +ospf_packet_db_desc_dump (struct stream *s, u_int16_t length) +{ + struct ospf_db_desc *dd; + char dd_flags[8]; + + u_int32_t gp; + + gp = stream_get_getp (s); + dd = (struct ospf_db_desc *) STREAM_PNT (s); + + zlog_info ("Database Description"); + zlog_info (" Interface MTU %d", ntohs (dd->mtu)); + zlog_info (" Options %d (%s)", dd->options, + ospf_options_dump (dd->options)); + zlog_info (" Flags %d (%s)", dd->flags, + ospf_dd_flags_dump (dd->flags, dd_flags, sizeof dd_flags)); + zlog_info (" Sequence Number 0x%08lx", (u_long)ntohl (dd->dd_seqnum)); + + length -= OSPF_HEADER_SIZE + OSPF_DB_DESC_MIN_SIZE; + + stream_forward (s, OSPF_DB_DESC_MIN_SIZE); + + ospf_lsa_header_list_dump (s, length); + + stream_set_getp (s, gp); +} + +void +ospf_packet_ls_req_dump (struct stream *s, u_int16_t length) +{ + u_int32_t sp; + u_int32_t ls_type; + struct in_addr ls_id; + struct in_addr adv_router; + + sp = stream_get_getp (s); + + length -= OSPF_HEADER_SIZE; + + zlog_info ("Link State Request"); + zlog_info (" # Requests %d", length / 12); + + for (; length > 0; length -= 12) + { + ls_type = stream_getl (s); + ls_id.s_addr = stream_get_ipv4 (s); + adv_router.s_addr = stream_get_ipv4 (s); + + zlog_info (" LS type %d", ls_type); + zlog_info (" Link State ID %s", inet_ntoa (ls_id)); + zlog_info (" Advertising Router %s", + inet_ntoa (adv_router)); + } + + stream_set_getp (s, sp); +} + +void +ospf_packet_ls_upd_dump (struct stream *s, u_int16_t length) +{ + u_int32_t sp; + struct lsa_header *lsa; + int lsa_len; + u_int32_t count; + + length -= OSPF_HEADER_SIZE; + + sp = stream_get_getp (s); + + count = stream_getl (s); + length -= 4; + + zlog_info ("Link State Update"); + zlog_info (" # LSAs %d", count); + + while (length > 0 && count > 0) + { + if (length < OSPF_HEADER_SIZE || length % 4 != 0) + { + zlog_info (" Remaining %d bytes; Incorrect length.", length); + break; + } + + lsa = (struct lsa_header *) STREAM_PNT (s); + lsa_len = ntohs (lsa->length); + ospf_lsa_header_dump (lsa); + + switch (lsa->type) + { + case OSPF_ROUTER_LSA: + ospf_router_lsa_dump (s, length); + break; + case OSPF_NETWORK_LSA: + ospf_network_lsa_dump (s, length); + break; + case OSPF_SUMMARY_LSA: + case OSPF_ASBR_SUMMARY_LSA: + ospf_summary_lsa_dump (s, length); + break; + case OSPF_AS_EXTERNAL_LSA: + ospf_as_external_lsa_dump (s, length); + break; +#ifdef HAVE_NSSA + case OSPF_AS_NSSA_LSA: + /* XXX */ + break; +#endif /* HAVE_NSSA */ +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: + ospf_opaque_lsa_dump (s, length); + break; +#endif /* HAVE_OPAQUE_LSA */ + default: + break; + } + + stream_forward (s, lsa_len); + length -= lsa_len; + count--; + } + + stream_set_getp (s, sp); +} + +void +ospf_packet_ls_ack_dump (struct stream *s, u_int16_t length) +{ + u_int32_t sp; + + length -= OSPF_HEADER_SIZE; + sp = stream_get_getp (s); + + zlog_info ("Link State Acknowledgment"); + ospf_lsa_header_list_dump (s, length); + + stream_set_getp (s, sp); +} + +void +ospf_ip_header_dump (struct stream *s) +{ + u_int16_t length; + struct ip *iph; + + iph = (struct ip *) STREAM_PNT (s); + +#ifdef GNU_LINUX + length = ntohs (iph->ip_len); +#else /* GNU_LINUX */ + length = iph->ip_len; +#endif /* GNU_LINUX */ + + /* IP Header dump. */ + zlog_info ("ip_v %d", iph->ip_v); + zlog_info ("ip_hl %d", iph->ip_hl); + zlog_info ("ip_tos %d", iph->ip_tos); + zlog_info ("ip_len %d", length); + zlog_info ("ip_id %u", (u_int32_t) iph->ip_id); + zlog_info ("ip_off %u", (u_int32_t) iph->ip_off); + zlog_info ("ip_ttl %d", iph->ip_ttl); + zlog_info ("ip_p %d", iph->ip_p); + /* There is a report that Linux 2.0.37 does not have ip_sum. But + I'm not sure. Temporary commented out by kunihiro. */ + /* zlog_info ("ip_sum 0x%x", (u_int32_t) ntohs (iph->ip_sum)); */ + zlog_info ("ip_src %s", inet_ntoa (iph->ip_src)); + zlog_info ("ip_dst %s", inet_ntoa (iph->ip_dst)); +} + +void +ospf_header_dump (struct ospf_header *ospfh) +{ + char buf[9]; + + zlog_info ("Header"); + zlog_info (" Version %d", ospfh->version); + zlog_info (" Type %d (%s)", ospfh->type, + ospf_packet_type_str[ospfh->type]); + zlog_info (" Packet Len %d", ntohs (ospfh->length)); + zlog_info (" Router ID %s", inet_ntoa (ospfh->router_id)); + zlog_info (" Area ID %s", inet_ntoa (ospfh->area_id)); + zlog_info (" Checksum 0x%x", ntohs (ospfh->checksum)); + zlog_info (" AuType %d", ntohs (ospfh->auth_type)); + + switch (ntohs (ospfh->auth_type)) + { + case OSPF_AUTH_NULL: + break; + case OSPF_AUTH_SIMPLE: + memset (buf, 0, 9); + strncpy (buf, ospfh->u.auth_data, 8); + zlog_info (" Simple Password %s", buf); + break; + case OSPF_AUTH_CRYPTOGRAPHIC: + zlog_info (" Cryptographic Authentication"); + zlog_info (" Key ID %d", ospfh->u.crypt.key_id); + zlog_info (" Auth Data Len %d", ospfh->u.crypt.auth_data_len); + zlog_info (" Sequence number %ld", + (u_long)ntohl (ospfh->u.crypt.crypt_seqnum)); + break; + default: + zlog_info ("* This is not supported authentication type"); + break; + } + +} + +void +ospf_packet_dump (struct stream *s) +{ + struct ospf_header *ospfh; + unsigned long gp; + + /* Preserve pointer. */ + gp = stream_get_getp (s); + + /* OSPF Header dump. */ + ospfh = (struct ospf_header *) STREAM_PNT (s); + + /* Until detail flag is set, return. */ + if (!(term_debug_ospf_packet[ospfh->type - 1] & OSPF_DEBUG_DETAIL)) + return; + + /* Show OSPF header detail. */ + ospf_header_dump (ospfh); + stream_forward (s, OSPF_HEADER_SIZE); + + switch (ospfh->type) + { + case OSPF_MSG_HELLO: + ospf_packet_hello_dump (s, ntohs (ospfh->length)); + break; + case OSPF_MSG_DB_DESC: + ospf_packet_db_desc_dump (s, ntohs (ospfh->length)); + break; + case OSPF_MSG_LS_REQ: + ospf_packet_ls_req_dump (s, ntohs (ospfh->length)); + break; + case OSPF_MSG_LS_UPD: + ospf_packet_ls_upd_dump (s, ntohs (ospfh->length)); + break; + case OSPF_MSG_LS_ACK: + ospf_packet_ls_ack_dump (s, ntohs (ospfh->length)); + break; + default: + break; + } + + stream_set_getp (s, gp); +} + + +/* + [no] debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) + [send|recv [detail]] +*/ +DEFUN (debug_ospf_packet, + debug_ospf_packet_all_cmd, + "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)", + DEBUG_STR + OSPF_STR + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n") +{ + int type = 0; + int flag = 0; + int i; + + assert (argc > 0); + + /* Check packet type. */ + if (strncmp (argv[0], "h", 1) == 0) + type = OSPF_DEBUG_HELLO; + else if (strncmp (argv[0], "d", 1) == 0) + type = OSPF_DEBUG_DB_DESC; + else if (strncmp (argv[0], "ls-r", 4) == 0) + type = OSPF_DEBUG_LS_REQ; + else if (strncmp (argv[0], "ls-u", 4) == 0) + type = OSPF_DEBUG_LS_UPD; + else if (strncmp (argv[0], "ls-a", 4) == 0) + type = OSPF_DEBUG_LS_ACK; + else if (strncmp (argv[0], "a", 1) == 0) + type = OSPF_DEBUG_ALL; + + /* Default, both send and recv. */ + if (argc == 1) + flag = OSPF_DEBUG_SEND | OSPF_DEBUG_RECV; + + /* send or recv. */ + if (argc >= 2) + { + if (strncmp (argv[1], "s", 1) == 0) + flag = OSPF_DEBUG_SEND; + else if (strncmp (argv[1], "r", 1) == 0) + flag = OSPF_DEBUG_RECV; + else if (strncmp (argv[1], "d", 1) == 0) + flag = OSPF_DEBUG_SEND | OSPF_DEBUG_RECV | OSPF_DEBUG_DETAIL; + } + + /* detail. */ + if (argc == 3) + if (strncmp (argv[2], "d", 1) == 0) + flag |= OSPF_DEBUG_DETAIL; + + for (i = 0; i < 5; i++) + if (type & (0x01 << i)) + { + if (vty->node == CONFIG_NODE) + DEBUG_PACKET_ON (i, flag); + else + TERM_DEBUG_PACKET_ON (i, flag); + } + + return CMD_SUCCESS; +} + +ALIAS (debug_ospf_packet, + debug_ospf_packet_send_recv_cmd, + "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv|detail)", + "Debugging functions\n" + "OSPF information\n" + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n" + "Packet sent\n" + "Packet received\n" + "Detail information\n") + +ALIAS (debug_ospf_packet, + debug_ospf_packet_send_recv_detail_cmd, + "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) (detail|)", + "Debugging functions\n" + "OSPF information\n" + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n" + "Packet sent\n" + "Packet received\n" + "Detail Information\n") + + +DEFUN (no_debug_ospf_packet, + no_debug_ospf_packet_all_cmd, + "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n") +{ + int type = 0; + int flag = 0; + int i; + + assert (argc > 0); + + /* Check packet type. */ + if (strncmp (argv[0], "h", 1) == 0) + type = OSPF_DEBUG_HELLO; + else if (strncmp (argv[0], "d", 1) == 0) + type = OSPF_DEBUG_DB_DESC; + else if (strncmp (argv[0], "ls-r", 4) == 0) + type = OSPF_DEBUG_LS_REQ; + else if (strncmp (argv[0], "ls-u", 4) == 0) + type = OSPF_DEBUG_LS_UPD; + else if (strncmp (argv[0], "ls-a", 4) == 0) + type = OSPF_DEBUG_LS_ACK; + else if (strncmp (argv[0], "a", 1) == 0) + type = OSPF_DEBUG_ALL; + + /* Default, both send and recv. */ + if (argc == 1) + flag = OSPF_DEBUG_SEND | OSPF_DEBUG_RECV | OSPF_DEBUG_DETAIL ; + + /* send or recv. */ + if (argc == 2) + { + if (strncmp (argv[1], "s", 1) == 0) + flag = OSPF_DEBUG_SEND | OSPF_DEBUG_DETAIL; + else if (strncmp (argv[1], "r", 1) == 0) + flag = OSPF_DEBUG_RECV | OSPF_DEBUG_DETAIL; + else if (strncmp (argv[1], "d", 1) == 0) + flag = OSPF_DEBUG_DETAIL; + } + + /* detail. */ + if (argc == 3) + if (strncmp (argv[2], "d", 1) == 0) + flag = OSPF_DEBUG_DETAIL; + + for (i = 0; i < 5; i++) + if (type & (0x01 << i)) + { + if (vty->node == CONFIG_NODE) + DEBUG_PACKET_OFF (i, flag); + else + TERM_DEBUG_PACKET_OFF (i, flag); + } + +#ifdef DEBUG + for (i = 0; i < 5; i++) + zlog_info ("flag[%d] = %d", i, ospf_debug_packet[i]); +#endif /* DEBUG */ + + return CMD_SUCCESS; +} + +ALIAS (no_debug_ospf_packet, + no_debug_ospf_packet_send_recv_cmd, + "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv|detail)", + NO_STR + "Debugging functions\n" + "OSPF information\n" + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n" + "Packet sent\n" + "Packet received\n" + "Detail Information\n") + +ALIAS (no_debug_ospf_packet, + no_debug_ospf_packet_send_recv_detail_cmd, + "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) (detail|)", + NO_STR + "Debugging functions\n" + "OSPF information\n" + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n" + "Packet sent\n" + "Packet received\n" + "Detail Information\n") + + +DEFUN (debug_ospf_ism, + debug_ospf_ism_cmd, + "debug ospf ism", + DEBUG_STR + OSPF_STR + "OSPF Interface State Machine\n") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_ON (ism, ISM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + DEBUG_ON (ism, ISM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + DEBUG_ON (ism, ISM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + DEBUG_ON (ism, ISM_TIMERS); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_ON (ism, ISM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + TERM_DEBUG_ON (ism, ISM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + TERM_DEBUG_ON (ism, ISM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + TERM_DEBUG_ON (ism, ISM_TIMERS); + } + + return CMD_SUCCESS; +} + +ALIAS (debug_ospf_ism, + debug_ospf_ism_sub_cmd, + "debug ospf ism (status|events|timers)", + DEBUG_STR + OSPF_STR + "OSPF Interface State Machine\n" + "ISM Status Information\n" + "ISM Event Information\n" + "ISM TImer Information\n") + +DEFUN (no_debug_ospf_ism, + no_debug_ospf_ism_cmd, + "no debug ospf ism", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF Interface State Machine") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_OFF (ism, ISM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + DEBUG_OFF (ism, ISM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + DEBUG_OFF (ism, ISM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + DEBUG_OFF (ism, ISM_TIMERS); + } + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_OFF (ism, ISM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + TERM_DEBUG_OFF (ism, ISM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + TERM_DEBUG_OFF (ism, ISM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + TERM_DEBUG_OFF (ism, ISM_TIMERS); + } + + return CMD_SUCCESS; +} + +ALIAS (no_debug_ospf_ism, + no_debug_ospf_ism_sub_cmd, + "no debug ospf ism (status|events|timers)", + NO_STR + "Debugging functions\n" + "OSPF information\n" + "OSPF Interface State Machine\n" + "ISM Status Information\n" + "ISM Event Information\n" + "ISM Timer Information\n") + + +DEFUN (debug_ospf_nsm, + debug_ospf_nsm_cmd, + "debug ospf nsm", + DEBUG_STR + OSPF_STR + "OSPF Neighbor State Machine\n") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_ON (nsm, NSM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + DEBUG_ON (nsm, NSM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + DEBUG_ON (nsm, NSM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + DEBUG_ON (nsm, NSM_TIMERS); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_ON (nsm, NSM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + TERM_DEBUG_ON (nsm, NSM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + TERM_DEBUG_ON (nsm, NSM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + TERM_DEBUG_ON (nsm, NSM_TIMERS); + } + + return CMD_SUCCESS; +} + +ALIAS (debug_ospf_nsm, + debug_ospf_nsm_sub_cmd, + "debug ospf nsm (status|events|timers)", + DEBUG_STR + OSPF_STR + "OSPF Neighbor State Machine\n" + "NSM Status Information\n" + "NSM Event Information\n" + "NSM Timer Information\n") + +DEFUN (no_debug_ospf_nsm, + no_debug_ospf_nsm_cmd, + "no debug ospf nsm", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF Neighbor State Machine") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_OFF (nsm, NSM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + DEBUG_OFF (nsm, NSM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + DEBUG_OFF (nsm, NSM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + DEBUG_OFF (nsm, NSM_TIMERS); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_OFF (nsm, NSM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + TERM_DEBUG_OFF (nsm, NSM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + TERM_DEBUG_OFF (nsm, NSM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + TERM_DEBUG_OFF (nsm, NSM_TIMERS); + } + + return CMD_SUCCESS; +} + +ALIAS (no_debug_ospf_nsm, + no_debug_ospf_nsm_sub_cmd, + "no debug ospf nsm (status|events|timers)", + NO_STR + "Debugging functions\n" + "OSPF information\n" + "OSPF Interface State Machine\n" + "NSM Status Information\n" + "NSM Event Information\n" + "NSM Timer Information\n") + + +DEFUN (debug_ospf_lsa, + debug_ospf_lsa_cmd, + "debug ospf lsa", + DEBUG_STR + OSPF_STR + "OSPF Link State Advertisement\n") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_ON (lsa, LSA); + else if (argc == 1) + { + if (strncmp (argv[0], "g", 1) == 0) + DEBUG_ON (lsa, LSA_GENERATE); + else if (strncmp (argv[0], "f", 1) == 0) + DEBUG_ON (lsa, LSA_FLOODING); + else if (strncmp (argv[0], "i", 1) == 0) + DEBUG_ON (lsa, LSA_INSTALL); + else if (strncmp (argv[0], "r", 1) == 0) + DEBUG_ON (lsa, LSA_REFRESH); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_ON (lsa, LSA); + else if (argc == 1) + { + if (strncmp (argv[0], "g", 1) == 0) + TERM_DEBUG_ON (lsa, LSA_GENERATE); + else if (strncmp (argv[0], "f", 1) == 0) + TERM_DEBUG_ON (lsa, LSA_FLOODING); + else if (strncmp (argv[0], "i", 1) == 0) + TERM_DEBUG_ON (lsa, LSA_INSTALL); + else if (strncmp (argv[0], "r", 1) == 0) + TERM_DEBUG_ON (lsa, LSA_REFRESH); + } + + return CMD_SUCCESS; +} + +ALIAS (debug_ospf_lsa, + debug_ospf_lsa_sub_cmd, + "debug ospf lsa (generate|flooding|install|refresh)", + DEBUG_STR + OSPF_STR + "OSPF Link State Advertisement\n" + "LSA Generation\n" + "LSA Flooding\n" + "LSA Install/Delete\n" + "LSA Refresh\n") + +DEFUN (no_debug_ospf_lsa, + no_debug_ospf_lsa_cmd, + "no debug ospf lsa", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF Link State Advertisement\n") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_OFF (lsa, LSA); + else if (argc == 1) + { + if (strncmp (argv[0], "g", 1) == 0) + DEBUG_OFF (lsa, LSA_GENERATE); + else if (strncmp (argv[0], "f", 1) == 0) + DEBUG_OFF (lsa, LSA_FLOODING); + else if (strncmp (argv[0], "i", 1) == 0) + DEBUG_OFF (lsa, LSA_INSTALL); + else if (strncmp (argv[0], "r", 1) == 0) + DEBUG_OFF (lsa, LSA_REFRESH); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_OFF (lsa, LSA); + else if (argc == 1) + { + if (strncmp (argv[0], "g", 1) == 0) + TERM_DEBUG_OFF (lsa, LSA_GENERATE); + else if (strncmp (argv[0], "f", 1) == 0) + TERM_DEBUG_OFF (lsa, LSA_FLOODING); + else if (strncmp (argv[0], "i", 1) == 0) + TERM_DEBUG_OFF (lsa, LSA_INSTALL); + else if (strncmp (argv[0], "r", 1) == 0) + TERM_DEBUG_OFF (lsa, LSA_REFRESH); + } + + return CMD_SUCCESS; +} + +ALIAS (no_debug_ospf_lsa, + no_debug_ospf_lsa_sub_cmd, + "no debug ospf lsa (generate|flooding|install|refresh)", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF Link State Advertisement\n" + "LSA Generation\n" + "LSA Flooding\n" + "LSA Install/Delete\n" + "LSA Refres\n") + + +DEFUN (debug_ospf_zebra, + debug_ospf_zebra_cmd, + "debug ospf zebra", + DEBUG_STR + OSPF_STR + "OSPF Zebra information\n") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_ON (zebra, ZEBRA); + else if (argc == 1) + { + if (strncmp (argv[0], "i", 1) == 0) + DEBUG_ON (zebra, ZEBRA_INTERFACE); + else if (strncmp (argv[0], "r", 1) == 0) + DEBUG_ON (zebra, ZEBRA_REDISTRIBUTE); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_ON (zebra, ZEBRA); + else if (argc == 1) + { + if (strncmp (argv[0], "i", 1) == 0) + TERM_DEBUG_ON (zebra, ZEBRA_INTERFACE); + else if (strncmp (argv[0], "r", 1) == 0) + TERM_DEBUG_ON (zebra, ZEBRA_REDISTRIBUTE); + } + + return CMD_SUCCESS; +} + +ALIAS (debug_ospf_zebra, + debug_ospf_zebra_sub_cmd, + "debug ospf zebra (interface|redistribute)", + DEBUG_STR + OSPF_STR + "OSPF Zebra information\n" + "Zebra interface\n" + "Zebra redistribute\n") + +DEFUN (no_debug_ospf_zebra, + no_debug_ospf_zebra_cmd, + "no debug ospf zebra", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF Zebra information\n") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_OFF (zebra, ZEBRA); + else if (argc == 1) + { + if (strncmp (argv[0], "i", 1) == 0) + DEBUG_OFF (zebra, ZEBRA_INTERFACE); + else if (strncmp (argv[0], "r", 1) == 0) + DEBUG_OFF (zebra, ZEBRA_REDISTRIBUTE); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_OFF (zebra, ZEBRA); + else if (argc == 1) + { + if (strncmp (argv[0], "i", 1) == 0) + TERM_DEBUG_OFF (zebra, ZEBRA_INTERFACE); + else if (strncmp (argv[0], "r", 1) == 0) + TERM_DEBUG_OFF (zebra, ZEBRA_REDISTRIBUTE); + } + + return CMD_SUCCESS; +} + +ALIAS (no_debug_ospf_zebra, + no_debug_ospf_zebra_sub_cmd, + "no debug ospf zebra (interface|redistribute)", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF Zebra information\n" + "Zebra interface\n" + "Zebra redistribute\n") + +DEFUN (debug_ospf_event, + debug_ospf_event_cmd, + "debug ospf event", + DEBUG_STR + OSPF_STR + "OSPF event information\n") +{ + if (vty->node == CONFIG_NODE) + CONF_DEBUG_ON (event, EVENT); + TERM_DEBUG_ON (event, EVENT); + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf_event, + no_debug_ospf_event_cmd, + "no debug ospf event", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF event information\n") +{ + if (vty->node == CONFIG_NODE) + CONF_DEBUG_OFF (event, EVENT); + TERM_DEBUG_OFF (event, EVENT); + return CMD_SUCCESS; +} + +DEFUN (debug_ospf_nssa, + debug_ospf_nssa_cmd, + "debug ospf nssa", + DEBUG_STR + OSPF_STR + "OSPF nssa information\n") +{ + if (vty->node == CONFIG_NODE) + CONF_DEBUG_ON (nssa, NSSA); + TERM_DEBUG_ON (nssa, NSSA); + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf_nssa, + no_debug_ospf_nssa_cmd, + "no debug ospf nssa", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF nssa information\n") +{ + if (vty->node == CONFIG_NODE) + CONF_DEBUG_OFF (nssa, NSSA); + TERM_DEBUG_OFF (nssa, NSSA); + return CMD_SUCCESS; +} + + +DEFUN (show_debugging_ospf, + show_debugging_ospf_cmd, + "show debugging ospf", + SHOW_STR + DEBUG_STR + OSPF_STR) +{ + int i; + + vty_out (vty, "Zebra debugging status:%s", VTY_NEWLINE); + + /* Show debug status for ISM. */ + if (IS_DEBUG_OSPF (ism, ISM) == OSPF_DEBUG_ISM) + vty_out (vty, " OSPF ISM debugging is on%s", VTY_NEWLINE); + else + { + if (IS_DEBUG_OSPF (ism, ISM_STATUS)) + vty_out (vty, " OSPF ISM status debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (ism, ISM_EVENTS)) + vty_out (vty, " OSPF ISM event debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (ism, ISM_TIMERS)) + vty_out (vty, " OSPF ISM timer debugging is on%s", VTY_NEWLINE); + } + + /* Show debug status for NSM. */ + if (IS_DEBUG_OSPF (nsm, NSM) == OSPF_DEBUG_NSM) + vty_out (vty, " OSPF NSM debugging is on%s", VTY_NEWLINE); + else + { + if (IS_DEBUG_OSPF (nsm, NSM_STATUS)) + vty_out (vty, " OSPF NSM status debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (nsm, NSM_EVENTS)) + vty_out (vty, " OSPF NSM event debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (nsm, NSM_TIMERS)) + vty_out (vty, " OSPF NSM timer debugging is on%s", VTY_NEWLINE); + } + + /* Show debug status for OSPF Packets. */ + for (i = 0; i < 5; i++) + if (IS_DEBUG_OSPF_PACKET (i, SEND) && IS_DEBUG_OSPF_PACKET (i, RECV)) + { + vty_out (vty, " OSPF packet %s%s debugging is on%s", + ospf_packet_type_str[i + 1], + IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "", + VTY_NEWLINE); + } + else + { + if (IS_DEBUG_OSPF_PACKET (i, SEND)) + vty_out (vty, " OSPF packet %s send%s debugging is on%s", + ospf_packet_type_str[i + 1], + IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "", + VTY_NEWLINE); + if (IS_DEBUG_OSPF_PACKET (i, RECV)) + vty_out (vty, " OSPF packet %s receive%s debugging is on%s", + ospf_packet_type_str[i + 1], + IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "", + VTY_NEWLINE); + } + + /* Show debug status for OSPF LSAs. */ + if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) + vty_out (vty, " OSPF LSA debugging is on%s", VTY_NEWLINE); + else + { + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + vty_out (vty, " OSPF LSA generation debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + vty_out (vty, " OSPF LSA flooding debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) + vty_out (vty, " OSPF LSA install debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) + vty_out (vty, " OSPF LSA refresh debugging is on%s", VTY_NEWLINE); + } + + /* Show debug status for Zebra. */ + if (IS_DEBUG_OSPF (zebra, ZEBRA) == OSPF_DEBUG_ZEBRA) + vty_out (vty, " OSPF Zebra debugging is on%s", VTY_NEWLINE); + else + { + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + vty_out (vty, " OSPF Zebra interface debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + vty_out (vty, " OSPF Zebra redistribute debugging is on%s", VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +/* Debug node. */ +struct cmd_node debug_node = +{ + DEBUG_NODE, + "" +}; + +int +config_write_debug (struct vty *vty) +{ + int write = 0; + int i, r; + + char *type_str[] = {"hello", "dd", "ls-request", "ls-update", "ls-ack"}; + char *detail_str[] = {"", " send", " recv", "", " detail", + " send detail", " recv detail", " detail"}; + + /* debug ospf ism (status|events|timers). */ + if (IS_CONF_DEBUG_OSPF (ism, ISM) == OSPF_DEBUG_ISM) + vty_out (vty, "debug ospf ism%s", VTY_NEWLINE); + else + { + if (IS_CONF_DEBUG_OSPF (ism, ISM_STATUS)) + vty_out (vty, "debug ospf ism status%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (ism, ISM_EVENTS)) + vty_out (vty, "debug ospf ism event%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (ism, ISM_TIMERS)) + vty_out (vty, "debug ospf ism timer%s", VTY_NEWLINE); + } + + /* debug ospf nsm (status|events|timers). */ + if (IS_CONF_DEBUG_OSPF (nsm, NSM) == OSPF_DEBUG_NSM) + vty_out (vty, "debug ospf nsm%s", VTY_NEWLINE); + else + { + if (IS_CONF_DEBUG_OSPF (nsm, NSM_STATUS)) + vty_out (vty, "debug ospf ism status%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (nsm, NSM_EVENTS)) + vty_out (vty, "debug ospf nsm event%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (nsm, NSM_TIMERS)) + vty_out (vty, "debug ospf nsm timer%s", VTY_NEWLINE); + } + + /* debug ospf lsa (generate|flooding|install|refresh). */ + if (IS_CONF_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) + vty_out (vty, "debug ospf lsa%s", VTY_NEWLINE); + else + { + if (IS_CONF_DEBUG_OSPF (lsa, LSA_GENERATE)) + vty_out (vty, "debug ospf lsa generate%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (lsa, LSA_FLOODING)) + vty_out (vty, "debug ospf lsa flooding%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (lsa, LSA_INSTALL)) + vty_out (vty, "debug ospf lsa install%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (lsa, LSA_REFRESH)) + vty_out (vty, "debug ospf lsa refresh%s", VTY_NEWLINE); + + write = 1; + } + + /* debug ospf zebra (interface|redistribute). */ + if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA) == OSPF_DEBUG_ZEBRA) + vty_out (vty, "debug ospf zebra%s", VTY_NEWLINE); + else + { + if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + vty_out (vty, "debug ospf zebra interface%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + vty_out (vty, "debug ospf zebra redistribute%s", VTY_NEWLINE); + + write = 1; + } + + /* debug ospf event. */ + if (IS_CONF_DEBUG_OSPF (event, EVENT) == OSPF_DEBUG_EVENT) + { + vty_out (vty, "debug ospf event%s", VTY_NEWLINE); + write = 1; + } + + /* debug ospf nssa. */ + if (IS_CONF_DEBUG_OSPF (nssa, NSSA) == OSPF_DEBUG_NSSA) + { + vty_out (vty, "debug ospf nssa%s", VTY_NEWLINE); + write = 1; + } + + /* debug ospf packet all detail. */ + r = OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL; + for (i = 0; i < 5; i++) + r &= conf_debug_ospf_packet[i] & (OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL); + if (r == (OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL)) + { + vty_out (vty, "debug ospf packet all detail%s", VTY_NEWLINE); + return 1; + } + + /* debug ospf packet all. */ + r = OSPF_DEBUG_SEND_RECV; + for (i = 0; i < 5; i++) + r &= conf_debug_ospf_packet[i] & OSPF_DEBUG_SEND_RECV; + if (r == OSPF_DEBUG_SEND_RECV) + { + vty_out (vty, "debug ospf packet all%s", VTY_NEWLINE); + for (i = 0; i < 5; i++) + if (conf_debug_ospf_packet[i] & OSPF_DEBUG_DETAIL) + vty_out (vty, "debug ospf packet %s detail%s", + type_str[i], + VTY_NEWLINE); + return 1; + } + + /* debug ospf packet (hello|dd|ls-request|ls-update|ls-ack) + (send|recv) (detail). */ + for (i = 0; i < 5; i++) + { + if (conf_debug_ospf_packet[i] == 0) + continue; + + vty_out (vty, "debug ospf packet %s%s%s", + type_str[i], detail_str[conf_debug_ospf_packet[i]], + VTY_NEWLINE); + write = 1; + } + + return write; +} + +/* Initialize debug commands. */ +void +debug_init () +{ + install_node (&debug_node, config_write_debug); + + install_element (ENABLE_NODE, &show_debugging_ospf_cmd); + install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_detail_cmd); + install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_cmd); + install_element (ENABLE_NODE, &debug_ospf_packet_all_cmd); + install_element (ENABLE_NODE, &debug_ospf_ism_sub_cmd); + install_element (ENABLE_NODE, &debug_ospf_ism_cmd); + install_element (ENABLE_NODE, &debug_ospf_nsm_sub_cmd); + install_element (ENABLE_NODE, &debug_ospf_nsm_cmd); + install_element (ENABLE_NODE, &debug_ospf_lsa_sub_cmd); + install_element (ENABLE_NODE, &debug_ospf_lsa_cmd); + install_element (ENABLE_NODE, &debug_ospf_zebra_sub_cmd); + install_element (ENABLE_NODE, &debug_ospf_zebra_cmd); + install_element (ENABLE_NODE, &debug_ospf_event_cmd); +#ifdef HAVE_NSSA + install_element (ENABLE_NODE, &debug_ospf_nssa_cmd); +#endif /* HAVE_NSSA */ + install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_detail_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_packet_all_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_ism_sub_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_ism_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_nsm_sub_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_nsm_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_lsa_sub_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_lsa_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_zebra_sub_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_zebra_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_event_cmd); +#ifdef HAVE_NSSA + install_element (ENABLE_NODE, &no_debug_ospf_nssa_cmd); +#endif /* HAVE_NSSA */ + + install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_detail_cmd); + install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_cmd); + install_element (CONFIG_NODE, &debug_ospf_packet_all_cmd); + install_element (CONFIG_NODE, &debug_ospf_ism_sub_cmd); + install_element (CONFIG_NODE, &debug_ospf_ism_cmd); + install_element (CONFIG_NODE, &debug_ospf_nsm_sub_cmd); + install_element (CONFIG_NODE, &debug_ospf_nsm_cmd); + install_element (CONFIG_NODE, &debug_ospf_lsa_sub_cmd); + install_element (CONFIG_NODE, &debug_ospf_lsa_cmd); + install_element (CONFIG_NODE, &debug_ospf_zebra_sub_cmd); + install_element (CONFIG_NODE, &debug_ospf_zebra_cmd); + install_element (CONFIG_NODE, &debug_ospf_event_cmd); +#ifdef HAVE_NSSA + install_element (CONFIG_NODE, &debug_ospf_nssa_cmd); +#endif /* HAVE_NSSA */ + install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_detail_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_packet_all_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_ism_sub_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_ism_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_nsm_sub_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_nsm_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_lsa_sub_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_lsa_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_zebra_sub_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_zebra_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_event_cmd); +#ifdef HAVE_NSSA + install_element (CONFIG_NODE, &no_debug_ospf_nssa_cmd); +#endif /* HAVE_NSSA */ +} diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h new file mode 100644 index 00000000..804d5f70 --- /dev/null +++ b/ospfd/ospf_dump.h @@ -0,0 +1,139 @@ +/* + * OSPFd dump routine. + * Copyright (C) 1999 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_DUMP_H +#define _ZEBRA_OSPF_DUMP_H + +/* Debug Flags. */ +#define OSPF_DEBUG_HELLO 0x01 +#define OSPF_DEBUG_DB_DESC 0x02 +#define OSPF_DEBUG_LS_REQ 0x04 +#define OSPF_DEBUG_LS_UPD 0x08 +#define OSPF_DEBUG_LS_ACK 0x10 +#define OSPF_DEBUG_ALL 0x1f + +#define OSPF_DEBUG_SEND 0x01 +#define OSPF_DEBUG_RECV 0x02 +#define OSPF_DEBUG_SEND_RECV 0x03 +#define OSPF_DEBUG_DETAIL 0x04 + +#define OSPF_DEBUG_ISM_STATUS 0x01 +#define OSPF_DEBUG_ISM_EVENTS 0x02 +#define OSPF_DEBUG_ISM_TIMERS 0x04 +#define OSPF_DEBUG_ISM 0x07 +#define OSPF_DEBUG_NSM_STATUS 0x01 +#define OSPF_DEBUG_NSM_EVENTS 0x02 +#define OSPF_DEBUG_NSM_TIMERS 0x04 +#define OSPF_DEBUG_NSM 0x07 + +#define OSPF_DEBUG_LSA_GENERATE 0x01 +#define OSPF_DEBUG_LSA_FLOODING 0x02 +#define OSPF_DEBUG_LSA_INSTALL 0x04 +#define OSPF_DEBUG_LSA_REFRESH 0x08 +#define OSPF_DEBUG_LSA 0x0F + +#define OSPF_DEBUG_ZEBRA_INTERFACE 0x01 +#define OSPF_DEBUG_ZEBRA_REDISTRIBUTE 0x02 +#define OSPF_DEBUG_ZEBRA 0x03 + +#define OSPF_DEBUG_EVENT 0x01 +#define OSPF_DEBUG_NSSA 0x02 + +/* Macro for setting debug option. */ +#define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b) +#define CONF_DEBUG_PACKET_OFF(a, b) conf_debug_ospf_packet[a] &= ~(b) +#define TERM_DEBUG_PACKET_ON(a, b) term_debug_ospf_packet[a] |= (b) +#define TERM_DEBUG_PACKET_OFF(a, b) term_debug_ospf_packet[a] &= ~(b) +#define DEBUG_PACKET_ON(a, b) \ + do { \ + CONF_DEBUG_PACKET_ON(a, b); \ + TERM_DEBUG_PACKET_ON(a, b); \ + } while (0) +#define DEBUG_PACKET_OFF(a, b) \ + do { \ + CONF_DEBUG_PACKET_OFF(a, b); \ + TERM_DEBUG_PACKET_OFF(a, b); \ + } while (0) + +#define CONF_DEBUG_ON(a, b) conf_debug_ospf_ ## a |= (OSPF_DEBUG_ ## b) +#define CONF_DEBUG_OFF(a, b) conf_debug_ospf_ ## a &= ~(OSPF_DEBUG_ ## b) +#define TERM_DEBUG_ON(a, b) term_debug_ospf_ ## a |= (OSPF_DEBUG_ ## b) +#define TERM_DEBUG_OFF(a, b) term_debug_ospf_ ## a &= ~(OSPF_DEBUG_ ## b) +#define DEBUG_ON(a, b) \ + do { \ + CONF_DEBUG_ON(a, b); \ + TERM_DEBUG_ON(a, b); \ + } while (0) +#define DEBUG_OFF(a, b) \ + do { \ + CONF_DEBUG_OFF(a, b); \ + TERM_DEBUG_OFF(a, b); \ + } while (0) + +/* Macro for checking debug option. */ +#define IS_DEBUG_OSPF_PACKET(a, b) \ + (term_debug_ospf_packet[a] & OSPF_DEBUG_ ## b) +#define IS_DEBUG_OSPF(a, b) \ + (term_debug_ospf_ ## a & OSPF_DEBUG_ ## b) +#define IS_DEBUG_OSPF_EVENT IS_DEBUG_OSPF(event,EVENT) + +#define IS_DEBUG_OSPF_NSSA IS_DEBUG_OSPF(event,NSSA) + +#define IS_CONF_DEBUG_OSPF_PACKET(a, b) \ + (conf_debug_ospf_packet[a] & OSPF_DEBUG_ ## b) +#define IS_CONF_DEBUG_OSPF(a, b) \ + (conf_debug_ospf_ ## a & OSPF_DEBUG_ ## b) + +#ifdef ORIGINAL_CODING +#else /* ORIGINAL_CODING */ +struct stream; +#endif /* ORIGINAL_CODING */ + +#define AREA_NAME(A) ospf_area_name_string ((A)) +#define IF_NAME(I) ospf_if_name_string ((I)) + +/* Extern debug flag. */ +extern unsigned long term_debug_ospf_packet[]; +extern unsigned long term_debug_ospf_event; +extern unsigned long term_debug_ospf_ism; +extern unsigned long term_debug_ospf_nsm; +extern unsigned long term_debug_ospf_lsa; +extern unsigned long term_debug_ospf_zebra; +extern unsigned long term_debug_ospf_nssa; + +/* Message Strings. */ +extern char *ospf_packet_type_str[]; +extern char *ospf_lsa_type_str[]; + +/* Prototypes. */ +char *ospf_area_name_string (struct ospf_area *); +char *ospf_area_desc_string (struct ospf_area *); +char *ospf_if_name_string (struct ospf_interface *); +void ospf_nbr_state_message (struct ospf_neighbor *, char *, size_t); +char *ospf_options_dump (u_char); +char *ospf_timer_dump (struct thread *, char *, size_t); +void ospf_ip_header_dump (struct stream *); +void ospf_packet_dump (struct stream *); +void ospf_lsa_header_dump (struct lsa_header *); +void debug_init (); + +#endif /* _ZEBRA_OSPF_DUMP_H */ diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c new file mode 100644 index 00000000..bd33c345 --- /dev/null +++ b/ospfd/ospf_flood.c @@ -0,0 +1,1048 @@ +/* + * OSPF Flooding -- RFC2328 Section 13. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "command.h" +#include "table.h" +#include "thread.h" +#include "memory.h" +#include "log.h" +#include "zclient.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_dump.h" + +extern struct zclient *zclient; + +/* Do the LSA acking specified in table 19, Section 13.5, row 2 + * This get called from ospf_flood_out_interface. Declared inline + * for speed. */ +static void +ospf_flood_delayed_lsa_ack (struct ospf_neighbor *inbr, struct ospf_lsa *lsa) +{ + /* LSA is more recent than database copy, but was not + flooded back out receiving interface. Delayed + acknowledgment sent. If interface is in Backup state + delayed acknowledgment sent only if advertisement + received from Designated Router, otherwise do nothing See + RFC 2328 Section 13.5 */ + + /* Whether LSA is more recent or not, and whether this is in + response to the LSA being sent out recieving interface has been + worked out previously */ + + /* Deal with router as BDR */ + if (inbr->oi->state == ISM_Backup && ! NBR_IS_DR (inbr)) + return; + + /* Schedule a delayed LSA Ack to be sent */ + listnode_add (inbr->oi->ls_ack, ospf_lsa_lock (lsa)); +} + +/* Check LSA is related to external info. */ +struct external_info * +ospf_external_info_check (struct ospf_lsa *lsa) +{ + struct as_external_lsa *al; + struct prefix_ipv4 p; + struct route_node *rn; + int type; + + al = (struct as_external_lsa *) lsa->data; + + p.family = AF_INET; + p.prefix = lsa->data->id; + p.prefixlen = ip_masklen (al->mask); + + for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) + { + int redist_type = is_prefix_default (&p) ? DEFAULT_ROUTE : type; + if (ospf_is_type_redistributed (redist_type)) + if (EXTERNAL_INFO (type)) + { + rn = route_node_lookup (EXTERNAL_INFO (type), + (struct prefix *) &p); + if (rn) + { + route_unlock_node (rn); + if (rn->info != NULL) + return (struct external_info *) rn->info; + } + } + } + + return NULL; +} + +void +ospf_process_self_originated_lsa (struct ospf_lsa *new, struct ospf_area *area) +{ + struct ospf_interface *oi; + struct external_info *ei; + listnode node; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type%d:%s]: Process self-originated LSA", + new->data->type, inet_ntoa (new->data->id)); + + /* If we're here, we installed a self-originated LSA that we received + from a neighbor, i.e. it's more recent. We must see whether we want + to originate it. + If yes, we should use this LSA's sequence number and reoriginate + a new instance. + if not --- we must flush this LSA from the domain. */ + switch (new->data->type) + { + case OSPF_ROUTER_LSA: + /* Originate a new instance and schedule flooding */ + /* It shouldn't be necessary, but anyway */ + ospf_lsa_unlock (area->router_lsa_self); + area->router_lsa_self = ospf_lsa_lock (new); + + ospf_router_lsa_timer_add (area); + return; + case OSPF_NETWORK_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: +#endif /* HAVE_OPAQUE_LSA */ + /* We must find the interface the LSA could belong to. + If the interface is no more a broadcast type or we are no more + the DR, we flush the LSA otherwise -- create the new instance and + schedule flooding. */ + + /* Look through all interfaces, not just area, since interface + could be moved from one area to another. */ + for (node = listhead (ospf_top->oiflist); node; nextnode (node)) + /* These are sanity check. */ + if ((oi = getdata (node)) != NULL) + if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &new->data->id)) + { + if (oi->area != area || + oi->type != OSPF_IFTYPE_BROADCAST || + !IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))) + { + ospf_schedule_lsa_flush_area (area, new); + return; + } + +#ifdef HAVE_OPAQUE_LSA + if (new->data->type == OSPF_OPAQUE_LINK_LSA) + { + ospf_opaque_lsa_refresh (new); + return; + } +#endif /* HAVE_OPAQUE_LSA */ + + ospf_lsa_unlock (oi->network_lsa_self); + oi->network_lsa_self = ospf_lsa_lock (new); + + /* Schedule network-LSA origination. */ + ospf_network_lsa_timer_add (oi); + return; + } + break; + case OSPF_SUMMARY_LSA: + case OSPF_ASBR_SUMMARY_LSA: + ospf_schedule_abr_task (); + break; + case OSPF_AS_EXTERNAL_LSA : +#ifdef HAVE_NSSA + case OSPF_AS_NSSA_LSA: +#endif /* HAVE_NSSA */ + ei = ospf_external_info_check (new); + if (ei) + ospf_external_lsa_refresh (new, ei, LSA_REFRESH_FORCE); + else + ospf_lsa_flush_as (new); + break; +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AREA_LSA: + ospf_opaque_lsa_refresh (new); + break; + case OSPF_OPAQUE_AS_LSA: + ospf_opaque_lsa_refresh (new); /* Reconsideration may needed. *//* XXX */ + break; +#endif /* HAVE_OPAQUE_LSA */ + default: + break; + } +} + +/* OSPF LSA flooding -- RFC2328 Section 13.(5). */ + +/* Now Updated for NSSA operation, as follows: + + + Type-5's have no change. Blocked to STUB or NSSA. + + Type-7's can be received, and if a DR + they will also flood the local NSSA Area as Type-7's + + If a Self-Originated LSA (now an ASBR), + The LSDB will be updated as Type-5's, (for continual re-fresh) + + If an NSSA-IR it is installed/flooded as Type-7, P-bit on. + if an NSSA-ABR it is installed/flooded as Type-7, P-bit off. + + Later, during the ABR TASK, if the ABR is the Elected NSSA + translator, then All Type-7s (with P-bit ON) are Translated to + Type-5's and flooded to all non-NSSA/STUB areas. + + During ASE Calculations, + non-ABRs calculate external routes from Type-7's + ABRs calculate external routes from Type-5's and non-self Type-7s +*/ +int +ospf_flood (struct ospf_neighbor *nbr, struct ospf_lsa *current, + struct ospf_lsa *new) +{ + struct ospf_interface *oi; + struct timeval now; + int lsa_ack_flag; + + /* Type-7 LSA's will be flooded throughout their native NSSA area, + but will also be flooded as Type-5's into ABR capable links. */ + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Flooding]: start, NBR %s (%s), cur(%p), New-LSA[%s]", + inet_ntoa (nbr->router_id), + LOOKUP (ospf_nsm_state_msg, nbr->state), + current, + dump_lsa_key (new)); + + lsa_ack_flag = 0; + oi = nbr->oi; + + /* Get current time. */ + gettimeofday (&now, NULL); + + /* If there is already a database copy, and if the + database copy was received via flooding and installed less + than MinLSArrival seconds ago, discard the new LSA + (without acknowledging it). */ + if (current != NULL) /* -- endo. */ + { + if (IS_LSA_SELF (current) + && (ntohs (current->data->ls_age) == 0 + && ntohl (current->data->ls_seqnum) == OSPF_INITIAL_SEQUENCE_NUMBER)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Flooding]: Got a self-originated LSA, " + "while local one is initial instance."); + ; /* Accept this LSA for quick LSDB resynchronization. */ + } + else if (tv_cmp (tv_sub (now, current->tv_recv), + int2tv (OSPF_MIN_LS_ARRIVAL)) < 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Flooding]: LSA is received recently."); + return -1; + } + } + + /* Flood the new LSA out some subset of the router's interfaces. + In some cases (e.g., the state of the receiving interface is + DR and the LSA was received from a router other than the + Backup DR) the LSA will be flooded back out the receiving + interface. */ + lsa_ack_flag = ospf_flood_through (nbr, new); + +#ifdef HAVE_OPAQUE_LSA + /* Remove the current database copy from all neighbors' Link state + retransmission lists. AS_EXTERNAL and AS_EXTERNAL_OPAQUE does + ^^^^^^^^^^^^^^^^^^^^^^^ + not have area ID. + All other (even NSSA's) do have area ID. */ +#else /* HAVE_OPAQUE_LSA */ + /* Remove the current database copy from all neighbors' Link state + retransmission lists. Only AS_EXTERNAL does not have area ID. + All other (even NSSA's) do have area ID. */ +#endif /* HAVE_OPAQUE_LSA */ + if (current) + { + switch (current->data->type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + ospf_ls_retransmit_delete_nbr_all (NULL, current); + break; + default: + ospf_ls_retransmit_delete_nbr_all (nbr->oi->area, current); + break; + } + } + + /* Do some internal house keeping that is needed here */ + SET_FLAG (new->flags, OSPF_LSA_RECEIVED); + ospf_lsa_is_self_originated (new); /* Let it set the flag */ + + /* Install the new LSA in the link state database + (replacing the current database copy). This may cause the + routing table calculation to be scheduled. In addition, + timestamp the new LSA with the current time. The flooding + procedure cannot overwrite the newly installed LSA until + MinLSArrival seconds have elapsed. */ + + new = ospf_lsa_install (nbr->oi, new); + +#ifdef HAVE_NSSA + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("LSA[Flooding]: Type-%d installed", new->data->type); + + /* if (new->data->type == OSPF_AS_NSSA_LSA ) + return 0; */ +#endif /* HAVE_NSSA */ + + /* Acknowledge the receipt of the LSA by sending a Link State + Acknowledgment packet back out the receiving interface. */ + if (lsa_ack_flag) + ospf_flood_delayed_lsa_ack (nbr, new); + + /* If this new LSA indicates that it was originated by the + receiving router itself, the router must take special action, + either updating the LSA or in some cases flushing it from + the routing domain. */ + if (ospf_lsa_is_self_originated (new)) + ospf_process_self_originated_lsa (new, oi->area); + else + /* Update statistics value for OSPF-MIB. */ + ospf_top->rx_lsa_count++; + + return 0; +} + +/* OSPF LSA flooding -- RFC2328 Section 13.3. */ +int +ospf_flood_through_interface (struct ospf_interface *oi, + struct ospf_neighbor *inbr, + struct ospf_lsa *lsa) +{ + struct ospf_neighbor *onbr; + struct route_node *rn; + int retx_flag; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_flood_through_interface(): " + "considering int %s, INBR(%s), LSA[%s]", + IF_NAME (oi), inbr ? inet_ntoa (inbr->router_id) : "NULL", + dump_lsa_key (lsa)); + + if (!ospf_if_is_enable (oi)) + return 0; + + /* Remember if new LSA is aded to a retransmit list. */ + retx_flag = 0; + + /* Each of the neighbors attached to this interface are examined, + to determine whether they must receive the new LSA. The following + steps are executed for each neighbor: */ + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + { + struct ospf_lsa *ls_req; + + if (rn->info == NULL) + continue; + + onbr = rn->info; + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_flood_through_interface(): considering nbr %s (%s)", + inet_ntoa (onbr->router_id), + LOOKUP (ospf_nsm_state_msg, onbr->state)); + + /* If the neighbor is in a lesser state than Exchange, it + does not participate in flooding, and the next neighbor + should be examined. */ + if (onbr->state < NSM_Exchange) + continue; + + /* If the adjacency is not yet full (neighbor state is + Exchange or Loading), examine the Link state request + list associated with this adjacency. If there is an + instance of the new LSA on the list, it indicates that + the neighboring router has an instance of the LSA + already. Compare the new LSA to the neighbor's copy: */ + if (onbr->state < NSM_Full) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_flood_through_interface(): nbr adj is not Full"); + ls_req = ospf_ls_request_lookup (onbr, lsa); + if (ls_req != NULL) + { + int ret; + + ret = ospf_lsa_more_recent (ls_req, lsa); + /* The new LSA is less recent. */ + if (ret > 0) + continue; + /* The two copies are the same instance, then delete + the LSA from the Link state request list. */ + else if (ret == 0) + { + ospf_ls_request_delete (onbr, ls_req); + ospf_check_nbr_loading (onbr); + continue; + } + /* The new LSA is more recent. Delete the LSA + from the Link state request list. */ + else + { + ospf_ls_request_delete (onbr, ls_req); + ospf_check_nbr_loading (onbr); + } + } + } + +#ifdef HAVE_OPAQUE_LSA + if (IS_OPAQUE_LSA (lsa->data->type)) + { + if (! CHECK_FLAG (onbr->options, OSPF_OPTION_O)) + { + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("Skip this neighbor: Not Opaque-capable."); + continue; + } + + if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (ospf_top->opaque) + && IS_LSA_SELF (lsa) + && onbr->state == NSM_Full) + { + /* Small attempt to reduce unnecessary retransmission. */ + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("Skip this neighbor: Initial flushing done."); + continue; + } + } +#endif /* HAVE_OPAQUE_LSA */ + + /* If the new LSA was received from this neighbor, + examine the next neighbor. */ +#ifdef ORIGINAL_CODING + if (inbr) + if (IPV4_ADDR_SAME (&inbr->router_id, &onbr->router_id)) + continue; +#else /* ORIGINAL_CODING */ + if (inbr) + { + /* + * Triggered by LSUpd message parser "ospf_ls_upd ()". + * E.g., all LSAs handling here is received via network. + */ + if (IPV4_ADDR_SAME (&inbr->router_id, &onbr->router_id)) + { + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("Skip this neighbor: inbr == onbr"); + continue; + } + } + else + { + /* + * Triggered by MaxAge remover, so far. + * NULL "inbr" means flooding starts from this node. + */ + if (IPV4_ADDR_SAME (&lsa->data->adv_router, &onbr->router_id)) + { + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("Skip this neighbor: lsah->adv_router == onbr"); + continue; + } + } +#endif /* ORIGINAL_CODING */ + + /* Add the new LSA to the Link state retransmission list + for the adjacency. The LSA will be retransmitted + at intervals until an acknowledgment is seen from + the neighbor. */ + ospf_ls_retransmit_add (onbr, lsa); + retx_flag = 1; + } + + /* If in the previous step, the LSA was NOT added to any of + the Link state retransmission lists, there is no need to + flood the LSA out the interface. */ + if (retx_flag == 0) + { + return (inbr && inbr->oi == oi); + } + + /* if we've received the lsa on this interface we need to perform + additional checking */ + if (inbr && (inbr->oi == oi)) + { + /* If the new LSA was received on this interface, and it was + received from either the Designated Router or the Backup + Designated Router, chances are that all the neighbors have + received the LSA already. */ + if (NBR_IS_DR (inbr) || NBR_IS_BDR (inbr)) + { +#ifdef HAVE_NSSA + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_flood_through_interface(): " + "DR/BDR NOT SEND to int %s", IF_NAME (oi)); +#endif /* HAVE_NSSA */ + return 1; + } + + /* If the new LSA was received on this interface, and the + interface state is Backup, examine the next interface. The + Designated Router will do the flooding on this interface. + However, if the Designated Router fails the router will + end up retransmitting the updates. */ + + if (oi->state == ISM_Backup) + { +#ifdef HAVE_NSSA + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_flood_through_interface(): " + "ISM_Backup NOT SEND to int %s", IF_NAME (oi)); +#endif /* HAVE_NSSA */ + return 1; + } + } + + /* The LSA must be flooded out the interface. Send a Link State + Update packet (including the new LSA as contents) out the + interface. The LSA's LS age must be incremented by InfTransDelay + (which must be > 0) when it is copied into the outgoing Link + State Update packet (until the LS age field reaches the maximum + value of MaxAge). */ + +#ifdef HAVE_NSSA + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_flood_through_interface(): " + "DR/BDR sending upd to int %s", IF_NAME (oi)); +#else /* ! HAVE_NSSA */ + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_flood_through_interface(): " + "sending upd to int %s", IF_NAME (oi)); +#endif /* HAVE_NSSA */ + + /* RFC2328 Section 13.3 + On non-broadcast networks, separate Link State Update + packets must be sent, as unicasts, to each adjacent neighbor + (i.e., those in state Exchange or greater). The destination + IP addresses for these packets are the neighbors' IP + addresses. */ + if (oi->type == OSPF_IFTYPE_NBMA) + { + struct route_node *rn; + struct ospf_neighbor *nbr; + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL) + if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange) + ospf_ls_upd_send_lsa (nbr, lsa, OSPF_SEND_PACKET_DIRECT); + } + else + ospf_ls_upd_send_lsa (oi->nbr_self, lsa, OSPF_SEND_PACKET_INDIRECT); + + return 0; +} + +int +ospf_flood_through_area (struct ospf_area * area,struct ospf_neighbor *inbr, + struct ospf_lsa *lsa) +{ + listnode node; + int lsa_ack_flag = 0; + + /* All other types are specific to a single area (Area A). The + eligible interfaces are all those interfaces attaching to the + Area A. If Area A is the backbone, this includes all the virtual + links. */ + for (node = listhead (area->oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + + if (area->area_id.s_addr != OSPF_AREA_BACKBONE && + oi->type == OSPF_IFTYPE_VIRTUALLINK) + continue; + +#ifdef HAVE_OPAQUE_LSA + if ((lsa->data->type == OSPF_OPAQUE_LINK_LSA) && (lsa->oi != oi)) + { + /* + * Link local scoped Opaque-LSA should only be flooded + * for the link on which the LSA has received. + */ + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("Type-9 Opaque-LSA: lsa->oi(%p) != oi(%p)", lsa->oi, oi); + continue; + } +#endif /* HAVE_OPAQUE_LSA */ + + if (ospf_flood_through_interface (oi, inbr, lsa)) + lsa_ack_flag = 1; + } + + return (lsa_ack_flag); +} + +int +ospf_flood_through_as (struct ospf_neighbor *inbr, struct ospf_lsa *lsa) +{ + listnode node; + int lsa_ack_flag; + + lsa_ack_flag = 0; + + /* The incoming LSA is type 5 or type 7 (AS-EXTERNAL or AS-NSSA ) + + Divert the Type-5 LSA's to all non-NSSA/STUB areas + + Divert the Type-7 LSA's to all NSSA areas + + AS-external-LSAs are flooded throughout the entire AS, with the + exception of stub areas (see Section 3.6). The eligible + interfaces are all the router's interfaces, excluding virtual + links and those interfaces attaching to stub areas. */ + +#ifdef HAVE_NSSA + if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) /* Translated from 7 */ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("Flood/AS: NSSA TRANSLATED LSA"); +#endif /* HAVE_NSSA */ + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + int continue_flag = 0; + struct ospf_area *area = getdata (node); + listnode if_node; + + switch (area->external_routing) + { + /* Don't send AS externals into stub areas. Various types + of support for partial stub areas can be implemented + here. NSSA's will receive Type-7's that have areas + matching the originl LSA. */ + case OSPF_AREA_NSSA: /* Sending Type 5 or 7 into NSSA area */ +#ifdef HAVE_NSSA + /* Type-7, flood NSSA area */ + if (lsa->data->type == OSPF_AS_NSSA_LSA) + /* We will send it. */ + continue_flag = 0; + else + continue_flag = 1; /* Skip this NSSA area for Type-5's et al */ + break; +#endif /* HAVE_NSSA */ + + case OSPF_AREA_TYPE_MAX: + case OSPF_AREA_STUB: + continue_flag = 1; /* Skip this area. */ + break; + + case OSPF_AREA_DEFAULT: + default: +#ifdef HAVE_NSSA + /* No Type-7 into normal area */ + if (lsa->data->type == OSPF_AS_NSSA_LSA) + continue_flag = 1; /* skip Type-7 */ + else +#endif /* HAVE_NSSA */ + continue_flag = 0; /* Do this area. */ + break; + } + + /* Do continue for above switch. Saves a big if then mess */ + if (continue_flag) + continue; /* main for-loop */ + + /* send to every interface in this area */ + + for (if_node = listhead (area->oiflist); if_node; nextnode (if_node)) + { + struct ospf_interface *oi = getdata (if_node); + + /* Skip virtual links */ + if (oi->type != OSPF_IFTYPE_VIRTUALLINK) + if (ospf_flood_through_interface (oi, inbr, lsa)) /* lsa */ + lsa_ack_flag = 1; + } + } /* main area for-loop */ + + return (lsa_ack_flag); +} + +int +ospf_flood_through (struct ospf_neighbor *inbr, struct ospf_lsa *lsa) +{ + int lsa_ack_flag = 0; + + /* Type-7 LSA's for NSSA are flooded throughout the AS here, and + upon return are updated in the LSDB for Type-7's. Later, + re-fresh will re-send them (and also, if ABR, packet code will + translate to Type-5's) + + As usual, Type-5 LSA's (if not DISCARDED because we are STUB or + NSSA) are flooded throughout the AS, and are updated in the + global table. */ +#ifdef ORIGINAL_CODING + switch (lsa->data->type) + { + case OSPF_ROUTER_LSA: + case OSPF_NETWORK_LSA: + case OSPF_SUMMARY_LSA: + case OSPF_ASBR_SUMMARY_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: /* ospf_flood_through_interface ? */ + case OSPF_OPAQUE_AREA_LSA: +#endif /* HAVE_OPAQUE_LSA */ + lsa_ack_flag = ospf_flood_through_area (inbr->oi->area, inbr, lsa); + break; + case OSPF_AS_EXTERNAL_LSA: /* Type-5 */ +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + lsa_ack_flag = ospf_flood_through_as (inbr, lsa); + break; +#ifdef HAVE_NSSA + /* Type-7 Only received within NSSA, then flooded */ + case OSPF_AS_NSSA_LSA: + /* Any P-bit was installed with the Type-7. */ + lsa_ack_flag = ospf_flood_through_area (inbr->oi->area, inbr, lsa); + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_flood_through: LOCAL NSSA FLOOD of Type-7."); + break; +#endif /* HAVE_NSSA */ + default: + break; + } +#else /* ORIGINAL_CODING */ + /* + * At the common sub-sub-function "ospf_flood_through_interface()", + * a parameter "inbr" will be used to distinguish the called context + * whether the given LSA was received from the neighbor, or the + * flooding for the LSA starts from this node (e.g. the LSA was self- + * originated, or the LSA is going to be flushed from routing domain). + * + * So, for consistency reasons, this function "ospf_flood_through()" + * should also allow the usage that the given "inbr" parameter to be + * NULL. If we do so, corresponding AREA parameter should be referred + * by "lsa->area", instead of "inbr->oi->area". + */ + switch (lsa->data->type) + { + case OSPF_AS_EXTERNAL_LSA: /* Type-5 */ +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + lsa_ack_flag = ospf_flood_through_as (inbr, lsa); + break; +#ifdef HAVE_NSSA + /* Type-7 Only received within NSSA, then flooded */ + case OSPF_AS_NSSA_LSA: + /* Any P-bit was installed with the Type-7. */ + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_flood_through: LOCAL NSSA FLOOD of Type-7."); + /* Fallthrough */ +#endif /* HAVE_NSSA */ + default: + lsa_ack_flag = ospf_flood_through_area (lsa->area, inbr, lsa); + break; + } +#endif /* ORIGINAL_CODING */ + + return (lsa_ack_flag); +} + + + +/* Management functions for neighbor's Link State Request list. */ +void +ospf_ls_request_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + /* + * We cannot make use of the newly introduced callback function + * "lsdb->new_lsa_hook" to replace debug output below, just because + * it seems no simple and smart way to pass neighbor information to + * the common function "ospf_lsdb_add()" -- endo. + */ + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("RqstL(%lu)++, NBR(%s), LSA[%s]", + ospf_ls_request_count (nbr), + inet_ntoa (nbr->router_id), dump_lsa_key (lsa)); + + ospf_lsdb_add (&nbr->ls_req, lsa); +} + +unsigned long +ospf_ls_request_count (struct ospf_neighbor *nbr) +{ + return ospf_lsdb_count_all (&nbr->ls_req); +} + +int +ospf_ls_request_isempty (struct ospf_neighbor *nbr) +{ + return ospf_lsdb_isempty (&nbr->ls_req); +} + +/* Remove LSA from neighbor's ls-request list. */ +void +ospf_ls_request_delete (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + if (nbr->ls_req_last == lsa) + { + ospf_lsa_unlock (nbr->ls_req_last); + nbr->ls_req_last = NULL; + } + + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) /* -- endo. */ + zlog_info ("RqstL(%lu)--, NBR(%s), LSA[%s]", + ospf_ls_request_count (nbr), + inet_ntoa (nbr->router_id), dump_lsa_key (lsa)); + + ospf_lsdb_delete (&nbr->ls_req, lsa); +} + +/* Remove all LSA from neighbor's ls-requenst list. */ +void +ospf_ls_request_delete_all (struct ospf_neighbor *nbr) +{ + ospf_lsa_unlock (nbr->ls_req_last); + nbr->ls_req_last = NULL; + ospf_lsdb_delete_all (&nbr->ls_req); +} + +/* Lookup LSA from neighbor's ls-request list. */ +struct ospf_lsa * +ospf_ls_request_lookup (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + return ospf_lsdb_lookup (&nbr->ls_req, lsa); +} + +struct ospf_lsa * +ospf_ls_request_new (struct lsa_header *lsah) +{ + struct ospf_lsa *new; + + new = ospf_lsa_new (); + new->data = ospf_lsa_data_new (OSPF_LSA_HEADER_SIZE); + memcpy (new->data, lsah, OSPF_LSA_HEADER_SIZE); + + return new; +} + + +/* Management functions for neighbor's ls-retransmit list. */ +unsigned long +ospf_ls_retransmit_count (struct ospf_neighbor *nbr) +{ + return ospf_lsdb_count_all (&nbr->ls_rxmt); +} + +unsigned long +ospf_ls_retransmit_count_self (struct ospf_neighbor *nbr, int lsa_type) +{ + return ospf_lsdb_count_self (&nbr->ls_rxmt, lsa_type); +} + +int +ospf_ls_retransmit_isempty (struct ospf_neighbor *nbr) +{ + return ospf_lsdb_isempty (&nbr->ls_rxmt); +} + +/* Add LSA to be retransmitted to neighbor's ls-retransmit list. */ +void +ospf_ls_retransmit_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + struct ospf_lsa *old; + + old = ospf_ls_retransmit_lookup (nbr, lsa); + + if (ospf_lsa_more_recent (old, lsa) < 0) + { + if (old) + { + old->retransmit_counter--; + ospf_lsdb_delete (&nbr->ls_rxmt, old); + } + lsa->retransmit_counter++; + /* + * We cannot make use of the newly introduced callback function + * "lsdb->new_lsa_hook" to replace debug output below, just because + * it seems no simple and smart way to pass neighbor information to + * the common function "ospf_lsdb_add()" -- endo. + */ + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("RXmtL(%lu)++, NBR(%s), LSA[%s]", + ospf_ls_retransmit_count (nbr), + inet_ntoa (nbr->router_id), dump_lsa_key (lsa)); + ospf_lsdb_add (&nbr->ls_rxmt, lsa); + } +} + +/* Remove LSA from neibghbor's ls-retransmit list. */ +void +ospf_ls_retransmit_delete (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + if (ospf_ls_retransmit_lookup (nbr, lsa)) + { + lsa->retransmit_counter--; + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) /* -- endo. */ + zlog_info ("RXmtL(%lu)--, NBR(%s), LSA[%s]", + ospf_ls_retransmit_count (nbr), + inet_ntoa (nbr->router_id), dump_lsa_key (lsa)); + ospf_lsdb_delete (&nbr->ls_rxmt, lsa); + } +} + +/* Clear neighbor's ls-retransmit list. */ +void +ospf_ls_retransmit_clear (struct ospf_neighbor *nbr) +{ + struct ospf_lsdb *lsdb; + int i; + + lsdb = &nbr->ls_rxmt; + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + { + struct route_table *table = lsdb->type[i].db; + struct route_node *rn; + struct ospf_lsa *lsa; + + for (rn = route_top (table); rn; rn = route_next (rn)) + if ((lsa = rn->info) != NULL) + ospf_ls_retransmit_delete (nbr, lsa); + } + + ospf_lsa_unlock (nbr->ls_req_last); + nbr->ls_req_last = NULL; +} + +/* Lookup LSA from neighbor's ls-retransmit list. */ +struct ospf_lsa * +ospf_ls_retransmit_lookup (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + return ospf_lsdb_lookup (&nbr->ls_rxmt, lsa); +} + +/* Remove All neighbor/interface's Link State Retransmit list in area. */ +void +ospf_ls_retransmit_delete_nbr_all (struct ospf_area *area, + struct ospf_lsa *lsa) +{ + listnode node; + list oiflist = area ? area->oiflist : ospf_top->oiflist; + + for (node = listhead (oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + struct route_node *rn; + struct ospf_neighbor *nbr; + struct ospf_lsa *lsr; + + if (ospf_if_is_enable (oi)) + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + /* If LSA find in LS-retransmit list, then remove it. */ + if ((nbr = rn->info) != NULL) + { + lsr = ospf_ls_retransmit_lookup (nbr, lsa); + + /* If LSA find in ls-retransmit list, remove it. */ + if (lsr != NULL && lsr->data->ls_seqnum == lsa->data->ls_seqnum) + ospf_ls_retransmit_delete (nbr, lsr); + } + } +} + +/* Add LSA to the current database copy of all neighbors' + Link state retransmission lists. */ +void +ospf_ls_retransmit_add_nbr_all (struct ospf_interface *ospfi, + struct ospf_lsa *lsa) +{ + listnode node; + + for (node = listhead (ospf_top->oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + struct route_node *rn; + struct ospf_neighbor *nbr; + struct ospf_lsa *old; + + if (ospf_if_is_enable (oi)) + if (OSPF_AREA_SAME (&ospfi->area, &oi->area)) + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL) + if (nbr->state == NSM_Full) + { + if ((old = ospf_ls_retransmit_lookup (nbr, lsa))) + ospf_ls_retransmit_delete (nbr, old); + + ospf_ls_retransmit_add (nbr, lsa); + } + } +} + + +/* Sets ls_age to MaxAge and floods throu the area. + When we implement ASE routing, there will be anothe function + flushing an LSA from the whole domain. */ +void +ospf_lsa_flush_area (struct ospf_lsa *lsa, struct ospf_area *area) +{ + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); + ospf_flood_through_area (area, NULL, lsa); + ospf_lsa_maxage (lsa); +} + +void +ospf_lsa_flush_as (struct ospf_lsa *lsa) +{ + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); + ospf_flood_through_as (NULL, lsa); + ospf_lsa_maxage (lsa); +} + +/* Flush LSA through AS -- used for AS-external-LSAs. */ +void +ospf_flush_through_as (struct ospf_lsa *lsa) +{ + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); + ospf_flood_through_as (NULL, lsa); + ospf_lsa_maxage (lsa); +} diff --git a/ospfd/ospf_flood.h b/ospfd/ospf_flood.h new file mode 100644 index 00000000..1a6ab979 --- /dev/null +++ b/ospfd/ospf_flood.h @@ -0,0 +1,65 @@ +/* + * OSPF Flooding -- RFC2328 Section 13. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_FLOODING_H +#define _ZEBRA_OSPF_FLOODING_H + +int ospf_flood (struct ospf_neighbor *, struct ospf_lsa *, struct ospf_lsa *); +int ospf_flood_through (struct ospf_neighbor *, struct ospf_lsa *); +int ospf_flood_through_area (struct ospf_area *, struct ospf_neighbor *, + struct ospf_lsa *); +int ospf_flood_through_as (struct ospf_neighbor *, struct ospf_lsa *); + +unsigned long ospf_ls_request_count (struct ospf_neighbor *); +int ospf_ls_request_isempty (struct ospf_neighbor *); +struct ospf_lsa *ospf_ls_request_new (struct lsa_header *); +void ospf_ls_request_free (struct ospf_lsa *); +void ospf_ls_request_add (struct ospf_neighbor *, struct ospf_lsa *); +void ospf_ls_request_delete (struct ospf_neighbor *, struct ospf_lsa *); +void ospf_ls_request_delete_all (struct ospf_neighbor *); +struct ospf_lsa *ospf_ls_request_lookup (struct ospf_neighbor *, + struct ospf_lsa *); + +unsigned long ospf_ls_retransmit_count (struct ospf_neighbor *); +unsigned long ospf_ls_retransmit_count_self (struct ospf_neighbor *, int); +int ospf_ls_retransmit_isempty (struct ospf_neighbor *); +void ospf_ls_retransmit_add (struct ospf_neighbor *, struct ospf_lsa *); +void ospf_ls_retransmit_delete (struct ospf_neighbor *, struct ospf_lsa *); +void ospf_ls_retransmit_clear (struct ospf_neighbor *); +struct ospf_lsa *ospf_ls_retransmit_lookup (struct ospf_neighbor *, + struct ospf_lsa *); +void ospf_ls_retransmit_delete_nbr_all (struct ospf_area *, struct ospf_lsa *); +void ospf_ls_retransmit_add_nbr_all (struct ospf_interface *, + struct ospf_lsa *); + +void ospf_flood_lsa_area (struct ospf_lsa *, struct ospf_area *); +void ospf_flood_lsa_as (struct ospf_lsa *); +void ospf_lsa_flush_area (struct ospf_lsa *, struct ospf_area *); +void ospf_lsa_flush_as (struct ospf_lsa *); +void ospf_flush_through_as (struct ospf_lsa *); +struct external_info *ospf_external_info_check (struct ospf_lsa *); + +void debug_ospf_ls_retransmit (struct ospf_neighbor *); + +void ospf_lsdb_init (struct ospf_lsdb *); + +#endif /* _ZEBRA_OSPF_FLOODING_H */ diff --git a/ospfd/ospf_ia.c b/ospfd/ospf_ia.c new file mode 100644 index 00000000..32c8d86b --- /dev/null +++ b/ospfd/ospf_ia.c @@ -0,0 +1,726 @@ +/* + * OSPF inter-area routing. + * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + + +#include + +#include "thread.h" +#include "memory.h" +#include "hash.h" +#include "linklist.h" +#include "prefix.h" +#include "table.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_ia.h" +#include "ospfd/ospf_dump.h" + +#define DEBUG + +struct ospf_route * +ospf_find_abr_route (struct route_table *rtrs, + struct prefix_ipv4 *abr, + struct ospf_area *area) +{ + struct route_node *rn; + struct ospf_route *or; + listnode node; + + if ((rn = route_node_lookup (rtrs, (struct prefix *) abr)) == NULL) + return NULL; + + route_unlock_node (rn); + + for (node = listhead ((list) rn->info); node; nextnode (node)) + if ((or = getdata (node)) != NULL) + if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id) && (or->u.std.flags & ROUTER_LSA_BORDER)) + return or; + + return NULL; +} + +void +ospf_ia_network_route (struct route_table *rt, struct prefix_ipv4 *p, + struct ospf_route *new_or, struct ospf_route *abr_or) +{ + struct route_node *rn1; + struct ospf_route *or; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_network_route(): processing summary route to %s/%d", + inet_ntoa (p->prefix), p->prefixlen); + + /* Find a route to the same dest */ + if ((rn1 = route_node_lookup (rt, (struct prefix *) p))) + { + int res; + + route_unlock_node (rn1); + + if ((or = rn1->info)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_network_route(): " + "Found a route to the same network"); + /* Check the existing route. */ + if ((res = ospf_route_cmp (new_or, or)) < 0) + { + /* New route is better, so replace old one. */ + ospf_route_subst (rn1, new_or, abr_or); + } + else if (res == 0) + { + /* New and old route are equal, so next hops can be added. */ + route_lock_node (rn1); + ospf_route_copy_nexthops (or, abr_or->path); + route_unlock_node (rn1); + + /* new route can be deleted, because existing route has been updated. */ + ospf_route_free (new_or); + } + else + { + /* New route is worse, so free it. */ + ospf_route_free (new_or); + return; + } + } /* if (or)*/ + } /*if (rn1)*/ + else + { /* no route */ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_network_route(): add new route to %s/%d", + inet_ntoa (p->prefix), p->prefixlen); + ospf_route_add (rt, p, new_or, abr_or); + } +} + +void +ospf_ia_router_route (struct route_table *rt, struct prefix_ipv4 *p, + struct ospf_route *new_or, struct ospf_route *abr_or) +{ + struct route_node *rn; + struct ospf_route *or = NULL; + int ret; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_router_route(): considering %s/%d", + inet_ntoa (p->prefix), p->prefixlen); + /* Find a route to the same dest */ + rn = route_node_get (rt,(struct prefix *) p); + + if (rn->info == NULL) + /* This is a new route */ + rn->info = list_new (); + else + { + struct ospf_area *or_area; + or_area = ospf_area_lookup_by_area_id (new_or->u.std.area_id); + assert (or_area); + /* This is an additional route */ + route_unlock_node (rn); + or = ospf_find_asbr_route_through_area (rt, p, or_area); + } + + if (or) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_router_route(): " + "a route to the same ABR through the same area exists"); + /* New route is better */ + if ((ret = ospf_route_cmp (new_or, or)) < 0) + { + listnode_delete (rn->info, or); + ospf_route_free (or); + /* proceed down */ + } + /* Routes are the same */ + else if (ret == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_router_route(): merging the new route"); + + ospf_route_copy_nexthops (or, abr_or->path); + ospf_route_free (new_or); + return; + } + /* New route is worse */ + else + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_router_route(): skipping the new route"); + ospf_route_free (new_or); + return; + } + } + + ospf_route_copy_nexthops (new_or, abr_or->path); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_router_route(): adding the new route"); + + listnode_add (rn->info, new_or); +} + + +struct ia_args +{ + struct route_table *rt; + struct route_table *rtrs; + struct ospf_area *area; +}; + +int +process_summary_lsa (struct ospf_lsa *l, void *v, int i) +{ + struct ospf_area_range *range; + struct ospf_route *abr_or, *new_or; + struct summary_lsa *sl; + struct prefix_ipv4 p, abr; + u_int32_t metric; + struct ia_args *args; + + if (l == NULL) + return 0; + + args = (struct ia_args *) v; + sl = (struct summary_lsa *) l->data; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("process_summary_lsa(): LS ID: %s", inet_ntoa (sl->header.id)); + + metric = GET_METRIC (sl->metric); + + if (metric == OSPF_LS_INFINITY) + return 0; + + if (IS_LSA_MAXAGE (l)) + return 0; + + if (ospf_lsa_is_self_originated (l)) + return 0; + + p.family = AF_INET; + p.prefix = sl->header.id; + + if (sl->header.type == OSPF_SUMMARY_LSA) + p.prefixlen = ip_masklen (sl->mask); + else + p.prefixlen = IPV4_MAX_BITLEN; + + apply_mask_ipv4 (&p); + + if (sl->header.type == OSPF_SUMMARY_LSA && + (range = ospf_area_range_match_any (ospf_top, &p)) && + ospf_area_range_active (range)) + return 0; + + if (ospf_top->abr_type != OSPF_ABR_STAND && + args->area->external_routing != OSPF_AREA_DEFAULT && + p.prefix.s_addr == OSPF_DEFAULT_DESTINATION && + p.prefixlen == 0) + return 0; /* Ignore summary default from a stub area */ + + abr.family = AF_INET; + abr.prefix = sl->header.adv_router; + abr.prefixlen = IPV4_MAX_BITLEN; + apply_mask_ipv4 (&abr); + + abr_or = ospf_find_abr_route (args->rtrs, &abr, args->area); + + if (abr_or == NULL) + return 0; + + new_or = ospf_route_new (); + new_or->type = OSPF_DESTINATION_NETWORK; + new_or->id = sl->header.id; + new_or->mask = sl->mask; + new_or->u.std.options = sl->header.options; + new_or->u.std.origin = (struct lsa_header *) sl; + new_or->cost = abr_or->cost + metric; + new_or->u.std.area_id = args->area->area_id; +#ifdef HAVE_NSSA + new_or->u.std.external_routing = args->area->external_routing; +#endif /* HAVE_NSSA */ + new_or->path_type = OSPF_PATH_INTER_AREA; + + if (sl->header.type == OSPF_SUMMARY_LSA) + ospf_ia_network_route (args->rt, &p, new_or, abr_or); + else + { + new_or->type = OSPF_DESTINATION_ROUTER; + new_or->u.std.flags = ROUTER_LSA_EXTERNAL; + ospf_ia_router_route (args->rtrs, &p, new_or, abr_or); + } + + return 0; +} + +void +ospf_examine_summaries (struct ospf_area * area, + struct route_table *lsdb_rt, + struct route_table *rt, + struct route_table *rtrs) +{ + struct ia_args args = {rt, rtrs, area}; + foreach_lsa (lsdb_rt, &args, 0, process_summary_lsa); +} + +int +ospf_area_is_transit (struct ospf_area *area) +{ + return (area->transit == OSPF_TRANSIT_TRUE) || + ospf_full_virtual_nbrs(area); /* Cisco forgets to set the V-bit :( */ +} + +void +ospf_update_network_route (struct route_table *rt, + struct route_table *rtrs, + struct summary_lsa *lsa, + struct prefix_ipv4 *p, + struct ospf_area *area) +{ + struct route_node *rn; + struct ospf_route *or, *abr_or, *new_or; + struct prefix_ipv4 abr; + u_int32_t cost; + + abr.family = AF_INET; + abr.prefix =lsa->header.adv_router; + abr.prefixlen = IPV4_MAX_BITLEN; + apply_mask_ipv4 (&abr); + + abr_or = ospf_find_abr_route (rtrs, &abr, area); + + if (abr_or == NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_update_network_route(): can't find a route to the ABR"); + return; + } + + cost = abr_or->cost + GET_METRIC (lsa->metric); + + rn = route_node_lookup (rt, (struct prefix *) p); + + if (! rn) + { + if (ospf_top->abr_type != OSPF_ABR_SHORTCUT) + return; /* Standard ABR can update only already installed + backbone paths */ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_update_network_route(): " + "Allowing Shortcut ABR to add new route"); + new_or = ospf_route_new (); + new_or->type = OSPF_DESTINATION_NETWORK; + new_or->id = lsa->header.id; + new_or->mask = lsa->mask; + new_or->u.std.options = lsa->header.options; + new_or->u.std.origin = (struct lsa_header *) lsa; + new_or->cost = cost; + new_or->u.std.area_id = area->area_id; +#ifdef HAVE_NSSA + new_or->u.std.external_routing = area->external_routing; +#endif /* HAVE_NSSA */ + new_or->path_type = OSPF_PATH_INTER_AREA; + ospf_route_add (rt, p, new_or, abr_or); + + return; + } + else + { + route_unlock_node (rn); + if (rn->info == NULL) + return; + } + + or = rn->info; + + if (or->path_type != OSPF_PATH_INTRA_AREA && + or->path_type != OSPF_PATH_INTER_AREA) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_update_network_route(): ERR: path type is wrong"); + return; + } + + if (ospf_top->abr_type == OSPF_ABR_SHORTCUT) + { + if (or->path_type == OSPF_PATH_INTRA_AREA && + !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_update_network_route(): Shortcut: " + "this intra-area path is not backbone"); + return; + } + } + else /* Not Shortcut ABR */ + { + if (!OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_update_network_route(): " + "route is not BB-associated"); + return; /* We can update only BB routes */ + } + } + + if (or->cost < cost) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_update_network_route(): new route is worse"); + return; + } + + if (or->cost == cost) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_update_network_route(): " + "new route is same distance, adding nexthops"); + ospf_route_copy_nexthops (or, abr_or->path); + } + + if (or->cost > cost) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_update_network_route(): " + "new route is better, overriding nexthops"); + ospf_route_subst_nexthops (or, abr_or->path); + or->cost = cost; + + if ((ospf_top->abr_type == OSPF_ABR_SHORTCUT) && + !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) + { + or->path_type = OSPF_PATH_INTER_AREA; + or->u.std.area_id = area->area_id; +#ifdef HAVE_NSSA + or->u.std.external_routing = area->external_routing; +#endif /* HAVE_NSSA */ + /* Note that we can do this only in Shortcut ABR mode, + because standard ABR must leave the route type and area + unchanged + */ + } + } +} + +void +ospf_update_router_route (struct route_table *rtrs, + struct summary_lsa *lsa, + struct prefix_ipv4 *p, + struct ospf_area *area) +{ + struct ospf_route *or, *abr_or, *new_or; + struct prefix_ipv4 abr; + u_int32_t cost; + + abr.family = AF_INET; + abr.prefix = lsa->header.adv_router; + abr.prefixlen = IPV4_MAX_BITLEN; + apply_mask_ipv4 (&abr); + + abr_or = ospf_find_abr_route (rtrs, &abr, area); + + if (abr_or == NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_update_router_route(): can't find a route to the ABR"); + return; + } + + cost = abr_or->cost + GET_METRIC (lsa->metric); + + /* First try to find a backbone path, + because standard ABR can update only BB-associated paths */ + + if ((ospf_top->backbone == NULL) && + (ospf_top->abr_type != OSPF_ABR_SHORTCUT)) + + /* no BB area, not Shortcut ABR, exiting */ + return; + + or = ospf_find_asbr_route_through_area (rtrs, p, ospf_top->backbone); + + if (or == NULL) + { + if (ospf_top->abr_type != OSPF_ABR_SHORTCUT) + + /* route to ASBR through the BB not found + the router is not Shortcut ABR, exiting */ + + return; + else + /* We're a Shortcut ABR*/ + { + /* Let it either add a new router or update the route + through the same (non-BB) area. */ + + new_or = ospf_route_new (); + new_or->type = OSPF_DESTINATION_ROUTER; + new_or->id = lsa->header.id; + new_or->mask = lsa->mask; + new_or->u.std.options = lsa->header.options; + new_or->u.std.origin = (struct lsa_header *)lsa; + new_or->cost = cost; + new_or->u.std.area_id = area->area_id; +#ifdef HAVE_NSSA + new_or->u.std.external_routing = area->external_routing; +#endif /* HAVE_NSSA */ + new_or->path_type = OSPF_PATH_INTER_AREA; + new_or->u.std.flags = ROUTER_LSA_EXTERNAL; + ospf_ia_router_route (rtrs, p, new_or, abr_or); + + return; + } + } + + /* At this point the "or" is always bb-associated */ + + if (!(or->u.std.flags & ROUTER_LSA_EXTERNAL)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_upd_router_route(): the remote router is not an ASBR"); + return; + } + + if (or->path_type != OSPF_PATH_INTRA_AREA && + or->path_type != OSPF_PATH_INTER_AREA) + return; + + if (or->cost < cost) + return; + + else if (or->cost == cost) + ospf_route_copy_nexthops (or, abr_or->path); + + else if (or->cost > cost) + { + ospf_route_subst_nexthops (or, abr_or->path); + or->cost = cost; + + /* Even if the ABR runs in Shortcut mode, we can't change + the path type and area, because the "or" is always bb-associated + at this point and even Shortcut ABR can't change these attributes */ + } +} + +int +process_transit_summary_lsa (struct ospf_lsa *l, void *v, int i) +{ + struct summary_lsa *sl; + struct prefix_ipv4 p; + u_int32_t metric; + struct ia_args *args; + + if (l == NULL) + return 0; + + args = (struct ia_args *) v; + sl = (struct summary_lsa *) l->data; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("process_transit_summaries(): LS ID: %s", + inet_ntoa (l->data->id)); + metric = GET_METRIC (sl->metric); + + if (metric == OSPF_LS_INFINITY) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("process_transit_summaries(): metric is infinity, skip"); + return 0; + } + + if (IS_LSA_MAXAGE (l)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("process_transit_summaries(): This LSA is too old"); + return 0; + } + + if (ospf_lsa_is_self_originated (l)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("process_transit_summaries(): This LSA is mine, skip"); + return 0; + } + + p.family = AF_INET; + p.prefix = sl->header.id; + + if (sl->header.type == OSPF_SUMMARY_LSA) + p.prefixlen = ip_masklen (sl->mask); + else + p.prefixlen = IPV4_MAX_BITLEN; + + apply_mask_ipv4 (&p); + + if (sl->header.type == OSPF_SUMMARY_LSA) + ospf_update_network_route (args->rt, args->rtrs, sl, &p, args->area); + else + ospf_update_router_route (args->rtrs, sl, &p, args->area); + + return 0; +} + +void +ospf_examine_transit_summaries (struct ospf_area *area, + /* struct ospf_lsdb *lsdb, */ + struct route_table *lsdb_rt, + struct route_table *rt, + struct route_table *rtrs) +{ + struct ia_args args = {rt, rtrs, area}; + + /* ospf_lsdb_iterator (lsdb, &args, 0, process_transit_summary_lsa); */ + foreach_lsa (lsdb_rt, &args, 0, process_transit_summary_lsa); +} + +void +ospf_ia_routing (struct route_table *rt, + struct route_table *rtrs) +{ + struct ospf_area * area; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_routing():start"); + + if (OSPF_IS_ABR) + { + listnode node; + struct ospf_area *area; + + switch (ospf_top->abr_type) + { + case OSPF_ABR_STAND: + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_routing():Standard ABR"); + + if ((area = ospf_top->backbone)) + { + listnode node; + + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("ospf_ia_routing():backbone area found"); + zlog_info ("ospf_ia_routing():examining summaries"); + } + + OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + if ((area = getdata (node)) != NULL) + if (area != ospf_top->backbone) + if (ospf_area_is_transit (area)) + OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL (area, rt, rtrs); + } + else + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_routing():backbone area NOT found"); + break; + case OSPF_ABR_IBM: + case OSPF_ABR_CISCO: + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_routing():Alternative Cisco/IBM ABR"); + area = ospf_top->backbone; /* Find the BB */ + + /* If we have an active BB connection */ + if (area && ospf_act_bb_connection ()) + { + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("ospf_ia_routing(): backbone area found"); + zlog_info ("ospf_ia_routing(): examining BB summaries"); + } + + OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + if ((area = getdata (node)) != NULL) + if (area != ospf_top->backbone) + if (ospf_area_is_transit (area)) + OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL (area, rt, rtrs); + } + else + { /* No active BB connection--consider all areas */ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_routing(): " + "Active BB connection not found"); + for (node = listhead (ospf_top->areas); node; nextnode (node)) + if ((area = getdata (node)) != NULL) + OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); + } + break; + case OSPF_ABR_SHORTCUT: + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_routing():Alternative Shortcut"); + area = ospf_top->backbone; /* Find the BB */ + + /* If we have an active BB connection */ + if (area && ospf_act_bb_connection ()) + { + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("ospf_ia_routing(): backbone area found"); + zlog_info ("ospf_ia_routing(): examining BB summaries"); + } + OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); + } + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + if ((area = getdata (node)) != NULL) + if (area != ospf_top->backbone) + if (ospf_area_is_transit (area) || + ((area->shortcut_configured != OSPF_SHORTCUT_DISABLE) && + ((ospf_top->backbone == NULL) || + ((area->shortcut_configured == OSPF_SHORTCUT_ENABLE) && + area->shortcut_capability)))) + OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL (area, rt, rtrs); + break; + default: + break; + } + } + else + { + listnode node; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_routing():not ABR, considering all areas"); + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + if ((area = getdata (node)) != NULL) + OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); + } +} diff --git a/ospfd/ospf_ia.h b/ospfd/ospf_ia.h new file mode 100644 index 00000000..afb2d4d5 --- /dev/null +++ b/ospfd/ospf_ia.h @@ -0,0 +1,42 @@ +/* + * OSPF inter-area routing. + * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_IA_H +#define _ZEBRA_OSPF_IA_H + +/* Macros. */ +#define OSPF_EXAMINE_SUMMARIES_ALL(A,N,R) \ + { \ + ospf_examine_summaries ((A), SUMMARY_LSDB ((A)), (N), (R)); \ + ospf_examine_summaries ((A), ASBR_SUMMARY_LSDB ((A)), (N), (R)); \ + } + +#define OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL(A,N,R) \ + { \ + ospf_examine_transit_summaries ((A), SUMMARY_LSDB ((A)), (N), (R)); \ + ospf_examine_transit_summaries ((A), ASBR_SUMMARY_LSDB ((A)), (N), (R)); \ + } + +void ospf_ia_routing (struct route_table *, struct route_table *); +int ospf_area_is_transit (struct ospf_area *); + +#endif /* _ZEBRA_OSPF_IA_H */ diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c new file mode 100644 index 00000000..ddae9800 --- /dev/null +++ b/ospfd/ospf_interface.c @@ -0,0 +1,1045 @@ +/* + * OSPF Interface functions. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "thread.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "memory.h" +#include "command.h" +#include "stream.h" +#include "log.h" + +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospfd.h" +#include "ospfd/ospf_network.h" +#include "ospfd/ospf_dump.h" +#ifdef HAVE_SNMP +#include "ospfd/ospf_snmp.h" +#endif /* HAVE_SNMP */ + + +int +ospf_if_get_output_cost (struct ospf_interface *oi) +{ + /* If all else fails, use default OSPF cost */ + u_int32_t cost; + u_int32_t bw, refbw; + + bw = oi->ifp->bandwidth ? oi->ifp->bandwidth : OSPF_DEFAULT_BANDWIDTH; + refbw = ospf_top ? ospf_top->ref_bandwidth : OSPF_DEFAULT_REF_BANDWIDTH; + + /* A specifed ip ospf cost overrides a calculated one. */ + if (OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (oi->ifp), output_cost_cmd) || + OSPF_IF_PARAM_CONFIGURED (oi->params, output_cost_cmd)) + cost = OSPF_IF_PARAM (oi, output_cost_cmd); + /* See if a cost can be calculated from the zebra processes + interface bandwidth field. */ + else + { + cost = (u_int32_t) ((double)refbw / (double)bw + (double)0.5); + if (cost < 1) + cost = 1; + else if (cost > 65535) + cost = 65535; + } + + return cost; +} + +void +ospf_if_recalculate_output_cost (struct interface *ifp) +{ + u_int32_t newcost; + struct route_node *rn; + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + struct ospf_interface *oi; + + if ( (oi = rn->info) == NULL) + continue; + + newcost = ospf_if_get_output_cost (oi); + + /* Is actual output cost changed? */ + if (oi->output_cost != newcost) + { + oi->output_cost = newcost; + ospf_router_lsa_timer_add (oi->area); + } + } +} + +void +ospf_if_reset_variables (struct ospf_interface *oi) +{ + /* Set default values. */ + /* don't clear this flag. oi->flag = OSPF_IF_DISABLE; */ + + if (oi->vl_data) + oi->type = OSPF_IFTYPE_VIRTUALLINK; + else + /* preserve network-type */ + if (oi->type != OSPF_IFTYPE_NBMA) + oi->type = OSPF_IFTYPE_BROADCAST; + + oi->state = ISM_Down; + + oi->crypt_seqnum = 0; + + /* This must be short, (less than RxmtInterval) + - RFC 2328 Section 13.5 para 3. Set to 1 second to avoid Acks being + held back for too long - MAG */ + oi->v_ls_ack = 1; +} + +void +ospf_add_to_if (struct interface *ifp, struct ospf_interface *oi) +{ + struct route_node *rn; + struct prefix p; + + p = *oi->address; + p.prefixlen = IPV4_MAX_PREFIXLEN; + + rn = route_node_get (IF_OIFS (ifp), &p); + assert (! rn->info); + rn->info = oi; +} + +void +ospf_delete_from_if (struct interface *ifp, struct ospf_interface *oi) +{ + struct route_node *rn; + struct prefix p; + + p = *oi->address; + p.prefixlen = IPV4_MAX_PREFIXLEN; + + rn = route_node_lookup (IF_OIFS (oi->ifp), &p); + assert (rn); + assert (rn->info); + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); +} + +struct ospf_interface * +ospf_if_new (struct interface *ifp, struct prefix *p) +{ + struct ospf_interface *oi; + + oi = XCALLOC (MTYPE_OSPF_IF, sizeof (struct ospf_interface)); + memset (oi, 0, sizeof (struct ospf_interface)); + + /* Set zebra interface pointer. */ + oi->ifp = ifp; + oi->address = p; + + ospf_add_to_if (ifp, oi); + listnode_add (ospf_top->oiflist, oi); + + /* Clear self-originated network-LSA. */ + oi->network_lsa_self = NULL; + + /* Initialize neighbor list. */ + oi->nbrs = route_table_init (); + + /* Initialize static neighbor list. */ + oi->nbr_nbma = list_new (); + + /* Initialize Link State Acknowledgment list. */ + oi->ls_ack = list_new (); + oi->ls_ack_direct.ls_ack = list_new (); + + /* Set default values. */ + ospf_if_reset_variables (oi); + + /* Add pseudo neighbor. */ + oi->nbr_self = ospf_nbr_new (oi); + oi->nbr_self->state = NSM_TwoWay; + /* oi->nbr_self->router_id = ospf_top->router_id; */ + oi->nbr_self->priority = OSPF_IF_PARAM (oi, priority); + oi->nbr_self->options = OSPF_OPTION_E; + + oi->ls_upd_queue = route_table_init (); + oi->t_ls_upd_event = NULL; + oi->t_ls_ack_direct = NULL; + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_type9_lsa_init (oi); +#endif /* HAVE_OPAQUE_LSA */ + + oi->ospf = ospf_top; + + return oi; +} + +/* Restore an interface to its pre UP state + Used from ism_interface_down only */ +void +ospf_if_cleanup (struct ospf_interface *oi) +{ + struct route_node *rn; + listnode node; + struct ospf_neighbor *nbr; + + /* oi->nbrs and oi->nbr_nbma should be deletete on InterafceDown event */ + /* delete all static neighbors attached to this interface */ + for (node = listhead (oi->nbr_nbma); node; ) + { + struct ospf_nbr_nbma *nbr_nbma = getdata (node); + nextnode (node); + + OSPF_POLL_TIMER_OFF (nbr_nbma->t_poll); + + if (nbr_nbma->nbr) + { + nbr_nbma->nbr->nbr_nbma = NULL; + nbr_nbma->nbr = NULL; + } + + nbr_nbma->oi = NULL; + + listnode_delete (oi->nbr_nbma, nbr_nbma); + } + + /* send Neighbor event KillNbr to all associated neighbors. */ + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL) + if (nbr != oi->nbr_self) + OSPF_NSM_EVENT_EXECUTE (nbr, NSM_KillNbr); + + /* Cleanup Link State Acknowlegdment list. */ + for (node = listhead (oi->ls_ack); node; nextnode (node)) + ospf_lsa_unlock (node->data); + list_delete_all_node (oi->ls_ack); + + oi->crypt_seqnum = 0; + + /* Empty link state update queue */ + ospf_ls_upd_queue_empty (oi); + + /* Handle pseudo neighbor. */ + ospf_nbr_delete (oi->nbr_self); + oi->nbr_self = ospf_nbr_new (oi); + oi->nbr_self->state = NSM_TwoWay; + oi->nbr_self->priority = OSPF_IF_PARAM (oi, priority); + oi->nbr_self->options = OSPF_OPTION_E; + + ospf_lsa_unlock (oi->network_lsa_self); + oi->network_lsa_self = NULL; + OSPF_TIMER_OFF (oi->t_network_lsa_self); +} + +void +ospf_if_free (struct ospf_interface *oi) +{ + ospf_if_down (oi); + + assert (oi->state == ISM_Down); + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_type9_lsa_term (oi); +#endif /* HAVE_OPAQUE_LSA */ + + /* Free Pseudo Neighbour */ + ospf_nbr_delete (oi->nbr_self); + + route_table_finish (oi->nbrs); + route_table_finish (oi->ls_upd_queue); + + /* Free any lists that should be freed */ + list_free (oi->nbr_nbma); + + list_free (oi->ls_ack); + list_free (oi->ls_ack_direct.ls_ack); + + ospf_delete_from_if (oi->ifp, oi); + + listnode_delete (ospf_top->oiflist, oi); + listnode_delete (oi->area->oiflist, oi); + + memset (oi, 0, sizeof (*oi)); + XFREE (MTYPE_OSPF_IF, oi); +} + + +/* +* check if interface with given address is configured and +* return it if yes. +*/ +struct ospf_interface * +ospf_if_is_configured (struct in_addr *address) +{ + listnode node; + struct ospf_interface *oi; + struct prefix *addr; + + for (node = listhead (ospf_top->oiflist); node; nextnode (node)) + if ((oi = getdata (node)) != NULL && oi->type != OSPF_IFTYPE_VIRTUALLINK) + { + if (oi->type == OSPF_IFTYPE_POINTOPOINT) + addr = oi->connected->destination; + else + addr = oi->address; + + if (IPV4_ADDR_SAME (address, &addr->u.prefix4)) + return oi; + } + + return NULL; +} + +int +ospf_if_is_up (struct ospf_interface *oi) +{ + return if_is_up (oi->ifp); +} + +struct ospf_interface * +ospf_if_lookup_by_local_addr (struct interface *ifp, struct in_addr address) +{ + listnode node; + struct ospf_interface *oi; + + for (node = listhead (ospf_top->oiflist); node; nextnode (node)) + if ((oi = getdata (node)) != NULL && oi->type != OSPF_IFTYPE_VIRTUALLINK) + { + if (ifp && oi->ifp != ifp) + continue; + + if (IPV4_ADDR_SAME (&address, &oi->address->u.prefix4)) + return oi; + } + + return NULL; +} + +struct ospf_interface * +ospf_if_lookup_by_prefix (struct prefix_ipv4 *p) +{ + listnode node; + struct ospf_interface *oi; + struct prefix ptmp; + + /* Check each Interface. */ + for (node = listhead (ospf_top->oiflist); node; nextnode (node)) { + if ((oi = getdata (node)) != NULL && oi->type != OSPF_IFTYPE_VIRTUALLINK) + { + if (oi->type == OSPF_IFTYPE_POINTOPOINT) { + prefix_copy (&ptmp, oi->connected->destination); + ptmp.prefixlen = IPV4_MAX_BITLEN; + } + else + prefix_copy (&ptmp, oi->address); + + apply_mask (&ptmp); + if (prefix_same (&ptmp, (struct prefix *) p)) + return oi; + } + } + return NULL; +} + +/* determine receiving interface by source of packet */ +struct ospf_interface * +ospf_if_lookup_recv_interface (struct in_addr src) +{ + listnode node; + struct prefix_ipv4 addr; + struct ospf_interface *oi, *match; + + addr.family = AF_INET; + addr.prefix = src; + addr.prefixlen = IPV4_MAX_BITLEN; + + match = NULL; + + for (node = listhead (ospf_top->oiflist); node; nextnode (node)) + { + oi = getdata (node); + + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + continue; + + if (oi->type == OSPF_IFTYPE_POINTOPOINT) + { + if (IPV4_ADDR_SAME (&oi->connected->destination->u.prefix4, &src)) + return oi; + } + else + { + if (prefix_match (oi->address, (struct prefix *) &addr)) + match = oi; + } + } + + return match; +} + +void +ospf_if_stream_set (struct ospf_interface *oi) +{ + /* set output fifo queue. */ + if (oi->obuf == NULL) + oi->obuf = ospf_fifo_new (); +} + +void +ospf_if_stream_unset (struct ospf_interface *oi) +{ + if (oi->obuf) + { + ospf_fifo_free (oi->obuf); + oi->obuf = NULL; + + if (oi->on_write_q) + { + listnode_delete (ospf_top->oi_write_q, oi); + if (list_isempty(ospf_top->oi_write_q)) + OSPF_TIMER_OFF (ospf_top->t_write); + oi->on_write_q = 0; + } + } +} + +struct ospf_if_params * +ospf_new_if_params () +{ + struct ospf_if_params *oip; + + oip = XMALLOC (MTYPE_OSPF_IF_PARAMS, sizeof (struct ospf_if_params)); + memset (oip, 0, sizeof (struct ospf_if_params)); + + if (!oip) + return NULL; + + memset (oip, 0, sizeof (struct ospf_if_params)); + + UNSET_IF_PARAM (oip, output_cost_cmd); + UNSET_IF_PARAM (oip, transmit_delay); + UNSET_IF_PARAM (oip, retransmit_interval); + UNSET_IF_PARAM (oip, passive_interface); + UNSET_IF_PARAM (oip, v_hello); + UNSET_IF_PARAM (oip, v_wait); + UNSET_IF_PARAM (oip, priority); + UNSET_IF_PARAM (oip, type); + UNSET_IF_PARAM (oip, auth_simple); + UNSET_IF_PARAM (oip, auth_crypt); + UNSET_IF_PARAM (oip, auth_type); + + oip->auth_crypt = list_new (); + + return oip; +} + +void +ospf_del_if_params (struct ospf_if_params *oip) +{ + list_delete (oip->auth_crypt); + XFREE (MTYPE_OSPF_IF_PARAMS, oip); +} + +void +ospf_free_if_params (struct interface *ifp, struct in_addr addr) +{ + struct ospf_if_params *oip; + struct prefix_ipv4 p; + struct route_node *rn; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = addr; + rn = route_node_lookup (IF_OIFS_PARAMS (ifp), (struct prefix*)&p); + if (!rn || !rn->info) + return; + + oip = rn->info; + route_unlock_node (rn); + + if (!OSPF_IF_PARAM_CONFIGURED (oip, output_cost_cmd) && + !OSPF_IF_PARAM_CONFIGURED (oip, transmit_delay) && + !OSPF_IF_PARAM_CONFIGURED (oip, retransmit_interval) && + !OSPF_IF_PARAM_CONFIGURED (oip, passive_interface) && + !OSPF_IF_PARAM_CONFIGURED (oip, v_hello) && + !OSPF_IF_PARAM_CONFIGURED (oip, v_wait) && + !OSPF_IF_PARAM_CONFIGURED (oip, priority) && + !OSPF_IF_PARAM_CONFIGURED (oip, type) && + !OSPF_IF_PARAM_CONFIGURED (oip, auth_simple) && + !OSPF_IF_PARAM_CONFIGURED (oip, auth_type) && + listcount (oip->auth_crypt) == 0) + { + ospf_del_if_params (oip); + rn->info = NULL; + route_unlock_node (rn); + } +} + +struct ospf_if_params * +ospf_lookup_if_params (struct interface *ifp, struct in_addr addr) +{ + struct prefix_ipv4 p; + struct route_node *rn; + + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = addr; + + rn = route_node_lookup (IF_OIFS_PARAMS (ifp), (struct prefix*)&p); + + if (rn) + { + route_unlock_node (rn); + return rn->info; + } + + return NULL; +} + +struct ospf_if_params * +ospf_get_if_params (struct interface *ifp, struct in_addr addr) +{ + struct prefix_ipv4 p; + struct route_node *rn; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = addr; + + rn = route_node_get (IF_OIFS_PARAMS (ifp), (struct prefix*)&p); + + if (rn->info == NULL) + rn->info = ospf_new_if_params (); + else + route_unlock_node (rn); + + return rn->info; +} + +void +ospf_if_update_params (struct interface *ifp, struct in_addr addr) +{ + struct route_node *rn; + struct ospf_interface *oi; + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + if ((oi = rn->info) == NULL) + continue; + + if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &addr)) + oi->params = ospf_lookup_if_params (ifp, oi->address->u.prefix4); + } +} + +int +ospf_if_new_hook (struct interface *ifp) +{ + int rc = 0; + + ifp->info = XMALLOC (MTYPE_OSPF_IF_INFO, sizeof (struct ospf_if_info)); + memset (ifp->info, 0, sizeof (struct ospf_if_info)); + + IF_OIFS (ifp) = route_table_init (); + IF_OIFS_PARAMS (ifp) = route_table_init (); + + IF_DEF_PARAMS (ifp) = ospf_new_if_params (); + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), transmit_delay); + IF_DEF_PARAMS (ifp)->transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), retransmit_interval); + IF_DEF_PARAMS (ifp)->retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), priority); + IF_DEF_PARAMS (ifp)->priority = OSPF_ROUTER_PRIORITY_DEFAULT; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), passive_interface); + IF_DEF_PARAMS (ifp)->passive_interface = OSPF_IF_ACTIVE; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_hello); + IF_DEF_PARAMS (ifp)->v_hello = OSPF_HELLO_INTERVAL_DEFAULT; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_wait); + IF_DEF_PARAMS (ifp)->v_wait = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_simple); + memset (IF_DEF_PARAMS (ifp)->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE); + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_crypt); + IF_DEF_PARAMS (ifp)->auth_crypt = list_new (); + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_type); + IF_DEF_PARAMS (ifp)->auth_type = OSPF_AUTH_NOTSET; + +#ifdef HAVE_OPAQUE_LSA + rc = ospf_opaque_new_if (ifp); +#endif /* HAVE_OPAQUE_LSA */ + return rc; +} + +int +ospf_if_delete_hook (struct interface *ifp) +{ + int rc = 0; +#ifdef HAVE_OPAQUE_LSA + rc = ospf_opaque_del_if (ifp); +#endif /* HAVE_OPAQUE_LSA */ + route_table_finish (IF_OIFS (ifp)); + route_table_finish (IF_OIFS_PARAMS (ifp)); + XFREE (MTYPE_OSPF_IF_INFO, ifp->info); + ifp->info = NULL; + + return rc; +} + +int +ospf_if_is_enable (struct ospf_interface *oi) +{ + if (!if_is_loopback (oi->ifp)) + if (if_is_up (oi->ifp)) + return 1; + + return 0; +} + +int +ospf_if_up (struct ospf_interface *oi) +{ + if (oi == NULL) + return 0; + + if (oi->type == OSPF_IFTYPE_LOOPBACK) + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_LoopInd); + else + { + if (oi->type != OSPF_IFTYPE_VIRTUALLINK) + ospf_if_add_allspfrouters (ospf_top, oi->address, oi->ifp->ifindex); + ospf_if_stream_set (oi); + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_InterfaceUp); + } + + return 1; +} + +int +ospf_if_down (struct ospf_interface *oi) +{ + if (oi == NULL) + return 0; + + OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); + /* Shutdown packet reception and sending */ + ospf_if_stream_unset (oi); + if (oi->type != OSPF_IFTYPE_VIRTUALLINK) + ospf_if_drop_allspfrouters (ospf_top, oi->address, oi->ifp->ifindex); + + + return 1; +} + + +/* Virtual Link related functions. */ + +struct ospf_vl_data * +ospf_vl_data_new (struct ospf_area *area, struct in_addr vl_peer) +{ + struct ospf_vl_data *vl_data; + + vl_data = XMALLOC (MTYPE_OSPF_VL_DATA, sizeof (struct ospf_vl_data)); + memset (vl_data, 0, sizeof (struct ospf_vl_data)); + + vl_data->vl_peer.s_addr = vl_peer.s_addr; + vl_data->vl_area_id = area->area_id; + vl_data->format = area->format; + + return vl_data; +} + +void +ospf_vl_data_free (struct ospf_vl_data *vl_data) +{ + XFREE (MTYPE_OSPF_VL_DATA, vl_data); +} + +u_int vlink_count = 0; + +struct ospf_interface * +ospf_vl_new (struct ospf_vl_data *vl_data) +{ + struct ospf_interface * voi; + struct interface * vi; + char ifname[INTERFACE_NAMSIZ + 1]; + struct ospf_area *area; + struct in_addr area_id; + struct connected *co; + struct prefix_ipv4 *p; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_new(): Start"); + if (vlink_count == OSPF_VL_MAX_COUNT) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_new(): Alarm: " + "cannot create more than OSPF_MAX_VL_COUNT virtual links"); + return NULL; + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_new(): creating pseudo zebra interface"); + + vi = if_create (); + co = connected_new (); + co->ifp = vi; + listnode_add (vi->connected, co); + + p = prefix_ipv4_new (); + p->family = AF_INET; + p->prefix.s_addr = 0; + p->prefixlen = 0; + + co->address = (struct prefix *)p; + + voi = ospf_if_new (vi, co->address); + if (voi == NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_new(): Alarm: OSPF int structure is not created"); + return NULL; + } + voi->connected = co; + voi->vl_data = vl_data; + voi->ifp->mtu = OSPF_VL_MTU; + voi->type = OSPF_IFTYPE_VIRTUALLINK; + + sprintf (ifname, "VLINK%d", vlink_count++); + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_new(): Created name: %s", ifname); + strncpy (vi->name, ifname, IFNAMSIZ); + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_new(): set if->name to %s", vi->name); + + area_id.s_addr = 0; + area = ospf_area_get (area_id, OSPF_AREA_ID_FORMAT_ADDRESS); + voi->area = area; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_new(): set associated area to the backbone"); + + ospf_area_add_if (voi->area, voi); + + ospf_if_stream_set (voi); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_new(): Stop"); + return voi; +} + +void +ospf_vl_if_delete (struct ospf_vl_data *vl_data) +{ + struct interface *ifp = vl_data->vl_oi->ifp; + vl_data->vl_oi->address->u.prefix4.s_addr = 0; + vl_data->vl_oi->address->prefixlen = 0; + ospf_if_free (vl_data->vl_oi); + if_delete (ifp); + vlink_count--; +} + +struct ospf_vl_data * +ospf_vl_lookup (struct ospf_area *area, struct in_addr vl_peer) +{ + struct ospf_vl_data *vl_data; + listnode node; + + for (node = listhead (ospf_top->vlinks); node; nextnode (node)) + if ((vl_data = getdata (node)) != NULL) + if (vl_data->vl_peer.s_addr == vl_peer.s_addr && + IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id)) + return vl_data; + + return NULL; +} + +void +ospf_vl_shutdown (struct ospf_vl_data *vl_data) +{ + struct ospf_interface *oi; + + if ((oi = vl_data->vl_oi) == NULL) + return; + + oi->address->u.prefix4.s_addr = 0; + oi->address->prefixlen = 0; + + UNSET_FLAG (oi->ifp->flags, IFF_UP); + /* OSPF_ISM_EVENT_SCHEDULE (oi, ISM_InterfaceDown); */ + OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); +} + +void +ospf_vl_add (struct ospf_vl_data *vl_data) +{ + listnode_add (ospf_top->vlinks, vl_data); +#ifdef HAVE_SNMP + ospf_snmp_vl_add (vl_data); +#endif /* HAVE_SNMP */ +} + +void +ospf_vl_delete (struct ospf_vl_data *vl_data) +{ + ospf_vl_shutdown (vl_data); + ospf_vl_if_delete (vl_data); + +#ifdef HAVE_SNMP + ospf_snmp_vl_delete (vl_data); +#endif /* HAVE_SNMP */ + listnode_delete (ospf_top->vlinks, vl_data); + + ospf_vl_data_free (vl_data); +} + +void +ospf_vl_set_params (struct ospf_vl_data *vl_data, struct vertex *v) +{ + int changed = 0; + struct ospf_interface *voi; + listnode node; + struct vertex_nexthop *nh; + int i; + struct router_lsa *rl; + + voi = vl_data->vl_oi; + + if (voi->output_cost != v->distance) + { + voi->output_cost = v->distance; + changed = 1; + } + + for (node = listhead (v->nexthop); node; nextnode (node)) + if ((nh = getdata (node)) != NULL) + { + vl_data->out_oi = (struct ospf_interface *) nh->oi; + + voi->address->u.prefix4 = vl_data->out_oi->address->u.prefix4; + voi->address->prefixlen = vl_data->out_oi->address->prefixlen; + + break; /* We take the first interface. */ + } + + rl = (struct router_lsa *)v->lsa; + + for (i = 0; i < ntohs (rl->links); i++) + { + switch (rl->link[i].type) + { + case LSA_LINK_TYPE_VIRTUALLINK: + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("found back link through VL"); + case LSA_LINK_TYPE_TRANSIT: + case LSA_LINK_TYPE_POINTOPOINT: + vl_data->peer_addr = rl->link[i].link_data; + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("%s peer address is %s\n", + vl_data->vl_oi->ifp->name, inet_ntoa(vl_data->peer_addr)); + return; + } + } +} + + +void +ospf_vl_up_check (struct ospf_area * area, struct in_addr rid, + struct vertex *v) +{ + listnode node; + struct ospf_vl_data *vl_data; + struct ospf_interface *oi; + + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("ospf_vl_up_check(): Start"); + zlog_info ("ospf_vl_up_check(): Router ID is %s", inet_ntoa (rid)); + zlog_info ("ospf_vl_up_check(): Area is %s", inet_ntoa (area->area_id)); + } + + for (node = listhead (ospf_top->vlinks); node; nextnode (node)) + { + if ((vl_data = getdata (node)) == NULL) + continue; + + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("ospf_vl_up_check(): considering VL, name: %s", + vl_data->vl_oi->ifp->name); + zlog_info ("ospf_vl_up_check(): VL area: %s, peer ID: %s", + inet_ntoa (vl_data->vl_area_id), + inet_ntoa (vl_data->vl_peer)); + } + + if (IPV4_ADDR_SAME (&vl_data->vl_peer, &rid) && + IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id)) + { + oi = vl_data->vl_oi; + SET_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_up_check(): this VL matched"); + + if (oi->state == ISM_Down) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_up_check(): VL is down, waking it up"); + SET_FLAG (oi->ifp->flags, IFF_UP); + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_InterfaceUp); + } + + ospf_vl_set_params (vl_data, v); + } + } +} + +void +ospf_vl_unapprove () +{ + listnode node; + struct ospf_vl_data *vl_data; + + for (node = listhead (ospf_top->vlinks); node; nextnode (node)) + if ((vl_data = getdata (node)) != NULL) + UNSET_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED); +} + +void +ospf_vl_shut_unapproved () +{ + listnode node; + struct ospf_vl_data *vl_data; + + for (node = listhead (ospf_top->vlinks); node; nextnode (node)) + if ((vl_data = getdata (node)) != NULL) + if (!CHECK_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED)) + ospf_vl_shutdown (vl_data); +} + +int +ospf_full_virtual_nbrs (struct ospf_area *area) +{ + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("counting fully adjacent virtual neighbors in area %s", + inet_ntoa (area->area_id)); + zlog_info ("there are %d of them", area->full_vls); + } + + return area->full_vls; +} + +int +ospf_vls_in_area (struct ospf_area *area) +{ + listnode node; + struct ospf_vl_data *vl_data; + int c = 0; + + for (node = listhead (ospf_top->vlinks); node; nextnode (node)) + if ((vl_data = getdata (node)) != NULL) + if (IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id)) + c++; + + return c; +} + + +struct crypt_key * +ospf_crypt_key_new () +{ + struct crypt_key *ck; + + ck = XMALLOC (MTYPE_OSPF_CRYPT_KEY, sizeof (struct crypt_key)); + memset (ck, 0, sizeof (struct crypt_key)); + + return ck; +} + +void +ospf_crypt_key_add (list crypt, struct crypt_key *ck) +{ + listnode_add (crypt, ck); +} + +struct crypt_key * +ospf_crypt_key_lookup (list auth_crypt, u_char key_id) +{ + listnode node; + struct crypt_key *ck; + + for (node = listhead (auth_crypt); node; nextnode (node)) + { + ck = getdata (node); + if (ck->key_id == key_id) + return ck; + } + + return NULL; +} + +int +ospf_crypt_key_delete (list auth_crypt, u_char key_id) +{ + listnode node; + struct crypt_key *ck; + + for (node = listhead (auth_crypt); node; nextnode (node)) + { + ck = getdata (node); + if (ck->key_id == key_id) + { + listnode_delete (auth_crypt, ck); + return 1; + } + } + + return 0; +} + +void +ospf_if_init () +{ + /* Initialize Zebra interface data structure. */ + if_init (); + if_add_hook (IF_NEW_HOOK, ospf_if_new_hook); + if_add_hook (IF_DELETE_HOOK, ospf_if_delete_hook); +} diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h new file mode 100644 index 00000000..6dc01aea --- /dev/null +++ b/ospfd/ospf_interface.h @@ -0,0 +1,245 @@ +/* + * OSPF Interface functions. + * Copyright (C) 1999 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_INTERFACE_H +#define _ZEBRA_OSPF_INTERFACE_H + +#define OSPF_AUTH_SIMPLE_SIZE 8 +#define OSPF_AUTH_MD5_SIZE 16 + +#define IF_OSPF_IF_INFO(I) ((struct ospf_if_info *)((I)->info)) +#define IF_DEF_PARAMS(I) (IF_OSPF_IF_INFO (I)->def_params) +#define IF_OIFS(I) (IF_OSPF_IF_INFO (I)->oifs) +#define IF_OIFS_PARAMS(I) (IF_OSPF_IF_INFO (I)->params) + +#define OSPF_IF_PARAM_CONFIGURED(S, P) ((S) && (S)->P##__config) +#define OSPF_IF_PARAM(O, P) \ + (OSPF_IF_PARAM_CONFIGURED ((O)->params, P)?\ + (O)->params->P:IF_DEF_PARAMS((O)->ifp)->P) + +#define DECLARE_IF_PARAM(T, P) T P; u_char P##__config:1 +#define UNSET_IF_PARAM(S, P) ((S)->P##__config) = 0 +#define SET_IF_PARAM(S, P) ((S)->P##__config) = 1 + +struct ospf_if_params +{ + DECLARE_IF_PARAM (u_int32_t, transmit_delay); /* Interface Transmisson Delay */ + DECLARE_IF_PARAM (u_int32_t, output_cost_cmd);/* Command Interface Output Cost */ + DECLARE_IF_PARAM (u_int32_t, retransmit_interval); /* Retransmission Interval */ + DECLARE_IF_PARAM (u_char, passive_interface); /* OSPF Interface is passive */ + DECLARE_IF_PARAM (u_char, priority); /* OSPF Interface priority */ + DECLARE_IF_PARAM (u_char, type); /* type of interface */ +#define OSPF_IF_ACTIVE 0 +#define OSPF_IF_PASSIVE 1 + + DECLARE_IF_PARAM (u_int32_t, v_hello); /* Hello Interval */ + DECLARE_IF_PARAM (u_int32_t, v_wait); /* Router Dead Interval */ + + /* Authentication data. */ + u_char auth_simple[OSPF_AUTH_SIMPLE_SIZE + 1]; /* Simple password. */ + u_char auth_simple__config:1; + + DECLARE_IF_PARAM (list, auth_crypt); /* List of Auth cryptographic data. */ + DECLARE_IF_PARAM (int, auth_type); /* OSPF authentication type */ +}; + +struct ospf_if_info +{ + struct ospf_if_params *def_params; + struct route_table *params; + struct route_table *oifs; +}; + +struct ospf_interface; + +struct ospf_vl_data +{ + struct in_addr vl_peer; /* Router-ID of the peer for VLs. */ + struct in_addr vl_area_id; /* Transit area for this VL. */ + int format; /* area ID format */ + struct ospf_interface *vl_oi; /* Interface data structure for the VL. */ + struct ospf_interface *out_oi; /* The interface to go out. */ + struct in_addr peer_addr; /* Address used to reach the peer. */ + u_char flags; +}; + + +#define OSPF_VL_MAX_COUNT 256 +#define OSPF_VL_MTU 1500 + +#define OSPF_VL_FLAG_APPROVED 0x01 + +struct crypt_key +{ + u_char key_id; + u_char auth_key[OSPF_AUTH_MD5_SIZE + 1]; +}; + +/* OSPF interface structure. */ +struct ospf_interface +{ + /* This interface's parent ospf instance. */ + struct ospf *ospf; + + /* OSPF Area. */ + struct ospf_area *area; + + /* Interface data from zebra. */ + struct interface *ifp; + struct ospf_vl_data *vl_data; /* Data for Virtual Link */ + + /* Packet send buffer. */ + struct ospf_fifo *obuf; /* Output queue */ + + /* OSPF Network Type. */ + u_char type; +#define OSPF_IFTYPE_NONE 0 +#define OSPF_IFTYPE_POINTOPOINT 1 +#define OSPF_IFTYPE_BROADCAST 2 +#define OSPF_IFTYPE_NBMA 3 +#define OSPF_IFTYPE_POINTOMULTIPOINT 4 +#define OSPF_IFTYPE_VIRTUALLINK 5 +#define OSPF_IFTYPE_LOOPBACK 6 +#define OSPF_IFTYPE_MAX 7 + + /* State of Interface State Machine. */ + u_char state; + + struct prefix *address; /* Interface prefix */ + struct connected *connected; /* Pointer to connected */ + + /* Configured varables. */ + struct ospf_if_params *params; + u_int32_t crypt_seqnum; /* Cryptographic Sequence Number */ + u_int32_t output_cost; /* Acutual Interface Output Cost */ + + /* Neighbor information. */ + struct route_table *nbrs; /* OSPF Neighbor List */ + struct ospf_neighbor *nbr_self; /* Neighbor Self */ +#define DR(I) ((I)->nbr_self->d_router) +#define BDR(I) ((I)->nbr_self->bd_router) +#define OPTIONS(I) ((I)->nbr_self->options) +#define PRIORITY(I) ((I)->nbr_self->priority) + + /* List of configured NBMA neighbor. */ + list nbr_nbma; + + /* self-originated LSAs. */ + struct ospf_lsa *network_lsa_self; /* network-LSA. */ +#ifdef HAVE_OPAQUE_LSA + list opaque_lsa_self; /* Type-9 Opaque-LSAs */ +#endif /* HAVE_OPAQUE_LSA */ + + struct route_table *ls_upd_queue; + + list ls_ack; /* Link State Acknowledgment list. */ + + struct + { + list ls_ack; + struct in_addr dst; + } ls_ack_direct; + + /* Timer values. */ + u_int32_t v_ls_ack; /* Delayed Link State Acknowledgment */ + + /* Threads. */ + struct thread *t_hello; /* timer */ + struct thread *t_wait; /* timer */ + struct thread *t_ls_ack; /* timer */ + struct thread *t_ls_ack_direct; /* event */ + struct thread *t_ls_upd_event; /* event */ + struct thread *t_network_lsa_self; /* self-originated network-LSA + reflesh thread. timer */ +#ifdef HAVE_OPAQUE_LSA + struct thread *t_opaque_lsa_self; /* Type-9 Opaque-LSAs */ +#endif /* HAVE_OPAQUE_LSA */ + + int on_write_q; + + /* Statistics fields. */ + u_int32_t hello_in; /* Hello message input count. */ + u_int32_t hello_out; /* Hello message output count. */ + u_int32_t db_desc_in; /* database desc. message input count. */ + u_int32_t db_desc_out; /* database desc. message output count. */ + u_int32_t ls_req_in; /* LS request message input count. */ + u_int32_t ls_req_out; /* LS request message output count. */ + u_int32_t ls_upd_in; /* LS update message input count. */ + u_int32_t ls_upd_out; /* LS update message output count. */ + u_int32_t ls_ack_in; /* LS Ack message input count. */ + u_int32_t ls_ack_out; /* LS Ack message output count. */ + u_int32_t discarded; /* discarded input count by error. */ + u_int32_t state_change; /* Number of status change. */ + + u_int full_nbrs; +}; + +/* Prototypes. */ +char *ospf_if_name (struct ospf_interface *); +struct ospf_interface *ospf_if_new (); +void ospf_if_cleanup (struct ospf_interface *); +void ospf_if_free (struct ospf_interface *); +int ospf_if_up (struct ospf_interface *); +int ospf_if_down (struct ospf_interface *); + +int ospf_if_is_up (struct ospf_interface *); +struct ospf_interface *ospf_if_lookup_by_name (char *); +struct ospf_interface *ospf_if_lookup_by_local_addr (struct interface *, struct in_addr); +struct ospf_interface *ospf_if_lookup_by_prefix (struct prefix_ipv4 *); +struct ospf_interface *ospf_if_addr_local (struct in_addr src); +struct ospf_interface *ospf_if_lookup_recv_interface (struct in_addr src); +struct ospf_interface *ospf_if_is_configured (struct in_addr *); + +struct ospf_if_params *ospf_lookup_if_params (struct interface *, struct in_addr); +struct ospf_if_params *ospf_get_if_params (struct interface *, struct in_addr); +void ospf_del_if_params (struct ospf_if_params *); +void ospf_free_if_params (struct interface *, struct in_addr); +void ospf_if_update_params (struct interface *, struct in_addr); + +int ospf_if_new_hook (struct interface *); +void ospf_if_init (); +void ospf_if_stream_set (struct ospf_interface *); +void ospf_if_stream_unset (struct ospf_interface *); +void ospf_if_reset_variables (struct ospf_interface *); +int ospf_if_is_enable (struct ospf_interface *); +int ospf_if_get_output_cost (struct ospf_interface *); +void ospf_if_recalculate_output_cost (struct interface *); + +struct ospf_interface *ospf_vl_new (struct ospf_vl_data *); +struct ospf_vl_data *ospf_vl_data_new (struct ospf_area *, struct in_addr); +struct ospf_vl_data *ospf_vl_lookup (struct ospf_area *, struct in_addr); +void ospf_vl_data_free (struct ospf_vl_data *); +void ospf_vl_add (struct ospf_vl_data *); +void ospf_vl_delete (struct ospf_vl_data *); +void ospf_vl_up_check (struct ospf_area *, struct in_addr, struct vertex *); +void ospf_vl_unapprove (); +void ospf_vl_shut_unapproved (); +int ospf_full_virtual_nbrs (struct ospf_area *); +int ospf_vls_in_area (struct ospf_area *); + +struct crypt_key *ospf_crypt_key_lookup (list, u_char); +struct crypt_key *ospf_crypt_key_new (); +void ospf_crypt_key_add (list, struct crypt_key *); +int ospf_crypt_key_delete (list, u_char key_id); + + +#endif /* _ZEBRA_OSPF_INTERFACE_H */ diff --git a/ospfd/ospf_ism.h b/ospfd/ospf_ism.h new file mode 100644 index 00000000..b04865af --- /dev/null +++ b/ospfd/ospf_ism.h @@ -0,0 +1,88 @@ +/* + * OSPF version 2 Interface State Machine. + * From RFC2328 [OSPF Version 2] + * Copyright (C) 1999 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_ISM_H +#define _ZEBRA_OSPF_ISM_H + +/* OSPF Interface State Machine Status. */ +#define ISM_DependUpon 0 +#define ISM_Down 1 +#define ISM_Loopback 2 +#define ISM_Waiting 3 +#define ISM_PointToPoint 4 +#define ISM_DROther 5 +#define ISM_Backup 6 +#define ISM_DR 7 +#define OSPF_ISM_STATE_MAX 8 + +/* OSPF Interface State Machine Event. */ +#define ISM_NoEvent 0 +#define ISM_InterfaceUp 1 +#define ISM_WaitTimer 2 +#define ISM_BackupSeen 3 +#define ISM_NeighborChange 4 +#define ISM_LoopInd 5 +#define ISM_UnloopInd 6 +#define ISM_InterfaceDown 7 +#define OSPF_ISM_EVENT_MAX 8 + +#define OSPF_ISM_WRITE_ON() \ + do \ + { \ + if (oi->on_write_q == 0) \ + { \ + listnode_add (ospf_top->oi_write_q, oi); \ + oi->on_write_q = 1; \ + } \ + if (ospf_top->t_write == NULL) \ + ospf_top->t_write = \ + thread_add_write (master, ospf_write, ospf_top, ospf_top->fd); \ + } while (0) + +/* Macro for OSPF ISM timer turn on. */ +#define OSPF_ISM_TIMER_ON(T,F,V) \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), oi, (V)) + +/* Macro for OSPF ISM timer turn off. */ +#define OSPF_ISM_TIMER_OFF(X) \ + if (X) \ + { \ + thread_cancel (X); \ + (X) = NULL; \ + } + +/* Macro for OSPF schedule event. */ +#define OSPF_ISM_EVENT_SCHEDULE(I,E) \ + thread_add_event (master, ospf_ism_event, (I), (E)) + +/* Macro for OSPF execute event. */ +#define OSPF_ISM_EVENT_EXECUTE(I,E) \ + thread_execute (master, ospf_ism_event, (I), (E)) + +/* Prototypes. */ +int ospf_ism_event (struct thread *); +void ism_change_status (struct ospf_interface *, int); +int ospf_hello_timer (struct thread *thread); + +#endif /* _ZEBRA_OSPF_ISM_H */ diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c new file mode 100644 index 00000000..5b63a76d --- /dev/null +++ b/ospfd/ospf_lsa.c @@ -0,0 +1,3315 @@ +/* + * OSPF Link State Advertisement + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "memory.h" +#include "stream.h" +#include "log.h" +#include "thread.h" +#include "hash.h" +#include "sockunion.h" /* for inet_aton() */ + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_zebra.h" + + +u_int32_t +get_metric (u_char *metric) +{ + u_int32_t m; + m = metric[0]; + m = (m << 8) + metric[1]; + m = (m << 8) + metric[2]; + return m; +} + + +struct timeval +tv_adjust (struct timeval a) +{ + while (a.tv_usec >= 1000000) + { + a.tv_usec -= 1000000; + a.tv_sec++; + } + + while (a.tv_usec < 0) + { + a.tv_usec += 1000000; + a.tv_sec--; + } + + return a; +} + +int +tv_ceil (struct timeval a) +{ + a = tv_adjust (a); + + return (a.tv_usec ? a.tv_sec + 1 : a.tv_sec); +} + +int +tv_floor (struct timeval a) +{ + a = tv_adjust (a); + + return a.tv_sec; +} + +struct timeval +int2tv (int a) +{ + struct timeval ret; + + ret.tv_sec = a; + ret.tv_usec = 0; + + return ret; +} + +struct timeval +tv_add (struct timeval a, struct timeval b) +{ + struct timeval ret; + + ret.tv_sec = a.tv_sec + b.tv_sec; + ret.tv_usec = a.tv_usec + b.tv_usec; + + return tv_adjust (ret); +} + +struct timeval +tv_sub (struct timeval a, struct timeval b) +{ + struct timeval ret; + + ret.tv_sec = a.tv_sec - b.tv_sec; + ret.tv_usec = a.tv_usec - b.tv_usec; + + return tv_adjust (ret); +} + +int +tv_cmp (struct timeval a, struct timeval b) +{ + return (a.tv_sec == b.tv_sec ? + a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec); +} + +int +ospf_lsa_refresh_delay (struct ospf_lsa *lsa) +{ + struct timeval delta, now; + int delay = 0; + + gettimeofday (&now, NULL); + delta = tv_sub (now, lsa->tv_orig); + + if (tv_cmp (delta, int2tv (OSPF_MIN_LS_INTERVAL)) < 0) + { + delay = tv_ceil (tv_sub (int2tv (OSPF_MIN_LS_INTERVAL), delta)); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type%d:%s]: Refresh timer delay %d seconds", + lsa->data->type, inet_ntoa (lsa->data->id), delay); + + assert (delay > 0); + } + + return delay; +} + + +int +get_age (struct ospf_lsa *lsa) +{ + int age; + struct timeval now; + + gettimeofday (&now, NULL); + age = ntohs (lsa->data->ls_age) + tv_floor (tv_sub (now, lsa->tv_recv)); + + return age; +} + + +/* Fletcher Checksum -- Refer to RFC1008. */ +#define MODX 4102 +#define LSA_CHECKSUM_OFFSET 15 + +u_int16_t +ospf_lsa_checksum (struct lsa_header *lsa) +{ + u_char *sp, *ep, *p, *q; + int c0 = 0, c1 = 0; + int x, y; + u_int16_t length; + + lsa->checksum = 0; + length = ntohs (lsa->length) - 2; + sp = (char *) &lsa->options; + + for (ep = sp + length; sp < ep; sp = q) + { + q = sp + MODX; + if (q > ep) + q = ep; + for (p = sp; p < q; p++) + { + c0 += *p; + c1 += c0; + } + c0 %= 255; + c1 %= 255; + } + + x = ((length - LSA_CHECKSUM_OFFSET) * c0 - c1) % 255; + if (x <= 0) + x += 255; + y = 510 - c0 - x; + if (y > 255) + y -= 255; + + /* take care endian issue. */ + lsa->checksum = htons ((x << 8) + y); + + return (lsa->checksum); +} + + + +/* Create OSPF LSA. */ +struct ospf_lsa * +ospf_lsa_new () +{ + struct ospf_lsa *new; + + new = XCALLOC (MTYPE_OSPF_LSA, sizeof (struct ospf_lsa)); + memset (new, 0, sizeof (struct ospf_lsa)); + + new->flags = 0; + new->lock = 1; + new->retransmit_counter = 0; + gettimeofday (&new->tv_recv, NULL); + new->tv_orig = new->tv_recv; + new->refresh_list = -1; + + return new; +} + +/* Duplicate OSPF LSA. */ +struct ospf_lsa * +ospf_lsa_dup (struct ospf_lsa *lsa) +{ + struct ospf_lsa *new; + + if (lsa == NULL) + return NULL; + + new = XCALLOC (MTYPE_OSPF_LSA, sizeof (struct ospf_lsa)); + + memcpy (new, lsa, sizeof (struct ospf_lsa)); + UNSET_FLAG (new->flags, OSPF_LSA_DISCARD); + new->lock = 1; + new->retransmit_counter = 0; + new->data = ospf_lsa_data_dup (lsa->data); + + return new; +} + +/* Free OSPF LSA. */ +void +ospf_lsa_free (struct ospf_lsa *lsa) +{ + assert (lsa->lock == 0); + + if (IS_DEBUG_OSPF (lsa, LSA)) + zlog_info ("LSA: freed %p", lsa); + + /* Delete LSA data. */ + if (lsa->data != NULL) + ospf_lsa_data_free (lsa->data); + + assert (lsa->refresh_list < 0); + + memset (lsa, 0, sizeof (struct ospf_lsa)); + XFREE (MTYPE_OSPF_LSA, lsa); +} + +/* Lock LSA. */ +struct ospf_lsa * +ospf_lsa_lock (struct ospf_lsa *lsa) +{ + lsa->lock++; + return lsa; +} + +/* Unlock LSA. */ +void +ospf_lsa_unlock (struct ospf_lsa *lsa) +{ + /* This is sanity check. */ + if (!lsa) + return; + + lsa->lock--; + + assert (lsa->lock >= 0); + + if (lsa->lock == 0) + { + assert (CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD)); + ospf_lsa_free (lsa); + } +} + +/* Check discard flag. */ +void +ospf_lsa_discard (struct ospf_lsa *lsa) +{ + if (!CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD)) + { + SET_FLAG (lsa->flags, OSPF_LSA_DISCARD); + ospf_lsa_unlock (lsa); + } +} + +/* Create LSA data. */ +struct lsa_header * +ospf_lsa_data_new (size_t size) +{ + struct lsa_header *new; + + new = (struct lsa_header *) XMALLOC (MTYPE_OSPF_LSA_DATA, size); + memset (new, 0, size); + + return new; +} + +/* Duplicate LSA data. */ +struct lsa_header * +ospf_lsa_data_dup (struct lsa_header *lsah) +{ + struct lsa_header *new; + + new = ospf_lsa_data_new (ntohs (lsah->length)); + memcpy (new, lsah, ntohs (lsah->length)); + + return new; +} + +/* Free LSA data. */ +void +ospf_lsa_data_free (struct lsa_header *lsah) +{ + if (IS_DEBUG_OSPF (lsa, LSA)) + zlog_info ("LSA[Type%d:%s]: data freed %p", + lsah->type, inet_ntoa (lsah->id), lsah); + + XFREE (MTYPE_OSPF_LSA_DATA, lsah); +} + + +/* LSA general functions. */ + +const char * +dump_lsa_key (struct ospf_lsa *lsa) +{ + static char buf[] = { + "Type255,id(255.255.255.255),ar(255.255.255.255)", + }; + struct lsa_header *lsah; + + if (lsa != NULL && (lsah = lsa->data) != NULL) + { + char id[INET_ADDRSTRLEN], ar[INET_ADDRSTRLEN]; + strcpy (id, inet_ntoa (lsah->id)); + strcpy (ar, inet_ntoa (lsah->adv_router)); + + sprintf (buf, "Type%d,id(%s),ar(%s)", lsah->type, id, ar); + } + else + strcpy (buf, "NULL"); + + return buf; +} + +u_int32_t +lsa_seqnum_increment (struct ospf_lsa *lsa) +{ + u_int32_t seqnum; + + seqnum = ntohl (lsa->data->ls_seqnum) + 1; + + return htonl (seqnum); +} + +void +lsa_header_set (struct stream *s, u_char options, + u_char type, struct in_addr id) +{ + struct lsa_header *lsah; + + lsah = (struct lsa_header *) STREAM_DATA (s); + + lsah->ls_age = htons (0); + lsah->options = options; + lsah->type = type; + lsah->id = id; + lsah->adv_router = ospf_top->router_id; + lsah->ls_seqnum = htonl (OSPF_INITIAL_SEQUENCE_NUMBER); + + ospf_output_forward (s, OSPF_LSA_HEADER_SIZE); +} + +/* router-LSA related functions. */ +/* Get router-LSA flags. */ +u_char +router_lsa_flags (struct ospf_area *area) +{ + u_char flags; + + flags = ospf_top->flags; + + /* Set virtual link flag. */ + if (ospf_full_virtual_nbrs (area)) + SET_FLAG (flags, ROUTER_LSA_VIRTUAL); + else + /* Just sanity check */ + UNSET_FLAG (flags, ROUTER_LSA_VIRTUAL); + + /* Set Shortcut ABR behabiour flag. */ + UNSET_FLAG (flags, ROUTER_LSA_SHORTCUT); + if (ospf_top->abr_type == OSPF_ABR_SHORTCUT) + if (!OSPF_IS_AREA_BACKBONE (area)) + if ((area->shortcut_configured == OSPF_SHORTCUT_DEFAULT && + !ospf_top->backbone) || + area->shortcut_configured == OSPF_SHORTCUT_ENABLE) + SET_FLAG (flags, ROUTER_LSA_SHORTCUT); + + /* ASBR can't exit in stub area. */ + if (area->external_routing == OSPF_AREA_STUB) + UNSET_FLAG (flags, OSPF_FLAG_ASBR); + + return flags; +} + +/* Lookup neighbor other than myself. + And check neighbor count, + Point-to-Point link must have only 1 neighbor. */ +struct ospf_neighbor * +ospf_nbr_lookup_ptop (struct route_table *nbrs, struct in_addr router_id) +{ + struct route_node *rn; + struct ospf_neighbor *nbr = NULL; + + /* Search neighbor, there must be one of two nbrs. */ + for (rn = route_top (nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL) + /* Ignore myself. */ + if (!IPV4_ADDR_SAME (&nbr->router_id, &ospf_top->router_id)) + if (nbr->state == NSM_Full) + break; + + /* PtoP link must have only 1 neighbor. */ + if (ospf_nbr_count (nbrs, 0) > 1) + zlog_warn ("Point-to-Point link has more than 1 neighobrs."); + + return nbr; +} + +/* Set a link information. */ +void +link_info_set (struct stream *s, struct in_addr id, + struct in_addr data, u_char type, u_char tos, u_int16_t cost) +{ + /* TOS based routing is not supported. */ + stream_put_ipv4 (s, id.s_addr); /* Link ID. */ + stream_put_ipv4 (s, data.s_addr); /* Link Data. */ + stream_putc (s, type); /* Link Type. */ + stream_putc (s, tos); /* TOS = 0. */ + stream_putw (s, cost); /* Link Cost. */ +} + +/* Describe Point-to-Point link. */ +int +lsa_link_ptop_set (struct stream *s, struct ospf_interface *oi) +{ + int links = 0; + struct ospf_neighbor *nbr; + struct in_addr id, mask; + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type1]: Set link Point-to-Point"); + + if ((nbr = ospf_nbr_lookup_ptop (oi->nbrs, ospf_top->router_id))) + if (nbr->state == NSM_Full) + { + /* For unnumbered point-to-point networks, the Link Data field + should specify the interface's MIB-II ifIndex value. */ + link_info_set (s, nbr->router_id, oi->address->u.prefix4, + LSA_LINK_TYPE_POINTOPOINT, 0, oi->output_cost); + links++; + } + + if (oi->connected->destination != NULL) + { + /* Option 1: + link_type = LSA_LINK_TYPE_STUB; + link_id = nbr->address.u.prefix4; + link_data.s_addr = 0xffffffff; + link_cost = o->output_cost; */ + + id.s_addr = oi->connected->destination->u.prefix4.s_addr; + mask.s_addr = 0xffffffff; + link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost); + } + else + { + /* Option 2: We need to include link to a stub + network regardless of the state of the neighbor */ + masklen2ip (oi->address->prefixlen, &mask); + id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; + link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost); + } + links++; + + return links; +} + +/* Describe Broadcast Link. */ +int +lsa_link_broadcast_set (struct stream *s, struct ospf_interface *oi) +{ + struct ospf_neighbor *dr; + struct in_addr id, mask; + + /* Describe Type 3 Link. */ + if (oi->state == ISM_Waiting) + { + masklen2ip (oi->address->prefixlen, &mask); + id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; + link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost); + return 1; + } + + dr = ospf_nbr_lookup_by_addr (oi->nbrs, &DR (oi)); + /* Describe Type 2 link. */ + if (dr && (dr->state == NSM_Full || + IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))) && + ospf_nbr_count (oi->nbrs, NSM_Full) > 0) + { + link_info_set (s, DR (oi), oi->address->u.prefix4, + LSA_LINK_TYPE_TRANSIT, 0, oi->output_cost); + } + /* Describe type 3 link. */ + else + { + masklen2ip (oi->address->prefixlen, &mask); + id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; + link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost); + } + return 1; +} + +int +lsa_link_loopback_set (struct stream *s, struct ospf_interface *oi) +{ + struct in_addr id, mask; + + /* Describe Type 3 Link. */ + if (oi->state != ISM_Loopback) + return 0; + + mask.s_addr = 0xffffffff; + id.s_addr = oi->address->u.prefix4.s_addr; + link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost); + return 1; +} + +/* Describe Virtual Link. */ +int +lsa_link_virtuallink_set (struct stream *s, struct ospf_interface *oi) +{ + struct ospf_neighbor *nbr; + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type1]: Set link type VL, state %d", oi->state); + + if (oi->state == ISM_PointToPoint) + if ((nbr = ospf_nbr_lookup_ptop (oi->nbrs, ospf_top->router_id))) + if (nbr->state == NSM_Full) + { + link_info_set (s, nbr->router_id, oi->address->u.prefix4, + LSA_LINK_TYPE_VIRTUALLINK, 0, oi->output_cost); + return 1; + } + + return 0; +} + +#define lsa_link_nbma_set(S,O) lsa_link_broadcast_set (S, O) + +/* Set router-LSA link information. */ +int +router_lsa_link_set (struct stream *s, struct ospf_area *area) +{ + listnode node; + int links = 0; + + for (node = listhead (area->oiflist); node; node = nextnode (node)) + { + struct ospf_interface *oi = node->data; + struct interface *ifp = oi->ifp; + + /* Check interface is up, OSPF is enable. */ + if (if_is_up (ifp)) + { + if (oi->state != ISM_Down) + { + /* Describe each link. */ + switch (oi->type) + { + case OSPF_IFTYPE_POINTOPOINT: + links += lsa_link_ptop_set (s, oi); + break; + case OSPF_IFTYPE_BROADCAST: + links += lsa_link_broadcast_set (s, oi); + break; + case OSPF_IFTYPE_NBMA: + links += lsa_link_nbma_set (s, oi); + break; + case OSPF_IFTYPE_POINTOMULTIPOINT: + /* Not supproted yet. */ + break; + case OSPF_IFTYPE_VIRTUALLINK: + links += lsa_link_virtuallink_set (s, oi); + break; + case OSPF_IFTYPE_LOOPBACK: + links += lsa_link_loopback_set (s, oi); + } + } + } + } + + return links; +} + +/* Set router-LSA body. */ +void +ospf_router_lsa_body_set (struct stream *s, struct ospf_area *area) +{ + unsigned long putp; + u_int16_t cnt; + + /* Set flags. */ + stream_putc (s, router_lsa_flags (area)); + + /* Set Zero fields. */ + stream_putc (s, 0); + + /* Keep pointer to # links. */ + putp = s->putp; + + /* Forward word */ + stream_putw(s, 0); + + /* Set all link information. */ + cnt = router_lsa_link_set (s, area); + + /* Set # of links here. */ + stream_putw_at (s, putp, cnt); +} + +/* Create new router-LSA. */ +struct ospf_lsa * +ospf_router_lsa_new (struct ospf_area *area) +{ + struct stream *s; + struct lsa_header *lsah; + struct ospf_lsa *new; + int length; + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type1]: Create router-LSA instance"); + + /* Create a stream for LSA. */ + s = stream_new (OSPF_MAX_LSA_SIZE); + lsah = (struct lsa_header *) STREAM_DATA (s); + +#ifdef HAVE_NSSA + /* Set LSA common header fields. */ + lsa_header_set (s, LSA_OPTIONS_GET (area) | LSA_NSSA_GET (area), + OSPF_ROUTER_LSA, ospf_top->router_id); +#else /* ! HAVE_NSSA */ + /* Set LSA common header fields. */ + lsa_header_set (s, LSA_OPTIONS_GET (area), + OSPF_ROUTER_LSA, ospf_top->router_id); +#endif /* HAVE_NSSA */ + + /* Set router-LSA body fields. */ + ospf_router_lsa_body_set (s, area); + + /* Set length. */ + length = stream_get_endp (s); + lsah->length = htons (length); + + /* Now, create OSPF LSA instance. */ + new = ospf_lsa_new (); + new->area = area; + SET_FLAG (new->flags, OSPF_LSA_SELF); + + /* Copy LSA data to store, discard stream. */ + new->data = ospf_lsa_data_new (length); + memcpy (new->data, lsah, length); + stream_free (s); + + return new; +} + +/* Originate Router-LSA. */ +struct ospf_lsa * +ospf_router_lsa_originate (struct ospf_area *area) +{ + struct ospf_lsa *new; + + /* Create new router-LSA instance. */ + new = ospf_router_lsa_new (area); + + /* Sanity check. */ + if (new->data->adv_router.s_addr == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type1]: AdvRouter is 0, discard"); + ospf_lsa_discard (new); + return NULL; + } + + /* Install LSA to LSDB. */ + new = ospf_lsa_install (NULL, new); + + /* Update LSA origination count. */ + ospf_top->lsa_originate_count++; + + /* Flooding new LSA through area. */ + ospf_flood_through_area (area, NULL, new); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: Originate router-LSA %p", + new->data->type, inet_ntoa (new->data->id), new); + ospf_lsa_header_dump (new->data); + } + + return new; +} + +/* Refresh router-LSA. */ +struct ospf_lsa * +ospf_router_lsa_refresh (struct ospf_lsa *lsa) +{ + struct ospf_area *area = lsa->area; + struct ospf_lsa *new; + + /* Sanity check. */ + assert (lsa->data); + + /* Delete LSA from neighbor retransmit-list. */ + ospf_ls_retransmit_delete_nbr_all (area, lsa); + + /* Create new router-LSA instance. */ + new = ospf_router_lsa_new (area); + new->data->ls_seqnum = lsa_seqnum_increment (lsa); + + ospf_lsa_install (NULL, new); + + /* Flood LSA through area. */ + ospf_flood_through_area (area, NULL, new); + + /* Debug logging. */ + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: router-LSA refresh", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_header_dump (new->data); + } + + return NULL; +} + +int +ospf_router_lsa_timer (struct thread *t) +{ + struct ospf_area *area; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Timer[router-LSA]: (router-LSA Refresh expire)"); + + area = THREAD_ARG (t); + area->t_router_lsa_self = NULL; + + /* Now refresh router-LSA. */ + if (area->router_lsa_self) + ospf_router_lsa_refresh (area->router_lsa_self); + /* Newly originate router-LSA. */ + else + ospf_router_lsa_originate (area); + + return 0; +} + +void +ospf_router_lsa_timer_add (struct ospf_area *area) +{ + /* Keep area's self-originated router-LSA. */ + struct ospf_lsa *lsa = area->router_lsa_self; + + /* Cancel previously scheduled router-LSA timer. */ + if (area->t_router_lsa_self) + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type1]: Cancel previous router-LSA timer"); + + OSPF_TIMER_OFF (area->t_router_lsa_self); + + /* If router-LSA is originated previously, check the interval time. */ + if (lsa) + { + int delay; + if ((delay = ospf_lsa_refresh_delay (lsa)) > 0) + { + OSPF_AREA_TIMER_ON (area->t_router_lsa_self, + ospf_router_lsa_timer, delay); + return; + } + } + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type1]: Scheduling router-LSA origination right away"); + + /* Immediately refresh router-LSA. */ + OSPF_AREA_TIMER_ON (area->t_router_lsa_self, ospf_router_lsa_timer, 0); +} + +int +ospf_router_lsa_update_timer (struct thread *t) +{ + listnode node; + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("Timer[router-LSA Update]: (timer expire)"); + + ospf_top->t_router_lsa_update = NULL; + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + struct ospf_area *area = getdata (node); + struct ospf_lsa *lsa = area->router_lsa_self; + struct router_lsa *rl; + char *area_str; + + /* Keep Area ID string. */ + area_str = AREA_NAME (area); + + /* If LSA not exist in this Area, originate new. */ + if (lsa == NULL) + { + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info("LSA[Type1]: Create router-LSA for Area %s", area_str); + + ospf_router_lsa_originate (area); + } + /* If router-ID is changed, Link ID must change. + First flush old LSA, then originate new. */ + else if (!IPV4_ADDR_SAME (&lsa->data->id, &ospf_top->router_id)) + { + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info("LSA[Type%d:%s]: Refresh router-LSA for Area %s", + lsa->data->type, inet_ntoa (lsa->data->id), area_str); + ospf_lsa_flush_area (lsa, area); + ospf_lsa_unlock (area->router_lsa_self); + area->router_lsa_self = NULL; + + /* Refresh router-LSA, (not install) and flood through area. */ + ospf_router_lsa_timer_add (area); + } + else + { + rl = (struct router_lsa *) lsa->data; + /* Refresh router-LSA, (not install) and flood through area. */ + if (rl->flags != ospf_top->flags) + ospf_router_lsa_timer_add (area); + } + } + + return 0; +} + + +/* network-LSA related functions. */ +/* Originate Network-LSA. */ +void +ospf_network_lsa_body_set (struct stream *s, struct ospf_interface *oi) +{ + struct in_addr mask; + struct route_node *rn; + struct ospf_neighbor *nbr; + + masklen2ip (oi->address->prefixlen, &mask); + stream_put_ipv4 (s, mask.s_addr); + + /* The network-LSA lists those routers that are fully adjacent to + the Designated Router; each fully adjacent router is identified by + its OSPF Router ID. The Designated Router includes itself in this + list. RFC2328, Section 12.4.2 */ + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL) + if (nbr->state == NSM_Full || nbr == oi->nbr_self) + stream_put_ipv4 (s, nbr->router_id.s_addr); +} + +struct ospf_lsa * +ospf_network_lsa_new (struct ospf_interface *oi) +{ + struct stream *s; + struct ospf_lsa *new; + struct lsa_header *lsah; + int length; + + /* If there are no neighbours on this network (the net is stub), + the router does not originate network-LSA (see RFC 12.4.2) */ + if (oi->full_nbrs == 0) + return NULL; + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type2]: Create network-LSA instance"); + + /* Create new stream for LSA. */ + s = stream_new (OSPF_MAX_LSA_SIZE); + lsah = (struct lsa_header *) STREAM_DATA (s); + + lsa_header_set (s, (OPTIONS (oi) | LSA_OPTIONS_GET (oi->area)), + OSPF_NETWORK_LSA, DR (oi)); + + /* Set network-LSA body fields. */ + ospf_network_lsa_body_set (s, oi); + + /* Set length. */ + length = stream_get_endp (s); + lsah->length = htons (length); + + /* Create OSPF LSA instance. */ + new = ospf_lsa_new (); + new->area = oi->area; + SET_FLAG (new->flags, OSPF_LSA_SELF); + + /* Copy LSA to store. */ + new->data = ospf_lsa_data_new (length); + memcpy (new->data, lsah, length); + stream_free (s); + + return new; +} + +/* Originate network-LSA. */ +struct ospf_lsa * +ospf_network_lsa_originate (struct ospf_interface *oi) +{ + struct ospf_lsa *new; + + /* Create new network-LSA instance. */ + new = ospf_network_lsa_new (oi); + if (new == NULL) + return NULL; + + /* Install LSA to LSDB. */ + new = ospf_lsa_install (oi, new); + + /* Update LSA origination count. */ + ospf_top->lsa_originate_count++; + + /* Flooding new LSA through area. */ + ospf_flood_through_area (oi->area, NULL, new); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: Originate network-LSA %p", + new->data->type, inet_ntoa (new->data->id), new); + ospf_lsa_header_dump (new->data); + } + + return new; +} + +int +ospf_network_lsa_refresh (struct ospf_lsa *lsa, struct ospf_interface *oi) +{ + struct ospf_area *area = lsa->area; + struct ospf_lsa *new; + + assert (lsa->data); + + /* Delete LSA from neighbor retransmit-list. */ + ospf_ls_retransmit_delete_nbr_all (area, lsa); + + /* Create new network-LSA instance. */ + new = ospf_network_lsa_new (oi); + if (new == NULL) + return -1; + new->data->ls_seqnum = lsa_seqnum_increment (lsa); + + ospf_lsa_install (oi, new); + + /* Flood LSA through aera. */ + ospf_flood_through_area (area, NULL, new); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: network-LSA refresh", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_header_dump (new->data); + } + + return 0; +} + +int +ospf_network_lsa_refresh_timer (struct thread *t) +{ + struct ospf_interface *oi; + + oi = THREAD_ARG (t); + oi->t_network_lsa_self = NULL; + + if (oi->network_lsa_self) + /* Now refresh network-LSA. */ + ospf_network_lsa_refresh (oi->network_lsa_self, oi); + else + /* Newly create network-LSA. */ + ospf_network_lsa_originate (oi); + + return 0; +} + +void +ospf_network_lsa_timer_add (struct ospf_interface *oi) +{ + /* Keep interface's self-originated network-LSA. */ + struct ospf_lsa *lsa = oi->network_lsa_self; + + /* Cancel previously schedules network-LSA timer. */ + if (oi->t_network_lsa_self) + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type2]: Cancel previous network-LSA timer"); + OSPF_TIMER_OFF (oi->t_network_lsa_self); + + /* If network-LSA is originated previously, check the interval time. */ + if (lsa) + { + int delay; + if ((delay = ospf_lsa_refresh_delay (lsa)) > 0) + { + oi->t_network_lsa_self = + thread_add_timer (master, ospf_network_lsa_refresh_timer, + oi, delay); + return; + } + } + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("Scheduling network-LSA origination right away"); + + /* Immediately refresh network-LSA. */ + oi->t_network_lsa_self = + thread_add_event (master, ospf_network_lsa_refresh_timer, oi, 0); +} + + +void +stream_put_ospf_metric (struct stream *s, u_int32_t metric_value) +{ + u_int32_t metric; + char *mp; + + /* Put 0 metric. TOS metric is not supported. */ + metric = htonl (metric_value); + mp = (char *) &metric; + mp++; + stream_put (s, mp, 3); +} + +/* summary-LSA related functions. */ +void +ospf_summary_lsa_body_set (struct stream *s, struct prefix *p, + u_int32_t metric) +{ + struct in_addr mask; + + masklen2ip (p->prefixlen, &mask); + + /* Put Network Mask. */ + stream_put_ipv4 (s, mask.s_addr); + + /* Set # TOS. */ + stream_putc (s, (u_char) 0); + + /* Set metric. */ + stream_put_ospf_metric (s, metric); +} + +struct ospf_lsa * +ospf_summary_lsa_new (struct ospf_area *area, struct prefix *p, + u_int32_t metric, struct in_addr id) +{ + struct stream *s; + struct ospf_lsa *new; + struct lsa_header *lsah; + int length; + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type3]: Create summary-LSA instance"); + + /* Create new stream for LSA. */ + s = stream_new (OSPF_MAX_LSA_SIZE); + lsah = (struct lsa_header *) STREAM_DATA (s); + + lsa_header_set (s, LSA_OPTIONS_GET (area), OSPF_SUMMARY_LSA, id); + + /* Set summary-LSA body fields. */ + ospf_summary_lsa_body_set (s, p, metric); + + /* Set length. */ + length = stream_get_endp (s); + lsah->length = htons (length); + + /* Create OSPF LSA instance. */ + new = ospf_lsa_new (); + new->area = area; + SET_FLAG (new->flags, OSPF_LSA_SELF); + + /* Copy LSA to store. */ + new->data = ospf_lsa_data_new (length); + memcpy (new->data, lsah, length); + stream_free (s); + + return new; +} + +/* Originate Summary-LSA. */ +struct ospf_lsa * +ospf_summary_lsa_originate (struct prefix_ipv4 *p, u_int32_t metric, + struct ospf_area *area) +{ + struct ospf_lsa *new; + struct in_addr id; + + id = ospf_lsa_unique_id (area->lsdb, OSPF_SUMMARY_LSA, p); + + /* Create new summary-LSA instance. */ + new = ospf_summary_lsa_new (area, (struct prefix *) p, metric, id); + + /* Instlal LSA to LSDB. */ + new = ospf_lsa_install (NULL, new); + + /* Update LSA origination count. */ + ospf_top->lsa_originate_count++; + + /* Flooding new LSA through area. */ + ospf_flood_through_area (area, NULL, new); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: Originate summary-LSA %p", + new->data->type, inet_ntoa (new->data->id), new); + ospf_lsa_header_dump (new->data); + } + + return new; +} + +struct ospf_lsa* +ospf_summary_lsa_refresh (struct ospf_lsa *lsa) +{ + struct ospf_lsa *new; + struct summary_lsa *sl; + struct prefix p; + + /* Sanity check. */ + assert (lsa->data); + + sl = (struct summary_lsa *)lsa->data; + p.prefixlen = ip_masklen (sl->mask); + new = ospf_summary_lsa_new (lsa->area, &p, GET_METRIC (sl->metric), + sl->header.id); + + new->data->ls_seqnum = lsa_seqnum_increment (lsa); + + /* Re-calculate checksum. */ + ospf_lsa_checksum (new->data); + + ospf_lsa_install (NULL, new); + + /* Flood LSA through AS. */ + ospf_flood_through_area (new->area, NULL, new); + + /* Debug logging. */ + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: summary-LSA refresh", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_header_dump (new->data); + } + + return new; +} + + +/* summary-ASBR-LSA related functions. */ +void +ospf_summary_asbr_lsa_body_set (struct stream *s, struct prefix *p, + u_int32_t metric) +{ + struct in_addr mask; + + masklen2ip (p->prefixlen, &mask); + + /* Put Network Mask. */ + stream_put_ipv4 (s, mask.s_addr); + + /* Set # TOS. */ + stream_putc (s, (u_char) 0); + + /* Set metric. */ + stream_put_ospf_metric (s, metric); +} + +struct ospf_lsa * +ospf_summary_asbr_lsa_new (struct ospf_area *area, struct prefix *p, + u_int32_t metric, struct in_addr id) +{ + struct stream *s; + struct ospf_lsa *new; + struct lsa_header *lsah; + int length; + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type3]: Create summary-LSA instance"); + + /* Create new stream for LSA. */ + s = stream_new (OSPF_MAX_LSA_SIZE); + lsah = (struct lsa_header *) STREAM_DATA (s); + + lsa_header_set (s, LSA_OPTIONS_GET (area), OSPF_ASBR_SUMMARY_LSA, id); + + /* Set summary-LSA body fields. */ + ospf_summary_asbr_lsa_body_set (s, p, metric); + + /* Set length. */ + length = stream_get_endp (s); + lsah->length = htons (length); + + /* Create OSPF LSA instance. */ + new = ospf_lsa_new (); + new->area = area; + SET_FLAG (new->flags, OSPF_LSA_SELF); + + /* Copy LSA to store. */ + new->data = ospf_lsa_data_new (length); + memcpy (new->data, lsah, length); + stream_free (s); + + return new; +} + +/* Originate summary-ASBR-LSA. */ +struct ospf_lsa * +ospf_summary_asbr_lsa_originate (struct prefix_ipv4 *p, u_int32_t metric, + struct ospf_area *area) +{ + struct ospf_lsa *new; + struct in_addr id; + + id = ospf_lsa_unique_id (area->lsdb, OSPF_ASBR_SUMMARY_LSA, p); + + /* Create new summary-LSA instance. */ + new = ospf_summary_asbr_lsa_new (area, (struct prefix *) p, metric, id); + + /* Install LSA to LSDB. */ + new = ospf_lsa_install (NULL, new); + + /* Update LSA origination count. */ + ospf_top->lsa_originate_count++; + + /* Flooding new LSA through area. */ + ospf_flood_through_area (area, NULL, new); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: Originate summary-ASBR-LSA %p", + new->data->type, inet_ntoa (new->data->id), new); + ospf_lsa_header_dump (new->data); + } + + return new; +} + +struct ospf_lsa* +ospf_summary_asbr_lsa_refresh (struct ospf_lsa *lsa) +{ + struct ospf_lsa *new; + struct summary_lsa *sl; + struct prefix p; + + /* Sanity check. */ + assert (lsa->data); + + sl = (struct summary_lsa *)lsa->data; + p.prefixlen = ip_masklen (sl->mask); + new = ospf_summary_asbr_lsa_new (lsa->area, &p, GET_METRIC (sl->metric), + sl->header.id); + + new->data->ls_seqnum = lsa_seqnum_increment (lsa); + + /* Re-calculate checksum. */ + ospf_lsa_checksum (new->data); + + ospf_lsa_install (NULL, new); + + /* Flood LSA through area. */ + ospf_flood_through_area (new->area, NULL, new); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: summary-ASBR-LSA refresh", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_header_dump (new->data); + } + + return new; +} + +/* AS-external-LSA related functions. */ + +/* Get nexthop for AS-external-LSAs. Return nexthop if its interface + is connected, else 0*/ +struct in_addr +ospf_external_lsa_nexthop_get (struct in_addr nexthop) +{ + struct in_addr fwd; + struct prefix nh; + /* struct route_node *rn; */ + listnode n1; + + fwd.s_addr = 0; + + if (!nexthop.s_addr) + return fwd; + + /* Check whether nexthop is covered by OSPF network. */ + nh.family = AF_INET; + nh.u.prefix4 = nexthop; + nh.prefixlen = IPV4_MAX_BITLEN; + + for (n1 = listhead (ospf_top->oiflist); n1; nextnode (n1)) + { + struct ospf_interface *oi = getdata (n1); + + if (if_is_up (oi->ifp)) + if (oi->address->family == AF_INET) + if (prefix_match (oi->address, &nh)) + return nexthop; + } + + return fwd; +} + +#ifdef HAVE_NSSA +/* NSSA-external-LSA related functions. */ + +/* Get 1st IP connection for Forward Addr */ + +struct in_addr +ospf_get_ip_from_ifp (struct ospf_interface *oi) +{ + struct in_addr fwd; + + fwd.s_addr = 0; + + if (if_is_up (oi->ifp)) + return oi->address->u.prefix4; + + return fwd; +} + +/* Get 1st IP connection for Forward Addr */ +struct in_addr +ospf_get_nssa_ip (void) +{ + struct in_addr fwd; + listnode n1; + + fwd.s_addr = 0; + + + for (n1 = listhead (ospf_top->oiflist); n1; nextnode (n1)) + { + struct ospf_interface *oi = getdata (n1); + + if (if_is_up (oi->ifp)) + if (oi->area->external_routing == OSPF_AREA_NSSA) + if (oi->address && oi->address->family == AF_INET) + return (oi->address->u.prefix4 ); + } + + return fwd; +} +#endif /* HAVE_NSSA */ + +#define DEFAULT_DEFAULT_METRIC 20 +#define DEFAULT_DEFAULT_ORIGINATE_METRIC 10 +#define DEFAULT_DEFAULT_ALWAYS_METRIC 1 + +#define DEFAULT_METRIC_TYPE EXTERNAL_METRIC_TYPE_2 + +int +metric_type (u_char src) +{ + return (ospf_top->dmetric[src].type < 0 ? + DEFAULT_METRIC_TYPE : ospf_top->dmetric[src].type); +} + +int +metric_value (u_char src) +{ + if (ospf_top->dmetric[src].value < 0) + { + if (src == DEFAULT_ROUTE) + { + if (ospf_top->default_originate == DEFAULT_ORIGINATE_ZEBRA) + return DEFAULT_DEFAULT_ORIGINATE_METRIC; + else + return DEFAULT_DEFAULT_ALWAYS_METRIC; + } + else if (ospf_top->default_metric < 0) + return DEFAULT_DEFAULT_METRIC; + else + return ospf_top->default_metric; + } + + return ospf_top->dmetric[src].value; +} + +/* Set AS-external-LSA body. */ +void +ospf_external_lsa_body_set (struct stream *s, struct external_info *ei) +{ + struct prefix_ipv4 *p = &ei->p; + struct in_addr mask, fwd_addr; + u_int32_t mvalue; + int mtype; + int type; + + /* Put Network Mask. */ + masklen2ip (p->prefixlen, &mask); + stream_put_ipv4 (s, mask.s_addr); + + /* If prefix is default, specify DEFAULT_ROUTE. */ + type = is_prefix_default (&ei->p) ? DEFAULT_ROUTE : ei->type; + + mtype = (ROUTEMAP_METRIC_TYPE (ei) != -1) ? + ROUTEMAP_METRIC_TYPE (ei) : metric_type (type); + + mvalue = (ROUTEMAP_METRIC (ei) != -1) ? + ROUTEMAP_METRIC (ei) : metric_value (type); + + /* Put type of external metric. */ + stream_putc (s, (mtype == EXTERNAL_METRIC_TYPE_2 ? 0x80 : 0)); + + /* Put 0 metric. TOS metric is not supported. */ + stream_put_ospf_metric (s, mvalue); + + /* Get forwarding address to nexthop if on the Connection List, else 0. */ + fwd_addr = ospf_external_lsa_nexthop_get (ei->nexthop); + + /* Put forwarding address. */ + stream_put_ipv4 (s, fwd_addr.s_addr); + + /* Put route tag -- This value should be introduced from configuration. */ + stream_putl (s, 0); +} + +/* Create new external-LSA. */ +struct ospf_lsa * +ospf_external_lsa_new (struct external_info *ei, struct in_addr *old_id) +{ + struct stream *s; + struct lsa_header *lsah; + struct ospf_lsa *new; + struct in_addr id; + int length; + + if (ei == NULL) + { + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_warn ("LSA[Type5]: External info is NULL, could not originated"); + return NULL; + } + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type5]: Originate AS-external-LSA instance"); + + /* If old Link State ID is specified, refresh LSA with same ID. */ + if (old_id) + id = *old_id; + /* Get Link State with unique ID. */ + else + { + id = ospf_lsa_unique_id (ospf_top->lsdb, OSPF_AS_EXTERNAL_LSA, &ei->p); + if (id.s_addr == 0xffffffff) + { + /* Maybe Link State ID not available. */ + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type5]: Link ID not available, can't originate"); + return NULL; + } + } + + /* Create new stream for LSA. */ + s = stream_new (OSPF_MAX_LSA_SIZE); + lsah = (struct lsa_header *) STREAM_DATA (s); + + /* Set LSA common header fields. */ + lsa_header_set (s, OSPF_OPTION_E, OSPF_AS_EXTERNAL_LSA, id); + + /* Set AS-external-LSA body fields. */ + ospf_external_lsa_body_set (s, ei); + + /* Set length. */ + length = stream_get_endp (s); + lsah->length = htons (length); + + /* Now, create OSPF LSA instance. */ + new = ospf_lsa_new (); + new->area = NULL; + SET_FLAG (new->flags, OSPF_LSA_SELF|OSPF_LSA_APPROVED); + + /* Copy LSA data to store, discard stream. */ + new->data = ospf_lsa_data_new (length); + memcpy (new->data, lsah, length); + stream_free (s); + + return new; +} + +#ifdef HAVE_NSSA +/* Set AS-external-LSA body test. */ +void +ospf_external_lsa_body_test (struct stream *s) +{ + struct in_addr mask, fwd_addr; + u_int32_t mvalue = 0; + /* int mtype; + int type; */ + + mask.s_addr = 0; + fwd_addr.s_addr = 0; + + /* Put Network Mask. */ + /* masklen2ip (p->prefixlen, &mask); */ + stream_put_ipv4 (s, mask.s_addr); + + /* If prefix is default, specify DEFAULT_ROUTE. */ + /* type = is_prefix_default (&ei->p) ? DEFAULT_ROUTE : ei->type; + + mtype = (ROUTEMAP_METRIC_TYPE (ei) != -1) ? + ROUTEMAP_METRIC_TYPE (ei) : metric_type (type); + + mvalue = (ROUTEMAP_METRIC (ei) != -1) ? + ROUTEMAP_METRIC (ei) : metric_value (type); */ + + /* Put type of external metric. */ + stream_putc (s, 0); + + /* Put 0 metric. TOS metric is not supported. */ + stream_put_ospf_metric (s, mvalue); + + + /* fwd_addr = ospf_top->router_id; */ + + /* OLD == ospf_external_lsa_nexthop_get (ei->nexthop); */ + + /* Put forwarding address. */ + /* stream_put_ipv4 (s, fwd_addr.s_addr); */ + stream_put_ipv4 (s, ospf_top->router_id.s_addr); + + /* Put route tag -- This value should be introduced from configuration. */ + stream_putl (s, 0); +} + +/* As Type-7 */ +void +ospf_install_flood_nssa (struct ospf_lsa *lsa, struct external_info *ei) +{ + struct ospf_lsa *new2; + struct as_external_lsa *extlsa; + + /* NSSA Originate or Refresh (If anyNSSA) + + LSA is self-originated. And just installed as Type-5. + Additionally, install as Type-7 LSDB for every attached NSSA. + + P-Bit controls which ABR performs translation to outside world; If + we are an ABR....do not set the P-bit, because we send the Type-5, + not as the ABR Translator, but as the ASBR owner within the AS! + + If we are NOT ABR, Flood through NSSA as Type-7 w/P-bit set. The + elected ABR Translator will see the P-bit, Translate, and re-flood. + + Later, ABR_TASK and P-bit will scan Type-7 LSDB and translate to + Type-5's to non-NSSA Areas. (it will also attempt a re-install) */ + + /* make lsa duplicate, lock=1 */ + new2 = ospf_lsa_dup(lsa); + + /* make type-7 */ + new2->data->type = OSPF_AS_NSSA_LSA; + + /* set P-bit if not ABR */ + if (! OSPF_IS_ABR) + { + SET_FLAG(new2->data->options, OSPF_OPTION_NP); + + /* set non-zero FWD ADDR + + draft-ietf-ospf-nssa-update-09.txt + + if the network between the NSSA AS boundary router and the + adjacent AS is advertised into OSPF as an internal OSPF route, + the forwarding address should be the next op address as is cu + currently done with type-5 LSAs. If the intervening network is + not adversited into OSPF as an internal OSPF route and the + type-7 LSA's P-bit is set a forwarding address should be + selected from one of the router's active OSPF inteface addresses + which belong to the NSSA. If no such addresses exist, then + no type-7 LSA's with the P-bit set should originate from this + router. */ + + extlsa = (struct as_external_lsa *)(lsa->data); + + if (extlsa->e[0].fwd_addr.s_addr == 0) + extlsa->e[0].fwd_addr = ospf_get_nssa_ip(); /* this NSSA area in ifp */ + + if (IS_DEBUG_OSPF_NSSA) + if (extlsa->e[0].fwd_addr.s_addr == 0) + { + zlog_info ("LSA[Type-7]: Could not build FWD-ADDR"); + ospf_lsa_discard(new2); + return; + } + } + + /* Re-calculate checksum. */ + ospf_lsa_checksum (new2->data); + + /* install also as Type-7 */ + ospf_lsa_install (NULL, new2); /* Remove Old, Lock New = 2 */ + + /* will send each copy, lock=2+n */ + ospf_flood_through_as (NULL, new2); /* all attached NSSA's, no AS/STUBs */ + + /* last send, lock=2 LSA is now permanent in Type-7 LSDB */ + /* It has the same ID as it's Type-5 Counter-Part */ + +} +#endif /* HAVE_NSSA */ + +int +is_prefix_default (struct prefix_ipv4 *p) +{ + struct prefix_ipv4 q; + + q.family = AF_INET; + q.prefix.s_addr = 0; + q.prefixlen = 0; + + return prefix_same ((struct prefix *) p, (struct prefix *) &q); +} + +/* Originate an AS-external-LSA, install and flood. */ +struct ospf_lsa * +ospf_external_lsa_originate (struct external_info *ei) +{ + struct ospf_lsa *new; + + /* Added for NSSA project.... + + External LSAs are originated in ASBRs as usual, but for NSSA systems. + there is the global Type-5 LSDB and a Type-7 LSDB installed for + every area. The Type-7's are flooded to every IR and every ABR; We + install the Type-5 LSDB so that the normal "refresh" code operates + as usual, and flag them as not used during ASE calculations. The + Type-7 LSDB is used for calculations. Each Type-7 has a Forwarding + Address of non-zero. + + If an ABR is the elected NSSA translator, following SPF and during + the ABR task it will translate all the scanned Type-7's, with P-bit + ON and not-self generated, and translate to Type-5's throughout the + non-NSSA/STUB AS. + + A difference in operation depends whether this ASBR is an ABR + or not. If not an ABR, the P-bit is ON, to indicate that any + elected NSSA-ABR can perform its translation. + + If an ABR, the P-bit is OFF; No ABR will perform translation and + this ASBR will flood the Type-5 LSA as usual. + + For the case where this ASBR is not an ABR, the ASE calculations + are based on the Type-5 LSDB; The Type-7 LSDB exists just to + demonstrate to the user that there are LSA's that belong to any + attached NSSA. + + Finally, it just so happens that when the ABR is translating every + Type-7 into Type-5, it installs it into the Type-5 LSDB as an + approved Type-5 (translated from Type-7); at the end of translation + if any Translated Type-5's remain unapproved, then they must be + flushed from the AS. + + */ + + /* Check the AS-external-LSA should be originated. */ + if (!ospf_redistribute_check (ei, NULL)) + return NULL; + + /* Create new AS-external-LSA instance. */ + if ((new = ospf_external_lsa_new (ei, NULL)) == NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type5:%s]: Could not originate AS-external-LSA", + inet_ntoa (ei->p.prefix)); + return NULL; + } + + /* Install newly created LSA into Type-5 LSDB, lock = 1. */ + ospf_lsa_install (NULL, new); + + /* Update LSA origination count. */ + ospf_top->lsa_originate_count++; + + /* Flooding new LSA. only to AS (non-NSSA/STUB) */ + ospf_flood_through_as (NULL, new); + +#ifdef HAVE_NSSA + /* If there is any attached NSSA, do special handling */ + if (ospf_top->anyNSSA) + ospf_install_flood_nssa (new, ei); /* Install/Flood Type-7 to all NSSAs */ +#endif /* HAVE_NSSA */ + + /* Debug logging. */ + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: Originate AS-external-LSA %p", + new->data->type, inet_ntoa (new->data->id), new); + ospf_lsa_header_dump (new->data); + } + + return new; +} + +/* Originate AS-external-LSA from external info with initial flag. */ +int +ospf_external_lsa_originate_timer (struct thread *t) +{ + struct route_node *rn; + struct external_info *ei; + struct route_table *rt; + int type; + + ospf_top->t_external_lsa = NULL; + type = THREAD_VAL (t); + + /* Originate As-external-LSA from all type of distribute source. */ + if ((rt = EXTERNAL_INFO (type))) + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((ei = rn->info) != NULL) + if (!is_prefix_default ((struct prefix_ipv4 *)&ei->p)) + if (!ospf_external_lsa_originate (ei)) + zlog_warn ("LSA: AS-external-LSA was not originated."); + + return 0; +} + +struct external_info * +ospf_default_external_info () +{ + int type; + struct route_node *rn; + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefix.s_addr = 0; + p.prefixlen = 0; + + /* First, lookup redistributed default route. */ + for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) + if (EXTERNAL_INFO (type) && type != ZEBRA_ROUTE_OSPF) + { + rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) &p); + if (rn != NULL) + { + route_unlock_node (rn); + assert (rn->info); + if (ospf_redistribute_check (rn->info, NULL)) + return rn->info; + } + } + + return NULL; +} + +int +ospf_default_originate_timer (struct thread *t) +{ + int *origin; + struct prefix_ipv4 p; + struct in_addr nexthop; + struct external_info *ei; + + /* Get originate flags. */ + origin = THREAD_ARG (t); + + p.family = AF_INET; + p.prefix.s_addr = 0; + p.prefixlen = 0; + + if (*origin == DEFAULT_ORIGINATE_ALWAYS) + { + /* If there is no default route via redistribute, + then originate AS-external-LSA with nexthop 0 (self). */ + nexthop.s_addr = 0; + ospf_external_info_add (DEFAULT_ROUTE, p, 0, nexthop); + } + + if ((ei = ospf_default_external_info ())) + ospf_external_lsa_originate (ei); + + return 0; +} + +/* Flush an AS-external-LSA from LSDB and routing domain. */ +void +ospf_external_lsa_flush (u_char type, struct prefix_ipv4 *p, + unsigned int ifindex, struct in_addr nexthop) +{ + struct ospf_lsa *lsa; + + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("LSA: Flushing AS-external-LSA %s/%d", + inet_ntoa (p->prefix), p->prefixlen); + + /* First lookup LSA from LSDB. */ + if (!(lsa = ospf_external_info_find_lsa (p))) + { + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_warn ("LSA: There is no such AS-external-LSA %s/%d in LSDB", + inet_ntoa (p->prefix), p->prefixlen); + return; + } + + /* Sweep LSA from Link State Retransmit List. */ + ospf_ls_retransmit_delete_nbr_all (NULL, lsa); + + /* There must be no self-originated LSA in rtrs_external. */ +#if 0 + /* Remove External route from Zebra. */ + ospf_zebra_delete ((struct prefix_ipv4 *) p, &nexthop); +#endif + + if (!IS_LSA_MAXAGE (lsa)) + { + /* Unregister LSA from Refresh queue. */ + ospf_refresher_unregister_lsa (ospf_top, lsa); + + /* Flush AS-external-LSA through AS. */ + ospf_flush_through_as (lsa); + } + + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("ospf_external_lsa_flush(): stop"); +} + +void +ospf_external_lsa_refresh_default () +{ + struct prefix_ipv4 p; + struct external_info *ei; + struct ospf_lsa *lsa; + + p.family = AF_INET; + p.prefixlen = 0; + p.prefix.s_addr = 0; + + ei = ospf_default_external_info (); + lsa = ospf_external_info_find_lsa (&p); + + if (ei) + { + if (lsa) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p", lsa); + ospf_external_lsa_refresh (lsa, ei, LSA_REFRESH_FORCE); + } + else + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type5:0.0.0.0]: Originate AS-external-LSA"); + ospf_external_lsa_originate (ei); + } + } + else + { + if (lsa) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type5:0.0.0.0]: Flush AS-external-LSA"); + ospf_lsa_flush_as (lsa); + } + } +} + +void +ospf_external_lsa_refresh_type (u_char type, int force) +{ + struct route_node *rn; + struct external_info *ei; + + if (type != DEFAULT_ROUTE) + if (EXTERNAL_INFO(type)) + /* Refresh each redistributed AS-external-LSAs. */ + for (rn = route_top (EXTERNAL_INFO (type)); rn; rn = route_next (rn)) + if ((ei = rn->info)) + if (!is_prefix_default (&ei->p)) + { + struct ospf_lsa *lsa; + + if ((lsa = ospf_external_info_find_lsa (&ei->p))) + ospf_external_lsa_refresh (lsa, ei, force); + else + ospf_external_lsa_originate (ei); + } +} + +/* Refresh AS-external-LSA. */ +void +ospf_external_lsa_refresh (struct ospf_lsa *lsa, + struct external_info *ei, int force) +{ + struct ospf_lsa *new; + int changed; + + /* Check the AS-external-LSA should be originated. */ + if (!ospf_redistribute_check (ei, &changed)) + { + ospf_external_lsa_flush (ei->type, &ei->p, ei->ifindex, ei->nexthop); + return; + } + + if (!changed && !force) + return; + + /* Delete LSA from neighbor retransmit-list. */ + ospf_ls_retransmit_delete_nbr_all (NULL, lsa); + + /* Unregister AS-external-LSA from refresh-list. */ + ospf_refresher_unregister_lsa (ospf_top, lsa); + + new = ospf_external_lsa_new (ei, &lsa->data->id); + + if (new == NULL) + { + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_warn ("LSA[Type%d:%s]: Could not be refreshed", lsa->data->type, + inet_ntoa (lsa->data->id)); + return; + } + + new->data->ls_seqnum = lsa_seqnum_increment (lsa); + + /* Record timestamp. */ + gettimeofday (&new->tv_orig, NULL); + + /* Re-calculate checksum. */ + ospf_lsa_checksum (new->data); + + ospf_lsa_install (NULL, new); /* As type-5. */ + + /* Flood LSA through AS. */ + ospf_flood_through_as (NULL, new); + +#ifdef HAVE_NSSA + /* If any attached NSSA, install as Type-7, flood to all NSSA Areas */ + if (ospf_top->anyNSSA) + ospf_install_flood_nssa (new, ei); /* Install/Flood per new rules */ +#endif /* HAVE_NSSA */ + + /* Register slef-originated LSA to refresh queue. */ + ospf_refresher_register_lsa (ospf_top, new); + + /* Debug logging. */ + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: AS-external-LSA refresh", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_header_dump (new->data); + } + + return; +} + + +/* LSA installation functions. */ + +/* Install router-LSA to an area. */ +struct ospf_lsa * +ospf_router_lsa_install (struct ospf_lsa *new, int rt_recalc) +{ + struct ospf_area *area = new->area; + + /* RFC 2328 Section 13.2 Router-LSAs and network-LSAs + The entire routing table must be recalculated, starting with + the shortest path calculations for each area (not just the + area whose link-state database has changed). + */ + if (rt_recalc) + ospf_spf_calculate_schedule(); + + if (IS_LSA_SELF (new)) + { + /* Set router-LSA refresh timer. */ + OSPF_TIMER_OFF (area->t_router_lsa_self); + OSPF_AREA_TIMER_ON (area->t_router_lsa_self, + ospf_router_lsa_timer, OSPF_LS_REFRESH_TIME); + + /* Set self-originated router-LSA. */ + ospf_lsa_unlock (area->router_lsa_self); + area->router_lsa_self = ospf_lsa_lock (new); + + if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) + zlog_info("LSA[Type%d]: ID %s is self-originated", + new->data->type, inet_ntoa (new->data->id)); + } + + return new; +} + +#define OSPF_INTERFACE_TIMER_ON(T,F,V) \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), oi, (V)) + +/* Install network-LSA to an area. */ +struct ospf_lsa * +ospf_network_lsa_install (struct ospf_interface *oi, + struct ospf_lsa *new, + int rt_recalc) +{ + + /* RFC 2328 Section 13.2 Router-LSAs and network-LSAs + The entire routing table must be recalculated, starting with + the shortest path calculations for each area (not just the + area whose link-state database has changed). + */ + if (rt_recalc) + ospf_spf_calculate_schedule(); + + /* We supposed that when LSA is originated by us, we pass the int + for which it was originated. If LSA was received by flooding, + the RECEIVED flag is set, so we do not link the LSA to the int. */ + if (IS_LSA_SELF (new) && !CHECK_FLAG (new->flags, OSPF_LSA_RECEIVED)) + { + /* Set LSRefresh timer. */ + OSPF_TIMER_OFF (oi->t_network_lsa_self); + + OSPF_INTERFACE_TIMER_ON (oi->t_network_lsa_self, + ospf_network_lsa_refresh_timer, + OSPF_LS_REFRESH_TIME); + + ospf_lsa_unlock (oi->network_lsa_self); + oi->network_lsa_self = ospf_lsa_lock (new); + } + + return new; +} + +/* Install summary-LSA to an area. */ +struct ospf_lsa * +ospf_summary_lsa_install (struct ospf_lsa *new, int rt_recalc) +{ + + if (rt_recalc && !IS_LSA_SELF (new)) + { + /* RFC 2328 Section 13.2 Summary-LSAs + The best route to the destination described by the summary- + LSA must be recalculated (see Section 16.5). If this + destination is an AS boundary router, it may also be + necessary to re-examine all the AS-external-LSAs. + */ + +#if 0 + /* This doesn't exist yet... */ + ospf_summary_incremental_update(new); */ +#else /* #if 0 */ + ospf_spf_calculate_schedule(); +#endif /* #if 0 */ + + if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) + zlog_info ("ospf_summary_lsa_install(): SPF scheduled"); + } + + if (IS_LSA_SELF (new)) + ospf_refresher_register_lsa (ospf_top, new); + + return new; +} + +/* Install ASBR-summary-LSA to an area. */ +struct ospf_lsa * +ospf_summary_asbr_lsa_install (struct ospf_lsa *new, int rt_recalc) +{ + if (rt_recalc && !IS_LSA_SELF (new)) + { + /* RFC 2328 Section 13.2 Summary-LSAs + The best route to the destination described by the summary- + LSA must be recalculated (see Section 16.5). If this + destination is an AS boundary router, it may also be + necessary to re-examine all the AS-external-LSAs. + */ +#if 0 + /* These don't exist yet... */ + ospf_summary_incremental_update(new); + /* Isn't this done by the above call? + - RFC 2328 Section 16.5 implies it should be */ + /* ospf_ase_calculate_schedule(); */ +#else /* #if 0 */ + ospf_spf_calculate_schedule(); +#endif /* #if 0 */ + } + + /* register LSA to refresh-list. */ + if (IS_LSA_SELF (new)) + ospf_refresher_register_lsa (ospf_top, new); + + return new; +} + +/* Install AS-external-LSA. */ +struct ospf_lsa * +ospf_external_lsa_install (struct ospf_lsa *new, int rt_recalc) +{ + ospf_ase_register_external_lsa (new, ospf_top); + /* If LSA is not self-originated, calculate an external route. */ + if (rt_recalc) + { + /* RFC 2328 Section 13.2 AS-external-LSAs + The best route to the destination described by the AS- + external-LSA must be recalculated (see Section 16.6). + */ + + if (!IS_LSA_SELF (new)) + ospf_ase_incremental_update (new, ospf_top); + } + + /* Register self-originated LSA to refresh queue. */ + if (IS_LSA_SELF (new)) + ospf_refresher_register_lsa (ospf_top, new); + + return new; +} + +void +ospf_discard_from_db (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) +{ + struct ospf_lsa *old; + + old = ospf_lsdb_lookup (lsdb, lsa); + + if (!old) + return; + + if (old->refresh_list >= 0) + ospf_refresher_unregister_lsa (ospf_top, old); + + ospf_ls_retransmit_delete_nbr_all (old->area, old); + + switch (old->data->type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + ospf_ase_unregister_external_lsa (old, ospf_top); + break; + default: + break; + } + + ospf_lsa_maxage_delete (old); + ospf_lsa_discard (old); +} + +/* callback for foreach_lsa */ +int +ospf_lsa_discard_callback (struct ospf_lsa *lsa, void *p, int i) +{ +#ifdef HAVE_NSSA + /* Removed: Stay away from any Local Translated Type-7 LSAs */ + /* if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) + return 0; */ +#endif /* HAVE_NSSA */ + ospf_discard_from_db ((struct ospf_lsdb *)p, lsa); + return 0; +} + +struct ospf_lsa * +ospf_lsa_install (struct ospf_interface *oi, struct ospf_lsa *lsa) +{ + struct ospf_lsa *new = NULL; + struct ospf_lsa *old = NULL; + struct ospf_lsdb *lsdb = NULL; + int rt_recalc; + + /* Set LSDB. */ + switch (lsa->data->type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + lsdb = ospf_top->lsdb; + break; + default: + lsdb = lsa->area->lsdb; + break; + } + +#ifdef HAVE_NSSA + if (IS_DEBUG_OSPF_NSSA) + { + zlog_info ("LSA[Installing]: Type-%d ", lsa->data->type); + + if (lsa->data->type == OSPF_AS_NSSA_LSA ) + zlog_info ("NSSA LSA AREA = %s", inet_ntoa (lsa->area->area_id)); + } +#endif /* HAVE_NSSA */ + + assert (lsdb); + + /* RFC 2328 13.2. Installing LSAs in the database + + Installing a new LSA in the database, either as the result of + flooding or a newly self-originated LSA, may cause the OSPF + routing table structure to be recalculated. The contents of the + new LSA should be compared to the old instance, if present. If + there is no difference, there is no need to recalculate the + routing table. When comparing an LSA to its previous instance, + the following are all considered to be differences in contents: + + o The LSA's Options field has changed. + + o One of the LSA instances has LS age set to MaxAge, and + the other does not. + + o The length field in the LSA header has changed. + + o The body of the LSA (i.e., anything outside the 20-byte + LSA header) has changed. Note that this excludes changes + in LS Sequence Number and LS Checksum. + + */ + /* Look up old LSA and determine if any SPF calculation or incremental + update is needed */ + old = ospf_lsdb_lookup (lsdb, lsa); + + /* Do comparision and record if recalc needed. */ + rt_recalc = 0; + if ( old == NULL || ospf_lsa_different(old, lsa)) + rt_recalc = 1; + + /* discard old LSA from LSDB */ + if (old != NULL) + ospf_discard_from_db (lsdb, lsa); + + /* Insert LSA to LSDB. */ + ospf_lsdb_add (lsdb, lsa); + lsa->lsdb = lsdb; + + /* Calculate Checksum if self-originated?. */ + if (IS_LSA_SELF (lsa)) + ospf_lsa_checksum (lsa->data); + + /* Do LSA specific installation process. */ + switch (lsa->data->type) + { + case OSPF_ROUTER_LSA: + new = ospf_router_lsa_install (lsa, rt_recalc); + break; + case OSPF_NETWORK_LSA: + assert (oi); + new = ospf_network_lsa_install (oi, lsa, rt_recalc); + break; + case OSPF_SUMMARY_LSA: + new = ospf_summary_lsa_install (lsa, rt_recalc); + break; + case OSPF_ASBR_SUMMARY_LSA: + new = ospf_summary_asbr_lsa_install (lsa, rt_recalc); + break; + case OSPF_AS_EXTERNAL_LSA: + new = ospf_external_lsa_install (lsa, rt_recalc); + break; +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: + new = ospf_opaque_lsa_install (lsa, rt_recalc); + break; +#endif /* HAVE_OPAQUE_LSA */ + default: /* NSSA, or type-6,8,9....nothing special */ +#ifdef HAVE_NSSA + new = ospf_external_lsa_install (lsa, rt_recalc); +#endif /* HAVE_NSSA */ + break; + } + + if (new == NULL) + return new; /* Installation failed, cannot proceed further -- endo. */ + + /* Debug logs. */ + if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) + { + char area_str[INET_ADDRSTRLEN]; + + switch (lsa->data->type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + zlog_info ("LSA[%s]: Install %s", + dump_lsa_key (new), + LOOKUP (ospf_lsa_type_msg, new->data->type)); + break; + default: + strcpy (area_str, inet_ntoa (new->area->area_id)); + zlog_info ("LSA[%s]: Install %s to Area %s", + dump_lsa_key (new), + LOOKUP (ospf_lsa_type_msg, new->data->type), area_str); + break; + } + } + + /* If received LSA' ls_age is MaxAge, set LSA on MaxAge LSA list. */ + if (IS_LSA_MAXAGE (new) && !IS_LSA_SELF (new)) + { + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("LSA[Type%d:%s]: Install LSA, MaxAge", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_maxage (lsa); + } + + return new; +} + + +int +ospf_check_nbr_status () +{ + listnode node; + + for (node = listhead (ospf_top->oiflist); node; node = nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + struct route_node *rn; + struct ospf_neighbor *nbr; + + if (ospf_if_is_enable (oi)) + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL) + if (nbr->state == NSM_Exchange || nbr->state == NSM_Loading) + { + route_unlock_node (rn); + return 0; + } + } + + return 1; +} + + +#ifdef ORIGINAL_CODING +/* This function flood the maxaged LSA to DR. */ +void +ospf_maxage_flood (struct ospf_lsa *lsa) +{ + switch (lsa->data->type) + { + case OSPF_ROUTER_LSA: + case OSPF_NETWORK_LSA: + case OSPF_SUMMARY_LSA: + case OSPF_ASBR_SUMMARY_LSA: +#ifdef HAVE_NSSA + case OSPF_AS_NSSA_LSA: +#endif /* HAVE_NSSA */ +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: +#endif /* HAVE_OPAQUE_LSA */ + ospf_flood_through_area (lsa->area, NULL, lsa); + break; + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + ospf_flood_through_as (NULL, lsa); + break; + default: + break; + } +} +#endif /* ORIGINAL_CODING */ + +int +ospf_maxage_lsa_remover (struct thread *thread) +{ + listnode node; + listnode next; + int reschedule = 0; + + ospf_top->t_maxage = NULL; + + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("LSA[MaxAge]: remover Start"); + + reschedule = !ospf_check_nbr_status (); + + if (!reschedule) + for (node = listhead (ospf_top->maxage_lsa); node; node = next) + { + struct ospf_lsa *lsa = getdata (node); + next = node->next; + + if (lsa->retransmit_counter > 0) + { + reschedule = 1; + continue; + } + + /* Remove LSA from the LSDB */ + if (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF)) + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("LSA[Type%d:%s]: This LSA is self-originated: ", + lsa->data->type, inet_ntoa (lsa->data->id)); + + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("LSA[Type%d:%s]: MaxAge LSA removed from list", + lsa->data->type, inet_ntoa (lsa->data->id)); + + /* Flood max age LSA. */ +#ifdef ORIGINAL_CODING + ospf_maxage_flood (lsa); +#else /* ORIGINAL_CODING */ + ospf_flood_through (NULL, lsa); +#endif /* ORIGINAL_CODING */ + + /* Remove from lsdb. */ + ospf_discard_from_db (lsa->lsdb, lsa); + ospf_lsdb_delete (lsa->lsdb, lsa); + } + + /* A MaxAge LSA must be removed immediately from the router's link + state database as soon as both a) it is no longer contained on any + neighbor Link state retransmission lists and b) none of the router's + neighbors are in states Exchange or Loading. */ + if (reschedule) + OSPF_SCHEDULE_MAXAGE (ospf_top->t_maxage, ospf_maxage_lsa_remover); + + return 0; +} + +int +ospf_lsa_maxage_exist (struct ospf_lsa *new) +{ + listnode node; + + for (node = listhead (ospf_top->maxage_lsa); node; nextnode (node)) + if (((struct ospf_lsa *) node->data) == new) + return 1; + + return 0; +} + +void +ospf_lsa_maxage_delete (struct ospf_lsa *lsa) +{ + listnode n; + + if ((n = listnode_lookup (ospf_top->maxage_lsa, lsa))) + { + list_delete_node (ospf_top->maxage_lsa, n); + ospf_lsa_unlock (lsa); + } +} + +void +ospf_lsa_maxage (struct ospf_lsa *lsa) +{ + /* When we saw a MaxAge LSA flooded to us, we put it on the list + and schedule the MaxAge LSA remover. */ + if (ospf_lsa_maxage_exist (lsa)) + { + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("LSA[Type%d:%s]: %p already exists on MaxAge LSA list", + lsa->data->type, inet_ntoa (lsa->data->id), lsa); + return; + } + + listnode_add (ospf_top->maxage_lsa, ospf_lsa_lock (lsa)); + + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("LSA[%s]: MaxAge LSA remover scheduled.", dump_lsa_key (lsa)); + + OSPF_SCHEDULE_MAXAGE (ospf_top->t_maxage, ospf_maxage_lsa_remover); +} + +int +ospf_lsa_maxage_walker_remover (struct ospf_lsa *lsa, void *p_arg, int int_arg) +{ +#ifdef HAVE_NSSA + /* Stay away from any Local Translated Type-7 LSAs */ + if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) + return 0; +#endif /* HAVE_NSSA */ + + if (IS_LSA_MAXAGE (lsa)) + /* Self-originated LSAs should NOT time-out instead, + they're flushed and submitted to the max_age list explicitly. */ + if (!ospf_lsa_is_self_originated (lsa)) + { + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info("LSA[%s]: is MaxAge", dump_lsa_key (lsa)); + + switch (lsa->data->type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + ospf_ase_incremental_update (lsa, ospf_top); + break; + default: + ospf_spf_calculate_schedule (); + break; + } + + ospf_lsa_maxage (lsa); + } + + return 0; +} + +/* Periodical check of MaxAge LSA. */ +int +ospf_lsa_maxage_walker (struct thread *t) +{ + listnode node; + + ospf_top->t_maxage_walker = NULL; + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + struct ospf_area *area = node->data; + + foreach_lsa (ROUTER_LSDB (area), NULL, 0, + ospf_lsa_maxage_walker_remover); + foreach_lsa (NETWORK_LSDB (area), NULL, 0, + ospf_lsa_maxage_walker_remover); + foreach_lsa (SUMMARY_LSDB (area), NULL, 0, + ospf_lsa_maxage_walker_remover); + foreach_lsa (ASBR_SUMMARY_LSDB (area), NULL, 0, + ospf_lsa_maxage_walker_remover); +#ifdef HAVE_OPAQUE_LSA + foreach_lsa (OPAQUE_LINK_LSDB (area), NULL, 0, + ospf_lsa_maxage_walker_remover); + foreach_lsa (OPAQUE_AREA_LSDB (area), NULL, 0, + ospf_lsa_maxage_walker_remover); +#endif /* HAVE_OPAQUE_LSA */ + } + + /* for AS-eternal-LSAs. */ + if (ospf_top->lsdb) + foreach_lsa (EXTERNAL_LSDB (ospf_top), NULL, 0, + ospf_lsa_maxage_walker_remover); + +#ifdef HAVE_OPAQUE_LSA + if (ospf_top->lsdb) + foreach_lsa (OPAQUE_AS_LSDB (ospf_top), NULL, 0, + ospf_lsa_maxage_walker_remover); +#endif /* HAVE_OPAQUE_LSA */ + + ospf_top->t_maxage_walker = + thread_add_timer (master, ospf_lsa_maxage_walker, NULL, + OSPF_LSA_MAXAGE_CHECK_INTERVAL); + return 0; +} + +int +find_summary (struct ospf_lsa *lsa, void * v, int i) +{ + struct prefix_ipv4 *p, pr; + + if ((p = (struct prefix_ipv4 *) v) != NULL) + if (lsa != NULL) + /* We're looking for self-originated one */ + if (ospf_lsa_is_self_originated (lsa)) + { + struct summary_lsa *sl = (struct summary_lsa *) lsa->data; + + pr.family = AF_INET; + pr.prefix = sl->header.id; + pr.prefixlen = ip_masklen (sl->mask); + apply_mask_ipv4 (&pr); + + if (prefix_same ((struct prefix*) &pr, (struct prefix*) p)) + return 1; + } + + return 0; +} + +int +find_asbr_summary (struct ospf_lsa *lsa, void * v, int i) +{ + struct prefix_ipv4 *p; + + if ((p = (struct prefix_ipv4 *) v) != NULL) + if (lsa != NULL) + /* We're looking for self-originated one */ + if (ospf_lsa_is_self_originated (lsa)) + { + struct summary_lsa *sl = (struct summary_lsa *) lsa->data; + + if (IPV4_ADDR_SAME (&p->prefix, &sl->header.id)) + return 1; + } + + return 0; +} + +struct ospf_lsa * +ospf_lsa_lookup (struct ospf_area *area, u_int32_t type, + struct in_addr id, struct in_addr adv_router) +{ + switch (type) + { + case OSPF_ROUTER_LSA: + case OSPF_NETWORK_LSA: + case OSPF_SUMMARY_LSA: + case OSPF_ASBR_SUMMARY_LSA: +#ifdef HAVE_NSSA + case OSPF_AS_NSSA_LSA: +#endif /* HAVE_NSSA */ +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: +#endif /* HAVE_OPAQUE_LSA */ + return ospf_lsdb_lookup_by_id (area->lsdb, type, id, adv_router); + break; + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + return ospf_lsdb_lookup_by_id (ospf_top->lsdb, type, id, adv_router); + break; + default: + break; + } + + return NULL; +} + +struct ospf_lsa * +ospf_lsa_lookup_by_id (struct ospf_area *area, u_int32_t type, + struct in_addr id) +{ + struct ospf_lsa *lsa; + struct route_node *rn; + + switch (type) + { + case OSPF_ROUTER_LSA: + return ospf_lsdb_lookup_by_id (area->lsdb, type, id, id); + break; + case OSPF_NETWORK_LSA: + for (rn = route_top (NETWORK_LSDB (area)); rn; rn = route_next (rn)) + if ((lsa = rn->info)) + if (IPV4_ADDR_SAME (&lsa->data->id, &id)) + { + route_unlock_node (rn); + return lsa; + } + break; + case OSPF_SUMMARY_LSA: + case OSPF_ASBR_SUMMARY_LSA: + /* Currently not used. */ + assert (1); + return ospf_lsdb_lookup_by_id (area->lsdb, type, id, id); + break; + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: + /* Currently not used. */ + break; +#endif /* HAVE_OPAQUE_LSA */ + default: + break; + } + + return NULL; +} + +struct ospf_lsa * +ospf_lsa_lookup_by_header (struct ospf_area *area, struct lsa_header *lsah) +{ + struct ospf_lsa *match; + +#ifdef HAVE_OPAQUE_LSA + /* + * Strictly speaking, the LSA-ID field for Opaque-LSAs (type-9/10/11) + * is redefined to have two subfields; opaque-type and opaque-id. + * However, it is harmless to treat the two sub fields together, as if + * they two were forming a unique LSA-ID. + */ +#endif /* HAVE_OPAQUE_LSA */ + + match = ospf_lsa_lookup (area, lsah->type, lsah->id, lsah->adv_router); + + if (match == NULL) + if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) + zlog_info ("LSA[Type%d:%s]: Lookup by header, NO MATCH", + lsah->type, inet_ntoa (lsah->id)); + + return match; +} + +/* return +n, l1 is more recent. + return -n, l2 is more recent. + return 0, l1 and l2 is identical. */ +int +ospf_lsa_more_recent (struct ospf_lsa *l1, struct ospf_lsa *l2) +{ + int r; + int x, y; + + if (l1 == NULL && l2 == NULL) + return 0; + if (l1 == NULL) + return -1; + if (l2 == NULL) + return 1; + + /* compare LS sequence number. */ + x = (int) ntohl (l1->data->ls_seqnum); + y = (int) ntohl (l2->data->ls_seqnum); + if (x > y) + return 1; + if (x < y) + return -1; + + /* compare LS checksum. */ + r = ntohs (l1->data->checksum) - ntohs (l2->data->checksum); + if (r) + return r; + + /* compare LS age. */ + if (IS_LSA_MAXAGE (l1) && !IS_LSA_MAXAGE (l2)) + return 1; + else if (!IS_LSA_MAXAGE (l1) && IS_LSA_MAXAGE (l2)) + return -1; + + /* compare LS age with MaxAgeDiff. */ + if (LS_AGE (l1) - LS_AGE (l2) > OSPF_LSA_MAXAGE_DIFF) + return -1; + else if (LS_AGE (l2) - LS_AGE (l1) > OSPF_LSA_MAXAGE_DIFF) + return 1; + + /* LSAs are identical. */ + return 0; +} + +/* If two LSAs are different, return 1, otherwise return 0. */ +int +ospf_lsa_different (struct ospf_lsa *l1, struct ospf_lsa *l2) +{ + char *p1, *p2; + assert (l1); + assert (l2); + assert (l1->data); + assert (l2->data); + + if (l1->data->options != l2->data->options) + return 1; + + if (IS_LSA_MAXAGE (l1) && !IS_LSA_MAXAGE (l2)) + return 1; + + if (IS_LSA_MAXAGE (l2) && !IS_LSA_MAXAGE (l1)) + return 1; + + if (l1->data->length != l2->data->length) + return 1; + + if (l1->data->length == 0) + return 1; + + assert (l1->data->length > OSPF_LSA_HEADER_SIZE); + + p1 = (char *) l1->data; + p2 = (char *) l2->data; + + if (memcmp (p1 + OSPF_LSA_HEADER_SIZE, p2 + OSPF_LSA_HEADER_SIZE, + ntohs( l1->data->length ) - OSPF_LSA_HEADER_SIZE) != 0) + return 1; + + return 0; +} + +#ifdef ORIGINAL_CODING +void +ospf_lsa_flush_self_originated (struct ospf_neighbor *nbr, + struct ospf_lsa *self, + struct ospf_lsa *new) +{ + u_int32_t seqnum; + + /* Adjust LS Sequence Number. */ + seqnum = ntohl (new->data->ls_seqnum) + 1; + self->data->ls_seqnum = htonl (seqnum); + + /* Recalculate LSA checksum. */ + ospf_lsa_checksum (self->data); + + /* Reflooding LSA. */ + /* RFC2328 Section 13.3 + On non-broadcast networks, separate Link State Update + packets must be sent, as unicasts, to each adjacent neighbor + (i.e., those in state Exchange or greater). The destination + IP addresses for these packets are the neighbors' IP + addresses. */ + if (nbr->oi->type == OSPF_IFTYPE_NBMA) + { + struct route_node *rn; + struct ospf_neighbor *onbr; + + for (rn = route_top (nbr->oi->nbrs); rn; rn = route_next (rn)) + if ((onbr = rn->info) != NULL) + if (onbr != nbr->oi->nbr_self && onbr->status >= NSM_Exchange) + ospf_ls_upd_send_lsa (onbr, self, OSPF_SEND_PACKET_DIRECT); + } + else + ospf_ls_upd_send_lsa (nbr, self, OSPF_SEND_PACKET_INDIRECT); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type%d:%s]: Flush self-originated LSA", + self->data->type, inet_ntoa (self->data->id)); +} +#else /* ORIGINAL_CODING */ +static int +ospf_lsa_flush_schedule (struct ospf_lsa *lsa, void *v, int i) +{ + if (lsa == NULL || !IS_LSA_SELF (lsa)) + return 0; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id)); + + /* Force given lsa's age to MaxAge. */ + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); + + switch (lsa->data->type) + { +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: + ospf_opaque_lsa_refresh (lsa); + break; +#endif /* HAVE_OPAQUE_LSA */ + default: + ospf_lsa_maxage (lsa); + break; + } + + return 0; +} + +void +ospf_flush_self_originated_lsas_now (struct ospf *top) +{ + listnode n1, n2; + struct ospf_area *area; + struct ospf_interface *oi; + struct ospf_lsa *lsa; + int need_to_flush_ase = 0; + + for (n1 = listhead (top->areas); n1; nextnode (n1)) + { + if ((area = getdata (n1)) == NULL) + continue; + + if ((lsa = area->router_lsa_self) != NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id)); + + ospf_lsa_flush_area (lsa, area); + ospf_lsa_unlock (area->router_lsa_self); + area->router_lsa_self = NULL; + OSPF_TIMER_OFF (area->t_router_lsa_self); + } + + for (n2 = listhead (area->oiflist); n2; nextnode (n2)) + { + if ((oi = getdata (n2)) == NULL) + continue; + + if ((lsa = oi->network_lsa_self) != NULL + && oi->state == ISM_DR + && oi->full_nbrs > 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id)); + + ospf_lsa_flush_area (oi->network_lsa_self, area); + ospf_lsa_unlock (oi->network_lsa_self); + oi->network_lsa_self = NULL; + OSPF_TIMER_OFF (oi->t_network_lsa_self); + } + + if (oi->type != OSPF_IFTYPE_VIRTUALLINK + && area->external_routing == OSPF_AREA_DEFAULT) + need_to_flush_ase = 1; + } + + foreach_lsa (SUMMARY_LSDB (area), NULL, 0, ospf_lsa_flush_schedule); + foreach_lsa (ASBR_SUMMARY_LSDB (area), NULL, 0, ospf_lsa_flush_schedule); +#ifdef HAVE_OPAQUE_LSA + foreach_lsa (OPAQUE_LINK_LSDB (area), + NULL, 0, ospf_lsa_flush_schedule); + foreach_lsa (OPAQUE_AREA_LSDB (area), + NULL, 0, ospf_lsa_flush_schedule); +#endif /* HAVE_OPAQUE_LSA */ + } + + if (need_to_flush_ase) + { + foreach_lsa (EXTERNAL_LSDB (top), NULL, 0, ospf_lsa_flush_schedule); +#ifdef HAVE_OPAQUE_LSA + foreach_lsa (OPAQUE_AS_LSDB (top), + NULL, 0, ospf_lsa_flush_schedule); +#endif /* HAVE_OPAQUE_LSA */ + } + + /* + * Make sure that the MaxAge LSA remover is executed immediately, + * without conflicting to other threads. + */ + if (top->t_maxage != NULL) + { + OSPF_TIMER_OFF (top->t_maxage); + thread_execute (master, ospf_maxage_lsa_remover, top, 0); + } + + return; +} +#endif /* ORIGINAL_CODING */ + +/* If there is self-originated LSA, then return 1, otherwise return 0. */ +/* An interface-independent version of ospf_lsa_is_self_originated */ +int +ospf_lsa_is_self_originated (struct ospf_lsa *lsa) +{ + listnode node; + + /* This LSA is already checked. */ + if (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF_CHECKED)) + return CHECK_FLAG (lsa->flags, OSPF_LSA_SELF); + + /* Make sure LSA is self-checked. */ + SET_FLAG (lsa->flags, OSPF_LSA_SELF_CHECKED); + + /* AdvRouter and Router ID is the same. */ + if (IPV4_ADDR_SAME (&lsa->data->adv_router, &ospf_top->router_id)) + SET_FLAG (lsa->flags, OSPF_LSA_SELF); + + /* LSA is router-LSA. */ + else if (lsa->data->type == OSPF_ROUTER_LSA && + IPV4_ADDR_SAME (&lsa->data->id, &ospf_top->router_id)) + SET_FLAG (lsa->flags, OSPF_LSA_SELF); + + /* LSA is network-LSA. Compare Link ID with all interfaces. */ + else if (lsa->data->type == OSPF_NETWORK_LSA) + for (node = listhead (ospf_top->oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + + /* Ignore virtual link. */ + if (oi->type != OSPF_IFTYPE_VIRTUALLINK) + if (oi->address->family == AF_INET) + if (IPV4_ADDR_SAME (&lsa->data->id, &oi->address->u.prefix4)) + { + /* to make it easier later */ + SET_FLAG (lsa->flags, OSPF_LSA_SELF); + return CHECK_FLAG (lsa->flags, OSPF_LSA_SELF); + } + } + + return CHECK_FLAG (lsa->flags, OSPF_LSA_SELF); +} + +/* Get unique Link State ID. */ +struct in_addr +ospf_lsa_unique_id (struct ospf_lsdb *lsdb, u_char type, struct prefix_ipv4 *p) +{ + struct ospf_lsa *lsa; + struct in_addr mask, id; + + id = p->prefix; + + /* Check existence of LSA instance. */ + lsa = ospf_lsdb_lookup_by_id (lsdb, type, id, ospf_top->router_id); + if (lsa) + { + struct as_external_lsa *al = (struct as_external_lsa *) lsa->data; + if (ip_masklen (al->mask) == p->prefixlen) + { + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_warn ("ospf_lsa_unique_id(): " + "Can't get Link State ID for %s/%d", + inet_ntoa (p->prefix), p->prefixlen); + /* id.s_addr = 0; */ + id.s_addr = 0xffffffff; + return id; + } + /* Masklen differs, then apply wildcard mask to Link State ID. */ + else + { + masklen2ip (p->prefixlen, &mask); + + id.s_addr = p->prefix.s_addr | (~mask.s_addr); + lsa = ospf_lsdb_lookup_by_id (ospf_top->lsdb, type, + id, ospf_top->router_id); + if (lsa) + { + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_warn ("ospf_lsa_unique_id(): " + "Can't get Link State ID for %s/%d", + inet_ntoa (p->prefix), p->prefixlen); + /* id.s_addr = 0; */ + id.s_addr = 0xffffffff; + return id; + } + } + } + + return id; +} + + +#define LSA_ACTION_ORIGN_RTR 1 +#define LSA_ACTION_ORIGN_NET 2 +#define LSA_ACTION_FLOOD_AREA 3 +#define LSA_ACTION_FLOOD_AS 4 +#define LSA_ACTION_FLUSH_AREA 5 +#define LSA_ACTION_FLUSH_AS 6 + +struct lsa_action +{ + u_char action; + struct ospf_area *area; + struct ospf_interface *oi; + struct ospf_lsa *lsa; +}; + +int +ospf_lsa_action (struct thread *t) +{ + struct lsa_action *data; + + data = THREAD_ARG (t); + + if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) + zlog_info ("LSA[Action]: Performing scheduled LSA action: %d", + data->action); + + switch (data->action) + { + case LSA_ACTION_ORIGN_RTR: + ospf_router_lsa_refresh (data->area->router_lsa_self); + break; + case LSA_ACTION_ORIGN_NET: + ospf_network_lsa_originate (data->oi); + break; + case LSA_ACTION_FLOOD_AREA: + ospf_flood_through_area (data->area, NULL, data->lsa); + break; + case LSA_ACTION_FLOOD_AS: + ospf_flood_through_as (NULL, data->lsa); + break; + case LSA_ACTION_FLUSH_AREA: + ospf_lsa_flush_area (data->lsa, data->area); + break; + case LSA_ACTION_FLUSH_AS: + ospf_lsa_flush_as (data->lsa); + break; + } + + ospf_lsa_unlock (data->lsa); + XFREE (MTYPE_OSPF_MESSAGE, data); + return 0; +} + +void +ospf_schedule_lsa_flood_area (struct ospf_area *area, struct ospf_lsa *lsa) +{ + struct lsa_action *data; + + data = XMALLOC (MTYPE_OSPF_MESSAGE, sizeof (struct lsa_action)); + memset (data, 0, sizeof (struct lsa_action)); + + data->action = LSA_ACTION_FLOOD_AREA; + data->area = area; + data->lsa = ospf_lsa_lock (lsa); + + thread_add_event (master, ospf_lsa_action, data, 0); +} + +void +ospf_schedule_lsa_flush_area (struct ospf_area *area, struct ospf_lsa *lsa) +{ + struct lsa_action *data; + + data = XMALLOC (MTYPE_OSPF_MESSAGE, sizeof (struct lsa_action)); + memset (data, 0, sizeof (struct lsa_action)); + + data->action = LSA_ACTION_FLUSH_AREA; + data->area = area; + data->lsa = ospf_lsa_lock (lsa); + + thread_add_event (master, ospf_lsa_action, data, 0); +} + + +/* LSA Refreshment functions. */ +void +ospf_lsa_refresh (struct ospf_lsa *lsa) +{ + struct external_info *ei; + assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF)); + + switch (lsa->data->type) + { + /* Router and Network LSAs are processed differently. */ + case OSPF_ROUTER_LSA: + case OSPF_NETWORK_LSA: + break; + case OSPF_SUMMARY_LSA: + ospf_summary_lsa_refresh (lsa); + break; + case OSPF_ASBR_SUMMARY_LSA: + ospf_summary_asbr_lsa_refresh (lsa); + break; + case OSPF_AS_EXTERNAL_LSA: + ei = ospf_external_info_check (lsa); + if (ei) + ospf_external_lsa_refresh (lsa, ei, LSA_REFRESH_FORCE); + else + ospf_lsa_flush_as (lsa); + break; +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: + ospf_opaque_lsa_refresh (lsa); + break; + default: + break; +#endif /* HAVE_OPAQUE_LSA */ + } +} + +void +ospf_refresher_register_lsa (struct ospf *top, struct ospf_lsa *lsa) +{ + u_int16_t index, current_index; + + assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF)); + + if (lsa->refresh_list < 0) + { + int delay; + + if (LS_AGE (lsa) == 0 && + ntohl (lsa->data->ls_seqnum) == OSPF_INITIAL_SEQUENCE_NUMBER) + /* Randomize first update by OSPF_LS_REFRESH_SHIFT factor */ + delay = OSPF_LS_REFRESH_SHIFT + (random () % OSPF_LS_REFRESH_TIME); + else + /* Randomize another updates by +-OSPF_LS_REFRESH_JITTER factor */ + delay = OSPF_LS_REFRESH_TIME - LS_AGE (lsa) - OSPF_LS_REFRESH_JITTER + + (random () % (2*OSPF_LS_REFRESH_JITTER)); + + if (delay < 0) + delay = 0; + + current_index = top->lsa_refresh_queue.index + + (time (NULL) - top->lsa_refresher_started)/OSPF_LSA_REFRESHER_GRANULARITY; + + index = (current_index + delay/OSPF_LSA_REFRESHER_GRANULARITY) + % (OSPF_LSA_REFRESHER_SLOTS); + + if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) + zlog_info ("LSA[Refresh]: lsa with age %d added to index %d", + LS_AGE (lsa), index); + if (!top->lsa_refresh_queue.qs[index]) + top->lsa_refresh_queue.qs[index] = list_new (); + listnode_add (top->lsa_refresh_queue.qs[index], ospf_lsa_lock (lsa)); + lsa->refresh_list = index; + } +} + +void +ospf_refresher_unregister_lsa (struct ospf *top, struct ospf_lsa *lsa) +{ + assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF)); + if (lsa->refresh_list >= 0) + { + list refresh_list = top->lsa_refresh_queue.qs[lsa->refresh_list]; + listnode_delete (refresh_list, lsa); + if (!listcount (refresh_list)) + { + list_free (refresh_list); + top->lsa_refresh_queue.qs[lsa->refresh_list] = NULL; + } + ospf_lsa_unlock (lsa); + lsa->refresh_list = -1; + } +} + +int +ospf_lsa_refresh_walker (struct thread *t) +{ + list refresh_list; + listnode node; + struct ospf *top = THREAD_ARG (t); + int i; + list lsa_to_refresh = list_new (); + + if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) + zlog_info ("LSA[Refresh]:ospf_lsa_refresh_walker(): start"); + + + i = top->lsa_refresh_queue.index; + + top->lsa_refresh_queue.index = + (top->lsa_refresh_queue.index + + (time (NULL) - top->lsa_refresher_started) / OSPF_LSA_REFRESHER_GRANULARITY) + % OSPF_LSA_REFRESHER_SLOTS; + + if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) + zlog_info ("LSA[Refresh]: ospf_lsa_refresh_walker(): next index %d", + top->lsa_refresh_queue.index); + + for (;i != top->lsa_refresh_queue.index; + i = (i + 1) % OSPF_LSA_REFRESHER_SLOTS) + { + if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) + zlog_info ("LSA[Refresh]: ospf_lsa_refresh_walker(): refresh index %d", i); + + refresh_list = top->lsa_refresh_queue.qs [i]; + + top->lsa_refresh_queue.qs [i] = NULL; + + if (refresh_list) + { + for (node = listhead (refresh_list); node;) + { + listnode next; + struct ospf_lsa *lsa = getdata (node); + next = node->next; + + if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) + zlog_info ("LSA[Refresh]: ospf_lsa_refresh_walker(): refresh lsa %p", lsa); + + list_delete_node (refresh_list, node); + ospf_lsa_unlock (lsa); + lsa->refresh_list = -1; + listnode_add (lsa_to_refresh, lsa); + node = next; + } + list_free (refresh_list); + } + } + + top->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker, + top, top->lsa_refresh_interval); + top->lsa_refresher_started = time (NULL); + + for (node = listhead (lsa_to_refresh); node; nextnode (node)) + ospf_lsa_refresh (getdata (node)); + + list_delete (lsa_to_refresh); + + if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) + zlog_info ("LSA[Refresh]: ospf_lsa_refresh_walker(): end"); + + return 0; +} + diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h new file mode 100644 index 00000000..02fbe704 --- /dev/null +++ b/ospfd/ospf_lsa.h @@ -0,0 +1,326 @@ +/* + * OSPF Link State Advertisement + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_LSA_H +#define _ZEBRA_OSPF_LSA_H + +/* OSPF LSA Range definition. */ +#define OSPF_MIN_LSA 1 /* begin range here */ +#if defined (HAVE_OPAQUE_LSA) +#define OSPF_MAX_LSA 12 +#elif defined (HAVE_NSSA) +#define OSPF_MAX_LSA 8 +#else +#define OSPF_MAX_LSA 6 +#endif + +/* OSPF LSA Type definition. */ +#define OSPF_UNKNOWN_LSA 0 +#define OSPF_ROUTER_LSA 1 +#define OSPF_NETWORK_LSA 2 +#define OSPF_SUMMARY_LSA 3 +#define OSPF_ASBR_SUMMARY_LSA 4 +#define OSPF_AS_EXTERNAL_LSA 5 +#define OSPF_GROUP_MEMBER_LSA 6 /* Not supported. */ +#define OSPF_AS_NSSA_LSA 7 +#define OSPF_EXTERNAL_ATTRIBUTES_LSA 8 /* Not supported. */ +#define OSPF_OPAQUE_LINK_LSA 9 +#define OSPF_OPAQUE_AREA_LSA 10 +#define OSPF_OPAQUE_AS_LSA 11 + +#define OSPF_LSA_HEADER_SIZE 20 +#define OSPF_MAX_LSA_SIZE 1500 + +/* AS-external-LSA refresh method. */ +#define LSA_REFRESH_IF_CHANGED 0 +#define LSA_REFRESH_FORCE 1 + +/* OSPF LSA header. */ +struct lsa_header +{ + u_int16_t ls_age; + u_char options; + u_char type; + struct in_addr id; + struct in_addr adv_router; + int ls_seqnum; + u_int16_t checksum; + u_int16_t length; +}; + +/* OSPF LSA. */ +struct ospf_lsa +{ + /* LSA origination flag. */ + u_char flags; +#define OSPF_LSA_SELF 0x01 +#define OSPF_LSA_SELF_CHECKED 0x02 +#define OSPF_LSA_RECEIVED 0x04 +#define OSPF_LSA_APPROVED 0x08 +#define OSPF_LSA_DISCARD 0x10 +#ifdef HAVE_NSSA +#define OSPF_LSA_LOCAL_XLT 0x20 +#endif /* HAVE_NSSA */ + + /* LSA data. */ + struct lsa_header *data; + + /* Received time stamp. */ + struct timeval tv_recv; + + /* Last time it was originated */ + struct timeval tv_orig; + + /* All of reference count, also lock to remove. */ + int lock; + + /* References to this LSA in neighbor retransmission lists*/ + int retransmit_counter; + + /* Area the LSA belongs to, may be NULL if AS-external-LSA. */ + struct ospf_area *area; + + /* Parent LSDB. */ + struct ospf_lsdb *lsdb; + + /* Related Route. */ + void *route; + + /* Refreshement List or Queue */ + int refresh_list; + +#ifdef HAVE_OPAQUE_LSA + /* For Type-9 Opaque-LSAs, reference to ospf-interface is required. */ + struct ospf_interface *oi; +#endif /* HAVE_OPAQUE_LSA */ +}; + +/* OSPF LSA Link Type. */ +#define LSA_LINK_TYPE_POINTOPOINT 1 +#define LSA_LINK_TYPE_TRANSIT 2 +#define LSA_LINK_TYPE_STUB 3 +#define LSA_LINK_TYPE_VIRTUALLINK 4 + +/* OSPF Router LSA Flag. */ +#define ROUTER_LSA_BORDER 0x01 /* The router is an ABR */ +#define ROUTER_LSA_EXTERNAL 0x02 /* The router is an ASBR */ +#define ROUTER_LSA_VIRTUAL 0x04 /* The router has a VL in this area */ +#define ROUTER_LSA_NT 0x10 /* NSSA-specific flag */ +#define ROUTER_LSA_SHORTCUT 0x20 /* Shortcut-ABR specific flag */ + +#define IS_ROUTER_LSA_VIRTUAL(x) ((x)->flags & ROUTER_LSA_VIRTUAL) +#define IS_ROUTER_LSA_EXTERNAL(x) ((x)->flags & ROUTER_LSA_EXTERNAL) +#define IS_ROUTER_LSA_BORDER(x) ((x)->flags & ROUTER_LSA_BORDER) +#define IS_ROUTER_LSA_SHORTCUT(x) ((x)->flags & ROUTER_LSA_SHORTCUT) + +/* OSPF Router-LSA Link information. */ +struct router_lsa_link +{ + struct in_addr link_id; + struct in_addr link_data; + struct + { + u_char type; + u_char tos_count; + u_int16_t metric; + } m[1]; +}; + +/* OSPF Router-LSAs structure. */ +struct router_lsa +{ + struct lsa_header header; + u_char flags; + u_char zero; + u_int16_t links; + struct + { + struct in_addr link_id; + struct in_addr link_data; + u_char type; + u_char tos; + u_int16_t metric; + } link[1]; +}; + +/* OSPF Network-LSAs structure. */ +struct network_lsa +{ + struct lsa_header header; + struct in_addr mask; + struct in_addr routers[1]; +}; + +/* OSPF Summary-LSAs structure. */ +struct summary_lsa +{ + struct lsa_header header; + struct in_addr mask; + u_char tos; + u_char metric[3]; +}; + +/* OSPF AS-external-LSAs structure. */ +struct as_external_lsa +{ + struct lsa_header header; + struct in_addr mask; + struct + { + u_char tos; + u_char metric[3]; + struct in_addr fwd_addr; + u_int32_t route_tag; + } e[1]; +}; + +#ifdef HAVE_OPAQUE_LSA +#include "ospfd/ospf_opaque.h" +#endif /* HAVE_OPAQUE_LSA */ + +/* Macros. */ +#define GET_METRIC(x) get_metric(x) +#define IS_EXTERNAL_METRIC(x) ((x) & 0x80) + +#define GET_AGE(x) (ntohs ((x)->data->ls_age) + time (NULL) - (x)->tv_recv) +#define LS_AGE(x) (OSPF_LSA_MAXAGE < get_age(x) ? \ + OSPF_LSA_MAXAGE : get_age(x)) +#define IS_LSA_SELF(L) (CHECK_FLAG ((L)->flags, OSPF_LSA_SELF)) +#define IS_LSA_MAXAGE(L) (LS_AGE ((L)) == OSPF_LSA_MAXAGE) + +#define OSPF_SUMMARY_LSA_SELF_FIND_BY_PREFIX(A,P) \ + foreach_lsa (SUMMARY_LSDB ((A)), \ + (struct prefix_ipv4 *) (P), 0, find_summary) + +#define OSPF_SUMMARY_ASBR_LSA_SELF_FIND_BY_PREFIX(A,P) \ + foreach_lsa (ASBR_SUMMARY_LSDB ((A)), \ + (struct prefix_ipv4 *) (P), 0, find_asbr_summary) + +#define OSPF_LSA_UPDATE_DELAY 2 + +#define OSPF_LSA_UPDATE_TIMER_ON(T,F) \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), 0, 2) + +struct ospf_route; +struct ospf_lsdb; + +/* Prototypes. */ +struct timeval tv_adjust (struct timeval); +int tv_ceil (struct timeval); +int tv_floor (struct timeval); +struct timeval int2tv (int); +struct timeval tv_add (struct timeval, struct timeval); +struct timeval tv_sub (struct timeval, struct timeval); +int tv_cmp (struct timeval, struct timeval); + +int get_age (struct ospf_lsa *); +u_int16_t ospf_lsa_checksum (struct lsa_header *); + +struct stream; +const char *dump_lsa_key (struct ospf_lsa *lsa); +u_int32_t lsa_seqnum_increment (struct ospf_lsa *lsa); +void lsa_header_set (struct stream *s, u_char options, u_char type, struct in_addr id); +struct ospf_neighbor *ospf_nbr_lookup_ptop (struct route_table *nbrs, struct in_addr router_id); + +/* Prototype for LSA primitive. */ +struct ospf_lsa *ospf_lsa_new (); +struct ospf_lsa *ospf_lsa_dup (); +void ospf_lsa_free (struct ospf_lsa *lsa); +struct ospf_lsa *ospf_lsa_lock (struct ospf_lsa *); +void ospf_lsa_unlock (struct ospf_lsa *); +void ospf_lsa_discard (struct ospf_lsa *); + +struct lsa_header *ospf_lsa_data_new (size_t); +struct lsa_header *ospf_lsa_data_dup (struct lsa_header *); +void ospf_lsa_data_free (struct lsa_header *); + +/* Prototype for various LSAs */ +struct ospf_lsa *ospf_router_lsa_originate (struct ospf_area *); +int ospf_router_lsa_update_timer (struct thread *); +void ospf_router_lsa_timer_add (struct ospf_area *); + +int ospf_network_lsa_refresh (struct ospf_lsa *, struct ospf_interface *); +void ospf_network_lsa_timer_add (struct ospf_interface *); + +struct ospf_lsa *ospf_summary_lsa_originate (struct prefix_ipv4 *, u_int32_t, + struct ospf_area *); +struct ospf_lsa *ospf_summary_asbr_lsa_originate (struct prefix_ipv4 *, + u_int32_t, + struct ospf_area *); +struct ospf_lsa *ospf_summary_lsa_refresh (struct ospf_lsa *); +struct ospf_lsa *ospf_summary_asbr_lsa_refresh (struct ospf_lsa *); + +struct ospf_lsa *ospf_lsa_install (struct ospf_interface *, struct ospf_lsa *); + +void ospf_external_lsa_flush (u_char, struct prefix_ipv4 *, + unsigned int, struct in_addr); + +struct in_addr ospf_get_ip_from_ifp (struct ospf_interface *oi); + +struct ospf_lsa *ospf_external_lsa_originate (struct external_info *); +int ospf_external_lsa_originate_timer (struct thread *); +struct ospf_lsa *ospf_lsa_lookup (struct ospf_area *, u_int32_t, + struct in_addr, struct in_addr); +struct ospf_lsa *ospf_lsa_lookup_by_id (struct ospf_area *,u_int32_t, struct in_addr); +struct ospf_lsa *ospf_lsa_lookup_by_header (struct ospf_area *, + struct lsa_header *); +int ospf_lsa_more_recent (struct ospf_lsa *, struct ospf_lsa *); +int ospf_lsa_different (struct ospf_lsa *, struct ospf_lsa *); +void ospf_flush_self_originated_lsas_now (struct ospf *top); + +int ospf_lsa_is_self_originated (struct ospf_lsa *); + +int find_summary (struct ospf_lsa *, void *, int); +int find_asbr_summary (struct ospf_lsa *, void *, int); + +void ospf_lsa_maxage (struct ospf_lsa *); +u_int32_t get_metric (u_char *); + +int ospf_lsa_maxage_walker (struct thread *); + +void ospf_external_lsa_refresh_default (void); + +void ospf_external_lsa_refresh_type (u_char, int); +void ospf_external_lsa_refresh (struct ospf_lsa *, struct external_info *ei, + int force); +struct in_addr ospf_lsa_unique_id (struct ospf_lsdb *, u_char, + struct prefix_ipv4 *); +void ospf_schedule_lsa_flood_area (struct ospf_area *, struct ospf_lsa *); +void ospf_schedule_lsa_flush_area (struct ospf_area *, struct ospf_lsa *); + +void ospf_refresher_register_lsa (struct ospf *, struct ospf_lsa *); +void ospf_refresher_unregister_lsa (struct ospf *, struct ospf_lsa *); +int ospf_lsa_refresh_walker (struct thread *); + +void ospf_lsa_init (); + +void ospf_lsa_maxage_delete (struct ospf_lsa *); + +void ospf_discard_from_db (struct ospf_lsdb *, struct ospf_lsa*); +int ospf_lsa_discard_callback (struct ospf_lsa *, void *, int); +int is_prefix_default (struct prefix_ipv4 *); + +int metric_type (u_char); +int metric_value (u_char); + +#endif /* _ZEBRA_OSPF_LSA_H */ diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c new file mode 100644 index 00000000..46d8d705 --- /dev/null +++ b/ospfd/ospf_lsdb.c @@ -0,0 +1,299 @@ +/* + * OSPF LSDB support. + * Copyright (C) 1999, 2000 Alex Zinin, Kunihiro Ishiguro, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "table.h" +#include "memory.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" + +struct ospf_lsdb * +ospf_lsdb_new () +{ + struct ospf_lsdb *new; + + new = XCALLOC (MTYPE_OSPF_LSDB, sizeof (struct ospf_lsdb)); + ospf_lsdb_init (new); + + return new; +} + +void +ospf_lsdb_init (struct ospf_lsdb *lsdb) +{ + int i; + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + lsdb->type[i].db = route_table_init (); +} + +void +ospf_lsdb_free (struct ospf_lsdb *lsdb) +{ + ospf_lsdb_cleanup (lsdb); + XFREE (MTYPE_OSPF_LSDB, lsdb); +} + +void +ospf_lsdb_cleanup (struct ospf_lsdb *lsdb) +{ + int i; + assert (lsdb); + assert (lsdb->total == 0); + + ospf_lsdb_delete_all (lsdb); + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + route_table_finish (lsdb->type[i].db); +} + +void +lsdb_prefix_set (struct prefix_ls *lp, struct ospf_lsa *lsa) +{ + memset (lp, 0, sizeof (struct prefix_ls)); + lp->family = 0; + lp->prefixlen = 64; + lp->id = lsa->data->id; + lp->adv_router = lsa->data->adv_router; +} + +/* Add new LSA to lsdb. */ +void +ospf_lsdb_add (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) +{ + struct route_table *table; + struct prefix_ls lp; + struct route_node *rn; + + table = lsdb->type[lsa->data->type].db; + lsdb_prefix_set (&lp, lsa); + rn = route_node_get (table, (struct prefix *)&lp); + if (!rn->info) + { + if (IS_LSA_SELF (lsa)) + lsdb->type[lsa->data->type].count_self++; + lsdb->type[lsa->data->type].count++; + lsdb->total++; + } + else + { + if (rn->info == lsa) + return; + + ospf_lsa_unlock (rn->info); + route_unlock_node (rn); + } + +#ifdef MONITOR_LSDB_CHANGE + if (lsdb->new_lsa_hook != NULL) + (* lsdb->new_lsa_hook)(lsa); +#endif /* MONITOR_LSDB_CHANGE */ + rn->info = ospf_lsa_lock (lsa); +} + +void +ospf_lsdb_delete (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) +{ + struct route_table *table; + struct prefix_ls lp; + struct route_node *rn; + + table = lsdb->type[lsa->data->type].db; + lsdb_prefix_set (&lp, lsa); + rn = route_node_lookup (table, (struct prefix *) &lp); + if (rn) + if (rn->info == lsa) + { + if (IS_LSA_SELF (lsa)) + lsdb->type[lsa->data->type].count_self--; + lsdb->type[lsa->data->type].count--; + lsdb->total--; + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); +#ifdef MONITOR_LSDB_CHANGE + if (lsdb->del_lsa_hook != NULL) + (* lsdb->del_lsa_hook)(lsa); +#endif /* MONITOR_LSDB_CHANGE */ + ospf_lsa_unlock (lsa); + return; + } +} + +void +ospf_lsdb_delete_all (struct ospf_lsdb *lsdb) +{ + struct route_table *table; + struct route_node *rn; + struct ospf_lsa *lsa; + int i; + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + { + table = lsdb->type[i].db; + for (rn = route_top (table); rn; rn = route_next (rn)) + if ((lsa = (rn->info)) != NULL) + { + if (IS_LSA_SELF (lsa)) + lsdb->type[i].count_self--; + lsdb->type[i].count--; + lsdb->total--; + rn->info = NULL; + route_unlock_node (rn); +#ifdef MONITOR_LSDB_CHANGE + if (lsdb->del_lsa_hook != NULL) + (* lsdb->del_lsa_hook)(lsa); +#endif /* MONITOR_LSDB_CHANGE */ + ospf_lsa_unlock (lsa); + } + } +} + +struct ospf_lsa * +ospf_lsdb_lookup (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) +{ + struct route_table *table; + struct prefix_ls lp; + struct route_node *rn; + struct ospf_lsa *find; + + table = lsdb->type[lsa->data->type].db; + lsdb_prefix_set (&lp, lsa); + rn = route_node_lookup (table, (struct prefix *) &lp); + if (rn) + { + find = rn->info; + route_unlock_node (rn); + return find; + } + return NULL; +} + +struct ospf_lsa * +ospf_lsdb_lookup_by_id (struct ospf_lsdb *lsdb, u_char type, + struct in_addr id, struct in_addr adv_router) +{ + struct route_table *table; + struct prefix_ls lp; + struct route_node *rn; + struct ospf_lsa *find; + + table = lsdb->type[type].db; + + memset (&lp, 0, sizeof (struct prefix_ls)); + lp.family = 0; + lp.prefixlen = 64; + lp.id = id; + lp.adv_router = adv_router; + + rn = route_node_lookup (table, (struct prefix *) &lp); + if (rn) + { + find = rn->info; + route_unlock_node (rn); + return find; + } + return NULL; +} + +struct ospf_lsa * +ospf_lsdb_lookup_by_id_next (struct ospf_lsdb *lsdb, u_char type, + struct in_addr id, struct in_addr adv_router, + int first) +{ + struct route_table *table; + struct prefix_ls lp; + struct route_node *rn; + struct ospf_lsa *find; + + table = lsdb->type[type].db; + + memset (&lp, 0, sizeof (struct prefix_ls)); + lp.family = 0; + lp.prefixlen = 64; + lp.id = id; + lp.adv_router = adv_router; + + if (first) + rn = route_top (table); + else + { + rn = route_node_get (table, (struct prefix *) &lp); + rn = route_next (rn); + } + + for (; rn; rn = route_next (rn)) + if (rn->info) + break; + + if (rn && rn->info) + { + find = rn->info; + route_unlock_node (rn); + return find; + } + return NULL; +} + +unsigned long +ospf_lsdb_count_all (struct ospf_lsdb *lsdb) +{ + return lsdb->total; +} + +unsigned long +ospf_lsdb_count (struct ospf_lsdb *lsdb, int type) +{ + return lsdb->type[type].count; +} + +unsigned long +ospf_lsdb_count_self (struct ospf_lsdb *lsdb, int type) +{ + return lsdb->type[type].count_self; +} + +unsigned long +ospf_lsdb_isempty (struct ospf_lsdb *lsdb) +{ + return (lsdb->total == 0); +} + +struct ospf_lsa * +foreach_lsa (struct route_table *table, void *p_arg, int int_arg, + int (*callback) (struct ospf_lsa *, void *, int)) +{ + struct route_node *rn; + struct ospf_lsa *lsa; + + for (rn = route_top (table); rn; rn = route_next (rn)) + if ((lsa = rn->info) != NULL) + if (callback (lsa, p_arg, int_arg)) + return lsa; + + return NULL; +} diff --git a/ospfd/ospf_lsdb.h b/ospfd/ospf_lsdb.h new file mode 100644 index 00000000..34344b3b --- /dev/null +++ b/ospfd/ospf_lsdb.h @@ -0,0 +1,83 @@ +/* + * OSPF LSDB support. + * Copyright (C) 1999, 2000 Alex Zinin, Kunihiro Ishiguro, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_LSDB_H +#define _ZEBRA_OSPF_LSDB_H + +/* OSPF LSDB structure. */ +struct ospf_lsdb +{ + struct + { + unsigned long count; + unsigned long count_self; + struct route_table *db; + } type[OSPF_MAX_LSA]; + unsigned long total; +#define MONITOR_LSDB_CHANGE 1 /* XXX */ +#ifdef MONITOR_LSDB_CHANGE + /* Hooks for callback functions to catch every add/del event. */ + int (* new_lsa_hook)(struct ospf_lsa *); + int (* del_lsa_hook)(struct ospf_lsa *); +#endif /* MONITOR_LSDB_CHANGE */ +}; + +/* Macros. */ +#define LSDB_LOOP(T,N,L) \ + for ((N) = route_top ((T)); ((N)); ((N)) = route_next ((N))) \ + if (((L) = (N)->info)) + +#define ROUTER_LSDB(A) ((A)->lsdb->type[OSPF_ROUTER_LSA].db) +#define NETWORK_LSDB(A) ((A)->lsdb->type[OSPF_NETWORK_LSA].db) +#define SUMMARY_LSDB(A) ((A)->lsdb->type[OSPF_SUMMARY_LSA].db) +#define ASBR_SUMMARY_LSDB(A) ((A)->lsdb->type[OSPF_ASBR_SUMMARY_LSA].db) +#define EXTERNAL_LSDB(O) ((O)->lsdb->type[OSPF_AS_EXTERNAL_LSA].db) +#define NSSA_LSDB(A) ((A)->lsdb->type[OSPF_AS_NSSA_LSA].db) +#define OPAQUE_LINK_LSDB(A) ((A)->lsdb->type[OSPF_OPAQUE_LINK_LSA].db) +#define OPAQUE_AREA_LSDB(A) ((A)->lsdb->type[OSPF_OPAQUE_AREA_LSA].db) +#define OPAQUE_AS_LSDB(O) ((O)->lsdb->type[OSPF_OPAQUE_AS_LSA].db) + +#define AREA_LSDB(A,T) ((A)->lsdb->type[(T)].db) +#define AS_LSDB(O,T) ((O)->lsdb->type[(T)].db) + +/* OSPF LSDB related functions. */ +struct ospf_lsdb *ospf_lsdb_new (); +void ospf_lsdb_init (struct ospf_lsdb *); +void ospf_lsdb_free (struct ospf_lsdb *); +void ospf_lsdb_cleanup (struct ospf_lsdb *); +void ospf_lsdb_add (struct ospf_lsdb *, struct ospf_lsa *); +void ospf_lsdb_delete (struct ospf_lsdb *, struct ospf_lsa *); +void ospf_lsdb_delete_all (struct ospf_lsdb *); +struct ospf_lsa *ospf_lsdb_lookup (struct ospf_lsdb *, struct ospf_lsa *); +struct ospf_lsa *ospf_lsdb_lookup_by_id (struct ospf_lsdb *, u_char, + struct in_addr, struct in_addr); +struct ospf_lsa *ospf_lsdb_lookup_by_id_next (struct ospf_lsdb *, u_char, + struct in_addr, struct in_addr, + int); +unsigned long ospf_lsdb_count_all (struct ospf_lsdb *); +unsigned long ospf_lsdb_count (struct ospf_lsdb *, int); +unsigned long ospf_lsdb_count_self (struct ospf_lsdb *, int); +unsigned long ospf_lsdb_isempty (struct ospf_lsdb *); +struct ospf_lsa *foreach_lsa (struct route_table *, void *, int, + int (*callback) (struct ospf_lsa *, void *, int)); + +#endif /* _ZEBRA_OSPF_LSDB_H */ diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c new file mode 100644 index 00000000..82960b24 --- /dev/null +++ b/ospfd/ospf_main.c @@ -0,0 +1,293 @@ +/* + * OSPFd main routine. + * Copyright (C) 1998, 99 Kunihiro Ishiguro, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "version.h" +#include "getopt.h" +#include "thread.h" +#include "prefix.h" +#include "linklist.h" +#include "if.h" +#include "vector.h" +#include "vty.h" +#include "command.h" +#include "filter.h" +#include "plist.h" +#include "stream.h" +#include "log.h" +#include "memory.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_vty.h" + +/* Configuration filename and directory. */ +char config_current[] = OSPF_DEFAULT_CONFIG; +char config_default[] = SYSCONFDIR OSPF_DEFAULT_CONFIG; + +/* OSPFd options. */ +struct option longopts[] = +{ + { "daemon", no_argument, NULL, 'd'}, + { "config_file", required_argument, NULL, 'f'}, + { "pid_file", required_argument, NULL, 'i'}, + { "log_mode", no_argument, NULL, 'l'}, + { "help", no_argument, NULL, 'h'}, + { "vty_addr", required_argument, NULL, 'A'}, + { "vty_port", required_argument, NULL, 'P'}, + { "version", no_argument, NULL, 'v'}, + { 0 } +}; + +/* OSPFd program name */ + +/* Master of threads. */ +struct thread_master *master; + +/* Process ID saved for use by init system */ +char *pid_file = PATH_OSPFD_PID; + +/* Help information display. */ +static void +usage (char *progname, int status) +{ + if (status != 0) + fprintf (stderr, "Try `%s --help' for more information.\n", progname); + else + { + printf ("Usage : %s [OPTION...]\n\ +Daemon which manages OSPF.\n\n\ +-d, --daemon Runs in daemon mode\n\ +-f, --config_file Set configuration file name\n\ +-i, --pid_file Set process identifier file name\n\ +-A, --vty_addr Set vty's bind address\n\ +-P, --vty_port Set vty's port number\n\ +-v, --version Print program version\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); + } + exit (status); +} + +/* SIGHUP handler. */ +void +sighup (int sig) +{ + zlog (NULL, LOG_INFO, "SIGHUP received"); +} + +/* SIGINT handler. */ +void +sigint (int sig) +{ + zlog (NULL, LOG_INFO, "Terminating on signal"); + + ospf_terminate (); + + exit (0); +} + +/* SIGUSR1 handler. */ +void +sigusr1 (int sig) +{ + zlog_rotate (NULL); +} + +/* Signal wrapper. */ +RETSIGTYPE * +signal_set (int signo, void (*func)(int)) +{ + int ret; + struct sigaction sig; + struct sigaction osig; + + sig.sa_handler = func; + sigemptyset (&sig.sa_mask); + sig.sa_flags = 0; +#ifdef SA_RESTART + sig.sa_flags |= SA_RESTART; +#endif /* SA_RESTART */ + + ret = sigaction (signo, &sig, &osig); + + if (ret < 0) + return (SIG_ERR); + else + return (osig.sa_handler); +} + +/* Initialization of signal handles. */ +void +signal_init () +{ + signal_set (SIGHUP, sighup); + signal_set (SIGINT, sigint); + signal_set (SIGTERM, sigint); + signal_set (SIGPIPE, SIG_IGN); +#ifdef SIGTSTP + signal_set (SIGTSTP, SIG_IGN); +#endif +#ifdef SIGTTIN + signal_set (SIGTTIN, SIG_IGN); +#endif +#ifdef SIGTTOU + signal_set (SIGTTOU, SIG_IGN); +#endif + signal_set (SIGUSR1, sigusr1); +} + +/* OSPFd main routine. */ +int +main (int argc, char **argv) +{ + char *p; + char *vty_addr = NULL; + int vty_port = 0; + int daemon_mode = 0; + char *config_file = NULL; + char *progname; + struct thread thread; + + /* Set umask before anything for security */ + umask (0027); + + /* get program name */ + progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + + /* Invoked by a priviledged user? -- endo. */ + if (getuid () != 0) + { + errno = EPERM; + perror (progname); + exit (1); + } + + zlog_default = openzlog (progname, ZLOG_NOLOG, ZLOG_OSPF, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + + while (1) + { + int opt; + + opt = getopt_long (argc, argv, "dlf:hA:P:v", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + case 'd': + daemon_mode = 1; + break; + case 'f': + config_file = optarg; + break; + case 'A': + vty_addr = optarg; + break; + case 'i': + pid_file = optarg; + break; + case 'P': + vty_port = atoi (optarg); + break; + case 'v': + print_version (progname); + exit (0); + break; + case 'h': + usage (progname, 0); + break; + default: + usage (progname, 1); + break; + } + } + + /* Initializations. */ + master = thread_master_create (); + + /* Library inits. */ + signal_init (); + cmd_init (1); + debug_init (); + vty_init (); + memory_init (); + + access_list_init (); + prefix_list_init (); + + /* OSPFd inits. */ + ospf_init (); + ospf_if_init (); + ospf_zebra_init (); + + /* OSPF vty inits. */ + ospf_vty_init (); + ospf_vty_show_init (); + + ospf_route_map_init (); +#ifdef HAVE_SNMP + ospf_snmp_init (); +#endif /* HAVE_SNMP */ +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_init (); +#endif /* HAVE_OPAQUE_LSA */ + + sort_node (); + + /* Get configuration file. */ + vty_read_config (config_file, config_current, config_default); + + /* Change to the daemon program. */ + if (daemon_mode) + daemon (0, 0); + + /* Process id file create. */ + pid_output (pid_file); + + /* Create VTY socket */ + vty_serv_sock (vty_addr, + vty_port ? vty_port : OSPF_VTY_PORT, OSPF_VTYSH_PATH); + + /* Print banner. */ + zlog (NULL, LOG_INFO, "OSPFd (%s) starts", ZEBRA_VERSION); + + /* Fetch next active thread. */ + while (thread_fetch (master, &thread)) + thread_call (&thread); + + /* Not reached. */ + exit (0); +} + diff --git a/ospfd/ospf_neighbor.h b/ospfd/ospf_neighbor.h new file mode 100644 index 00000000..f7b18742 --- /dev/null +++ b/ospfd/ospf_neighbor.h @@ -0,0 +1,106 @@ +/* + * OSPF Neighbor functions. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_NEIGHBOR_H +#define _ZEBRA_OSPF_NEIGHBOR_H + +/* Neighbor Data Structure */ +struct ospf_neighbor +{ + /* This neighbor's parent ospf interface. */ + struct ospf_interface *oi; + + /* OSPF neighbor Information */ + u_char state; /* NSM status. */ + u_char dd_flags; /* DD bit flags. */ + u_int32_t dd_seqnum; /* DD Sequence Number. */ + + /* Neighbor Information from Hello. */ + struct prefix address; /* Neighbor Interface Address. */ + + struct in_addr src; /* Src address. */ + struct in_addr router_id; /* Router ID. */ + u_char options; /* Options. */ + int priority; /* Router Priority. */ + struct in_addr d_router; /* Designated Router. */ + struct in_addr bd_router; /* Backup Designated Router. */ + + /* Last sent Database Description packet. */ + struct ospf_packet *last_send; + /* Timestemp when last Database Description packet was sent */ + struct timeval last_send_ts; + + /* Last received Databse Description packet. */ + struct + { + u_char options; + u_char flags; + u_int32_t dd_seqnum; + } last_recv; + + /* LSA data. */ + struct ospf_lsdb ls_rxmt; + struct ospf_lsdb db_sum; + struct ospf_lsdb ls_req; + struct ospf_lsa *ls_req_last; + + u_int32_t crypt_seqnum; /* Cryptographic Sequence Number. */ + + /* Timer values. */ + u_int32_t v_inactivity; + u_int32_t v_db_desc; + u_int32_t v_ls_req; + u_int32_t v_ls_upd; + + /* Threads. */ + struct thread *t_inactivity; + struct thread *t_db_desc; + struct thread *t_ls_req; + struct thread *t_ls_upd; + struct thread *t_hello_reply; + + /* Statistics Field */ + u_int32_t state_change; + struct ospf_nbr_nbma *nbr_nbma; +}; + +/* Macros. */ +#define NBR_IS_DR(n) IPV4_ADDR_SAME (&n->address.u.prefix4, &n->d_router) +#define NBR_IS_BDR(n) IPV4_ADDR_SAME (&n->address.u.prefix4, &n->bd_router) + +/* Prototypes. */ +struct ospf_neighbor *ospf_nbr_new (struct ospf_interface *); +void ospf_nbr_free (struct ospf_neighbor *); +void ospf_nbr_delete (struct ospf_neighbor *); +int ospf_nbr_bidirectional (struct in_addr *, struct in_addr *, int); +void ospf_nbr_add_self (struct ospf_interface *); +int ospf_nbr_count (struct route_table *, int); +#ifdef HAVE_OPAQUE_LSA +int ospf_opaque_capable_nbr_count (struct route_table *nbrs, int status); +#endif /* HAVE_OPAQUE_LSA */ +struct ospf_neighbor *ospf_nbr_lookup_by_addr (struct route_table *, + struct in_addr *); +struct ospf_neighbor *ospf_nbr_lookup_by_routerid (struct route_table *, + struct in_addr *); +void ospf_renegotiate_optional_capabilities (struct ospf *top); + +#endif /* _ZEBRA_OSPF_NEIGHBOR_H */ diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c new file mode 100644 index 00000000..56ec8647 --- /dev/null +++ b/ospfd/ospf_network.c @@ -0,0 +1,192 @@ +/* + * OSPF network related functions + * Copyright (C) 1999 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "thread.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "sockunion.h" +#include "log.h" +#include "sockopt.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_network.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_packet.h" + +/* Join to the OSPF ALL SPF ROUTERS multicast group. */ +int +ospf_if_add_allspfrouters (struct ospf *top, struct prefix *p, + unsigned int ifindex) +{ + int ret; + + ret = setsockopt_multicast_ipv4 (top->fd, IP_ADD_MEMBERSHIP, + p->u.prefix4, htonl (OSPF_ALLSPFROUTERS), + ifindex); + if (ret < 0) + zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (AllSPFRouters): %s", + strerror (errno)); + else + zlog_info ("interface %s join AllSPFRouters Multicast group.", + inet_ntoa (p->u.prefix4)); + + return ret; +} + +int +ospf_if_drop_allspfrouters (struct ospf *top, struct prefix *p, + unsigned int ifindex) +{ + int ret; + + ret = setsockopt_multicast_ipv4 (top->fd, IP_DROP_MEMBERSHIP, + p->u.prefix4, htonl (OSPF_ALLSPFROUTERS), + ifindex); + if (ret < 0) + zlog_warn("can't setsockopt IP_DROP_MEMBERSHIP (AllSPFRouters): %s", + strerror (errno)); + else + zlog_info ("interface %s leave AllSPFRouters Multicast group.", + inet_ntoa (p->u.prefix4)); + + return ret; +} + +/* Join to the OSPF ALL Designated ROUTERS multicast group. */ +int +ospf_if_add_alldrouters (struct ospf *top, struct prefix *p, unsigned int + ifindex) +{ + int ret; + + ret = setsockopt_multicast_ipv4 (top->fd, IP_ADD_MEMBERSHIP, + p->u.prefix4, htonl (OSPF_ALLDROUTERS), + ifindex); + if (ret < 0) + zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (AllDRouters): %s", + strerror (errno)); + else + zlog_info ("interface %s join AllDRouters Multicast group.", + inet_ntoa (p->u.prefix4)); + + return ret; +} + +int +ospf_if_drop_alldrouters (struct ospf *top, struct prefix *p, unsigned int + ifindex) +{ + int ret; + + ret = setsockopt_multicast_ipv4 (top->fd, IP_DROP_MEMBERSHIP, + p->u.prefix4, htonl (OSPF_ALLDROUTERS), + ifindex); + if (ret < 0) + zlog_warn ("can't setsockopt IP_DROP_MEMBERSHIP (AllDRouters): %s", + strerror (errno)); + else + zlog_info ("interface %s leave AllDRouters Multicast group.", + inet_ntoa (p->u.prefix4)); + + return ret; +} + +int +ospf_if_ipmulticast (struct ospf *top, struct prefix *p, unsigned int ifindex) +{ + u_char val; + int ret, len; + + val = 0; + len = sizeof (val); + + /* Prevent receiving self-origined multicast packets. */ + ret = setsockopt (top->fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&val, len); + if (ret < 0) + zlog_warn ("can't setsockopt IP_MULTICAST_LOOP(0): %s", strerror (errno)); + + /* Explicitly set multicast ttl to 1 -- endo. */ + val = 1; + ret = setsockopt (top->fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&val, len); + if (ret < 0) + zlog_warn ("can't setsockopt IP_MULTICAST_TTL(1): %s", strerror (errno)); + + ret = setsockopt_multicast_ipv4 (top->fd, IP_MULTICAST_IF, + p->u.prefix4, 0, ifindex); + if (ret < 0) + zlog_warn ("can't setsockopt IP_MULTICAST_IF: %s", strerror (errno)); + + return ret; +} + +int +ospf_sock_init (void) +{ + int ospf_sock; + int ret, tos, hincl = 1; + + ospf_sock = socket (AF_INET, SOCK_RAW, IPPROTO_OSPFIGP); + if (ospf_sock < 0) + { + zlog_warn ("ospf_read_sock_init: socket: %s", strerror (errno)); + return -1; + } + + /* Set precedence field. */ +#ifdef IPTOS_PREC_INTERNETCONTROL + tos = IPTOS_PREC_INTERNETCONTROL; + ret = setsockopt (ospf_sock, IPPROTO_IP, IP_TOS, + (char *) &tos, sizeof (int)); + if (ret < 0) + { + zlog_warn ("can't set sockopt IP_TOS %d to socket %d", tos, ospf_sock); + close (ospf_sock); /* Prevent sd leak. */ + return ret; + } +#endif /* IPTOS_PREC_INTERNETCONTROL */ + + /* we will include IP header with packet */ + ret = setsockopt (ospf_sock, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof (hincl)); + if (ret < 0) + zlog_warn ("Can't set IP_HDRINCL option"); + +#if defined (IP_PKTINFO) + ret = setsockopt (ospf_sock, IPPROTO_IP, IP_PKTINFO, &hincl, sizeof (hincl)); + if (ret < 0) + zlog_warn ("Can't set IP_PKTINFO option"); +#elif defined (IP_RECVIF) + ret = setsockopt (ospf_sock, IPPROTO_IP, IP_RECVIF, &hincl, sizeof (hincl)); + if (ret < 0) + zlog_warn ("Can't set IP_RECVIF option"); +#else +#warning "cannot be able to receive link information on this OS" +#endif + + return ospf_sock; +} diff --git a/ospfd/ospf_network.h b/ospfd/ospf_network.h new file mode 100644 index 00000000..52a25fd9 --- /dev/null +++ b/ospfd/ospf_network.h @@ -0,0 +1,34 @@ +/* + * OSPF network related functions. + * Copyright (C) 1999 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_NETWORK_H +#define _ZEBRA_OSPF_NETWORK_H + +/* Prototypes. */ +int ospf_if_add_allspfrouters (struct ospf *, struct prefix *, unsigned int); +int ospf_if_drop_allspfrouters (struct ospf *, struct prefix *, unsigned int); +int ospf_if_add_alldrouters (struct ospf *, struct prefix *, unsigned int); +int ospf_if_drop_alldrouters (struct ospf *, struct prefix *, unsigned int); +int ospf_if_ipmulticast (struct ospf *, struct prefix *, unsigned int); +int ospf_sock_init (void); + +#endif /* _ZEBRA_OSPF_NETWORK_H */ diff --git a/ospfd/ospf_nsm.h b/ospfd/ospf_nsm.h new file mode 100644 index 00000000..3d257305 --- /dev/null +++ b/ospfd/ospf_nsm.h @@ -0,0 +1,91 @@ +/* + * OSPF version 2 Neighbor State Machine + * From RFC2328 [OSPF Version 2] + * Copyright (C) 1999 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_NSM_H +#define _ZEBRA_OSPF_NSM_H + +/* OSPF Neighbor State Machine State. */ +#define NSM_DependUpon 0 +#define NSM_Down 1 +#define NSM_Attempt 2 +#define NSM_Init 3 +#define NSM_TwoWay 4 +#define NSM_ExStart 5 +#define NSM_Exchange 6 +#define NSM_Loading 7 +#define NSM_Full 8 +#define OSPF_NSM_STATE_MAX 9 + +/* OSPF Neighbor State Machine Event. */ +#define NSM_NoEvent 0 +#define NSM_HelloReceived 1 +#define NSM_Start 2 +#define NSM_TwoWayReceived 3 +#define NSM_NegotiationDone 4 +#define NSM_ExchangeDone 5 +#define NSM_BadLSReq 6 +#define NSM_LoadingDone 7 +#define NSM_AdjOK 8 +#define NSM_SeqNumberMismatch 9 +#define NSM_OneWayReceived 10 +#define NSM_KillNbr 11 +#define NSM_InactivityTimer 12 +#define NSM_LLDown 13 +#define OSPF_NSM_EVENT_MAX 14 + +/* Macro for OSPF NSM timer turn on. */ +#define OSPF_NSM_TIMER_ON(T,F,V) \ + do { \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), nbr, (V)); \ + } while (0) + +/* Macro for OSPF NSM timer turn off. */ +#define OSPF_NSM_TIMER_OFF(X) \ + do { \ + if (X) \ + { \ + thread_cancel (X); \ + (X) = NULL; \ + } \ + } while (0) + +/* Macro for OSPF NSM schedule event. */ +#define OSPF_NSM_EVENT_SCHEDULE(N,E) \ + thread_add_event (master, ospf_nsm_event, (N), (E)) + +/* Macro for OSPF NSM execute event. */ +#define OSPF_NSM_EVENT_EXECUTE(N,E) \ + thread_execute (master, ospf_nsm_event, (N), (E)) + +/* Prototypes. */ +int ospf_nsm_event (struct thread *); +void nsm_change_state (struct ospf_neighbor *, int); +void ospf_check_nbr_loading (struct ospf_neighbor *); +int ospf_db_summary_isempty (struct ospf_neighbor *); +int ospf_db_summary_count (struct ospf_neighbor *); +void ospf_db_summary_clear (struct ospf_neighbor *); +/* void ospf_db_summary_delete_all (struct ospf_neighbor *); */ + +#endif /* _ZEBRA_OSPF_NSM_H */ + diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c new file mode 100644 index 00000000..67c6608b --- /dev/null +++ b/ospfd/ospf_opaque.c @@ -0,0 +1,2392 @@ +/* + * This is an implementation of rfc2370. + * Copyright (C) 2001 KDD R&D Laboratories, Inc. + * http://www.kddlabs.co.jp/ + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/***** MTYPE definitions are not reflected to "memory.h" yet. *****/ +#define MTYPE_OSPF_OPAQUE_FUNCTAB 0 +#define MTYPE_OPAQUE_INFO_PER_TYPE 0 +#define MTYPE_OPAQUE_INFO_PER_ID 0 + +#include +#ifdef HAVE_OPAQUE_LSA + +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "memory.h" +#include "command.h" +#include "vty.h" +#include "stream.h" +#include "log.h" +#include "thread.h" +#include "hash.h" +#include "sockunion.h" /* for inet_aton() */ + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_zebra.h" + +/*------------------------------------------------------------------------* + * Followings are initialize/terminate functions for Opaque-LSAs handling. + *------------------------------------------------------------------------*/ + +#ifdef HAVE_OSPF_TE +#include "ospfd/ospf_te.h" +#endif /* HAVE_OSPF_TE */ + +static void ospf_opaque_register_vty (void); +static void ospf_opaque_funclist_init (void); +static void ospf_opaque_funclist_term (void); +static void free_opaque_info_per_type (void *val); +static void free_opaque_info_per_id (void *val); +static int ospf_opaque_lsa_install_hook (struct ospf_lsa *lsa); +static int ospf_opaque_lsa_delete_hook (struct ospf_lsa *lsa); + +void +ospf_opaque_init (void) +{ + ospf_opaque_register_vty (); + ospf_opaque_funclist_init (); + +#ifdef HAVE_OSPF_TE + if (ospf_mpls_te_init () != 0) + exit (1); +#endif /* HAVE_OSPF_TE */ + + return; +} + +void +ospf_opaque_term (void) +{ +#ifdef HAVE_OSPF_TE + ospf_mpls_te_term (); +#endif /* HAVE_OSPF_TE */ + + ospf_opaque_funclist_term (); + return; +} + +int +ospf_opaque_type9_lsa_init (struct ospf_interface *oi) +{ + if (oi->opaque_lsa_self != NULL) + list_delete (oi->opaque_lsa_self); + + oi->opaque_lsa_self = list_new (); + oi->opaque_lsa_self->del = free_opaque_info_per_type; + oi->t_opaque_lsa_self = NULL; + return 0; +} + +void +ospf_opaque_type9_lsa_term (struct ospf_interface *oi) +{ + OSPF_TIMER_OFF (oi->t_opaque_lsa_self); + if (oi->opaque_lsa_self != NULL) + list_delete (oi->opaque_lsa_self); + oi->opaque_lsa_self = NULL; + return; +} + +int +ospf_opaque_type10_lsa_init (struct ospf_area *area) +{ + if (area->opaque_lsa_self != NULL) + list_delete (area->opaque_lsa_self); + + area->opaque_lsa_self = list_new (); + area->opaque_lsa_self->del = free_opaque_info_per_type; + area->t_opaque_lsa_self = NULL; + +#ifdef MONITOR_LSDB_CHANGE + area->lsdb->new_lsa_hook = ospf_opaque_lsa_install_hook; + area->lsdb->del_lsa_hook = ospf_opaque_lsa_delete_hook; +#endif /* MONITOR_LSDB_CHANGE */ + return 0; +} + +void +ospf_opaque_type10_lsa_term (struct ospf_area *area) +{ +#ifdef MONITOR_LSDB_CHANGE + area->lsdb->new_lsa_hook = + area->lsdb->del_lsa_hook = NULL; +#endif /* MONITOR_LSDB_CHANGE */ + + OSPF_TIMER_OFF (area->t_opaque_lsa_self); + if (area->opaque_lsa_self != NULL) + list_delete (area->opaque_lsa_self); + area->opaque_lsa_self = NULL; + return; +} + +int +ospf_opaque_type11_lsa_init (struct ospf *top) +{ + if (top->opaque_lsa_self != NULL) + list_delete (top->opaque_lsa_self); + + top->opaque_lsa_self = list_new (); + top->opaque_lsa_self->del = free_opaque_info_per_type; + top->t_opaque_lsa_self = NULL; + +#ifdef MONITOR_LSDB_CHANGE + top->lsdb->new_lsa_hook = ospf_opaque_lsa_install_hook; + top->lsdb->del_lsa_hook = ospf_opaque_lsa_delete_hook; +#endif /* MONITOR_LSDB_CHANGE */ + return 0; +} + +void +ospf_opaque_type11_lsa_term (struct ospf *top) +{ +#ifdef MONITOR_LSDB_CHANGE + top->lsdb->new_lsa_hook = + top->lsdb->del_lsa_hook = NULL; +#endif /* MONITOR_LSDB_CHANGE */ + + OSPF_TIMER_OFF (top->t_opaque_lsa_self); + if (top->opaque_lsa_self != NULL) + list_delete (top->opaque_lsa_self); + top->opaque_lsa_self = NULL; + return; +} + +static const char * +ospf_opaque_type_name (u_char opaque_type) +{ + const char *name = "Unknown"; + + switch (opaque_type) + { + case OPAQUE_TYPE_WILDCARD: /* This is a special assignment! */ + name = "Wildcard"; + break; + case OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA: + name = "Traffic Engineering LSA"; + break; + case OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC: + name = "Sycamore optical topology description"; + break; + case OPAQUE_TYPE_GRACE_LSA: + name = "Grace-LSA"; + break; + default: + if (OPAQUE_TYPE_RANGE_UNASSIGNED (opaque_type)) + name = "Unassigned"; + else if (OPAQUE_TYPE_RANGE_RESERVED (opaque_type)) + name = "Private/Experimental"; + break; + } + return name; +} + +/*------------------------------------------------------------------------* + * Followings are management functions to store user specified callbacks. + *------------------------------------------------------------------------*/ + +struct opaque_info_per_type; /* Forward declaration. */ + +struct ospf_opaque_functab +{ + u_char opaque_type; + struct opaque_info_per_type *oipt; + + int (* new_if_hook)(struct interface *ifp); + int (* del_if_hook)(struct interface *ifp); + void (* ism_change_hook)(struct ospf_interface *oi, int old_status); + void (* nsm_change_hook)(struct ospf_neighbor *nbr, int old_status); + void (* config_write_router)(struct vty *vty); + void (* config_write_if )(struct vty *vty, struct interface *ifp); + void (* config_write_debug )(struct vty *vty); + void (* show_opaque_info )(struct vty *vty, struct ospf_lsa *lsa); + int (* lsa_originator)(void *arg); + void (* lsa_refresher )(struct ospf_lsa *lsa); + int (* new_lsa_hook)(struct ospf_lsa *lsa); + int (* del_lsa_hook)(struct ospf_lsa *lsa); +}; + +static list ospf_opaque_type9_funclist; +static list ospf_opaque_type10_funclist; +static list ospf_opaque_type11_funclist; + +static void +ospf_opaque_del_functab (void *val) +{ + XFREE (MTYPE_OSPF_OPAQUE_FUNCTAB, val); + return; +} + +static void +ospf_opaque_funclist_init (void) +{ + list funclist; + + funclist = ospf_opaque_type9_funclist = list_new (); + funclist->del = ospf_opaque_del_functab; + + funclist = ospf_opaque_type10_funclist = list_new (); + funclist->del = ospf_opaque_del_functab; + + funclist = ospf_opaque_type11_funclist = list_new (); + funclist->del = ospf_opaque_del_functab; + return; +} + +static void +ospf_opaque_funclist_term (void) +{ + list funclist; + + funclist = ospf_opaque_type9_funclist; + list_delete (funclist); + + funclist = ospf_opaque_type10_funclist; + list_delete (funclist); + + funclist = ospf_opaque_type11_funclist; + list_delete (funclist); + return; +} + +static list +ospf_get_opaque_funclist (u_char lsa_type) +{ + list funclist = NULL; + + switch (lsa_type) + { + case OSPF_OPAQUE_LINK_LSA: + funclist = ospf_opaque_type9_funclist; + break; + case OSPF_OPAQUE_AREA_LSA: + funclist = ospf_opaque_type10_funclist; + break; + case OSPF_OPAQUE_AS_LSA: + funclist = ospf_opaque_type11_funclist; + break; + default: + zlog_warn ("ospf_get_opaque_funclist: Unexpected LSA-type(%u)", lsa_type); + break; + } + return funclist; +} + +int +ospf_register_opaque_functab ( + u_char lsa_type, + u_char opaque_type, + int (* new_if_hook)(struct interface *ifp), + int (* del_if_hook)(struct interface *ifp), + void (* ism_change_hook)(struct ospf_interface *oi, int old_status), + void (* nsm_change_hook)(struct ospf_neighbor *nbr, int old_status), + void (* config_write_router)(struct vty *vty), + void (* config_write_if )(struct vty *vty, struct interface *ifp), + void (* config_write_debug )(struct vty *vty), + void (* show_opaque_info )(struct vty *vty, struct ospf_lsa *lsa), + int (* lsa_originator)(void *arg), + void (* lsa_refresher )(struct ospf_lsa *lsa), + int (* new_lsa_hook)(struct ospf_lsa *lsa), + int (* del_lsa_hook)(struct ospf_lsa *lsa)) +{ + list funclist; + struct ospf_opaque_functab *new; + int rc = -1; + + if ((funclist = ospf_get_opaque_funclist (lsa_type)) == NULL) + { + zlog_warn ("ospf_register_opaque_functab: Cannot get funclist for Type-%u LSAs?", lsa_type); + goto out; + } + else + { + listnode node; + struct ospf_opaque_functab *functab; + + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->opaque_type == opaque_type) + { + zlog_warn ("ospf_register_opaque_functab: Duplicated entry?: lsa_type(%u), opaque_type(%u)", lsa_type, opaque_type); + goto out; + } + } + + if ((new = XCALLOC (MTYPE_OSPF_OPAQUE_FUNCTAB, + sizeof (struct ospf_opaque_functab))) == NULL) + { + zlog_warn ("ospf_register_opaque_functab: XMALLOC: %s", strerror (errno)); + goto out; + } + + new->opaque_type = opaque_type; + new->oipt = NULL; + new->new_if_hook = new_if_hook; + new->del_if_hook = del_if_hook; + new->ism_change_hook = ism_change_hook; + new->nsm_change_hook = nsm_change_hook; + new->config_write_router = config_write_router; + new->config_write_if = config_write_if; + new->config_write_debug = config_write_debug; + new->show_opaque_info = show_opaque_info; + new->lsa_originator = lsa_originator; + new->lsa_refresher = lsa_refresher; + new->new_lsa_hook = new_lsa_hook; + new->del_lsa_hook = del_lsa_hook; + + listnode_add (funclist, new); + rc = 0; + +out: + return rc; +} + +void +ospf_delete_opaque_functab (u_char lsa_type, u_char opaque_type) +{ + list funclist; + listnode node; + struct ospf_opaque_functab *functab; + + if ((funclist = ospf_get_opaque_funclist (lsa_type)) != NULL) + for (node = listhead (funclist); node; nextnode (node)) + { + if ((functab = getdata (node)) != NULL + && functab->opaque_type == opaque_type) + { + /* Cleanup internal control information, if it still remains. */ + if (functab->oipt != NULL) + free_opaque_info_per_type (functab->oipt); + + /* Dequeue listnode entry from the list. */ + listnode_delete (funclist, functab); + + /* Avoid misjudgement in the next lookup. */ + if (listcount (funclist) == 0) + funclist->head = funclist->tail = NULL; + + XFREE (MTYPE_OSPF_OPAQUE_FUNCTAB, functab); + goto out; + } + } +out: + return; +} + +static struct ospf_opaque_functab * +ospf_opaque_functab_lookup (struct ospf_lsa *lsa) +{ + list funclist; + listnode node; + struct ospf_opaque_functab *functab; + u_char key = GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)); + + if ((funclist = ospf_get_opaque_funclist (lsa->data->type)) != NULL) + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->opaque_type == key) + return functab; + + return NULL; +} + +/*------------------------------------------------------------------------* + * Followings are management functions for self-originated LSA entries. + *------------------------------------------------------------------------*/ + +/* + * Opaque-LSA control information per opaque-type. + * Single Opaque-Type may have multiple instances; each of them will be + * identified by their opaque-id. + */ +struct opaque_info_per_type +{ + u_char opaque_type; + + enum { PROC_NORMAL, PROC_SUSPEND } status; + + /* + * Thread for (re-)origination scheduling for this opaque-type. + * + * Initial origination of Opaque-LSAs is controlled by generic + * Opaque-LSA handling module so that same opaque-type entries are + * called all at once when certain conditions are met. + * However, there might be cases that some Opaque-LSA clients need + * to (re-)originate their own Opaque-LSAs out-of-sync with others. + * This thread is prepared for that specific purpose. + */ + struct thread *t_opaque_lsa_self; + + /* + * Backpointer to an "owner" which is opaque-type dependent. + * type-9: struct ospf_interface + * type-10: struct ospf_area + * type-11: struct ospf + */ + void *owner; + + /* Collection of callback functions for this opaque-type. */ + struct ospf_opaque_functab *functab; + + /* List of Opaque-LSA control informations per opaque-id. */ + list id_list; +}; + +/* Opaque-LSA control information per opaque-id. */ +struct opaque_info_per_id +{ + u_int32_t opaque_id; + + /* Thread for refresh/flush scheduling for this opaque-type/id. */ + struct thread *t_opaque_lsa_self; + + /* Backpointer to Opaque-LSA control information per opaque-type. */ + struct opaque_info_per_type *opqctl_type; + + /* Here comes an actual Opaque-LSA entry for this opaque-type/id. */ + struct ospf_lsa *lsa; +}; + +static struct opaque_info_per_type *register_opaque_info_per_type (struct ospf_opaque_functab *functab, struct ospf_lsa *new); +static struct opaque_info_per_type *lookup_opaque_info_by_type (struct ospf_lsa *lsa); +static struct opaque_info_per_id *register_opaque_info_per_id (struct opaque_info_per_type *oipt, struct ospf_lsa *new); +static struct opaque_info_per_id *lookup_opaque_info_by_id (struct opaque_info_per_type *oipt, struct ospf_lsa *lsa); +static struct opaque_info_per_id *register_opaque_lsa (struct ospf_lsa *new); + + +static struct opaque_info_per_type * +register_opaque_info_per_type (struct ospf_opaque_functab *functab, + struct ospf_lsa *new) +{ + struct ospf *top; + struct opaque_info_per_type *oipt; + + if ((oipt = XCALLOC (MTYPE_OPAQUE_INFO_PER_TYPE, + sizeof (struct opaque_info_per_type))) == NULL) + { + zlog_warn ("register_opaque_info_per_type: XMALLOC: %s", strerror (errno)); + goto out; + } + + switch (new->data->type) + { + case OSPF_OPAQUE_LINK_LSA: + oipt->owner = new->oi; + listnode_add (new->oi->opaque_lsa_self, oipt); + break; + case OSPF_OPAQUE_AREA_LSA: + oipt->owner = new->area; + listnode_add (new->area->opaque_lsa_self, oipt); + break; + case OSPF_OPAQUE_AS_LSA: + top = ospf_top; + if (new->area != NULL && (top = new->area->top) == NULL) + { + free_opaque_info_per_type ((void *) oipt); + oipt = NULL; + goto out; /* This case may not exist. */ + } + oipt->owner = top; + listnode_add (top->opaque_lsa_self, oipt); + break; + default: + free_opaque_info_per_type ((void *) oipt); + oipt = NULL; + goto out; /* This case may not exist. */ + } + + oipt->opaque_type = GET_OPAQUE_TYPE (ntohl (new->data->id.s_addr)); + oipt->status = PROC_NORMAL; + oipt->t_opaque_lsa_self = NULL; + oipt->functab = functab; + functab->oipt = oipt; + oipt->id_list = list_new (); + oipt->id_list->del = free_opaque_info_per_id; + +out: + return oipt; +} + +static void +free_opaque_info_per_type (void *val) +{ + struct opaque_info_per_type *oipt = (struct opaque_info_per_type *) val; + struct opaque_info_per_id *oipi; + struct ospf_lsa *lsa; + listnode node; + + /* Control information per opaque-id may still exist. */ + for (node = listhead (oipt->id_list); node; nextnode (node)) + { + if ((oipi = getdata (node)) == NULL) + continue; + if ((lsa = oipi->lsa) == NULL) + continue; + if (IS_LSA_MAXAGE (lsa)) + continue; + ospf_opaque_lsa_flush_schedule (lsa); + } + + OSPF_TIMER_OFF (oipt->t_opaque_lsa_self); + list_delete (oipt->id_list); + XFREE (MTYPE_OPAQUE_INFO_PER_TYPE, oipt); + return; +} + +static struct opaque_info_per_type * +lookup_opaque_info_by_type (struct ospf_lsa *lsa) +{ + struct ospf *top; + struct ospf_area *area; + struct ospf_interface *oi; + list listtop = NULL; + listnode node; + struct opaque_info_per_type *oipt = NULL; + u_char key = GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)); + + switch (lsa->data->type) + { + case OSPF_OPAQUE_LINK_LSA: + if ((oi = lsa->oi) != NULL) + listtop = oi->opaque_lsa_self; + else + zlog_warn ("Type-9 Opaque-LSA: Reference to OI is missing?"); + break; + case OSPF_OPAQUE_AREA_LSA: + if ((area = lsa->area) != NULL) + listtop = area->opaque_lsa_self; + else + zlog_warn ("Type-10 Opaque-LSA: Reference to AREA is missing?"); + break; + case OSPF_OPAQUE_AS_LSA: + top = ospf_top; + if ((area = lsa->area) != NULL && (top = area->top) == NULL) + { + zlog_warn ("Type-11 Opaque-LSA: Reference to OSPF is missing?"); + break; /* Unlikely to happen. */ + } + listtop = top->opaque_lsa_self; + break; + default: + zlog_warn ("lookup_opaque_info_by_type: Unexpected LSA-type(%u)", lsa->data->type); + break; + } + + if (listtop != NULL) + for (node = listhead (listtop); node; nextnode (node)) + if ((oipt = getdata (node)) != NULL) + if (oipt->opaque_type == key) + return oipt; + + return NULL; +} + +static struct opaque_info_per_id * +register_opaque_info_per_id (struct opaque_info_per_type *oipt, + struct ospf_lsa *new) +{ + struct opaque_info_per_id *oipi; + + if ((oipi = XCALLOC (MTYPE_OPAQUE_INFO_PER_ID, + sizeof (struct opaque_info_per_id))) == NULL) + { + zlog_warn ("register_opaque_info_per_id: XMALLOC: %s", strerror (errno)); + goto out; + } + oipi->opaque_id = GET_OPAQUE_ID (ntohl (new->data->id.s_addr)); + oipi->t_opaque_lsa_self = NULL; + oipi->opqctl_type = oipt; + oipi->lsa = ospf_lsa_lock (new); + + listnode_add (oipt->id_list, oipi); + +out: + return oipi; +} + +static void +free_opaque_info_per_id (void *val) +{ + struct opaque_info_per_id *oipi = (struct opaque_info_per_id *) val; + + OSPF_TIMER_OFF (oipi->t_opaque_lsa_self); + if (oipi->lsa != NULL) + ospf_lsa_unlock (oipi->lsa); + XFREE (MTYPE_OPAQUE_INFO_PER_ID, oipi); + return; +} + +static struct opaque_info_per_id * +lookup_opaque_info_by_id (struct opaque_info_per_type *oipt, + struct ospf_lsa *lsa) +{ + listnode node; + struct opaque_info_per_id *oipi; + u_int32_t key = GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)); + + for (node = listhead (oipt->id_list); node; nextnode (node)) + if ((oipi = getdata (node)) != NULL) + if (oipi->opaque_id == key) + return oipi; + + return NULL; +} + +static struct opaque_info_per_id * +register_opaque_lsa (struct ospf_lsa *new) +{ + struct ospf_opaque_functab *functab; + struct opaque_info_per_type *oipt; + struct opaque_info_per_id *oipi = NULL; + + if ((functab = ospf_opaque_functab_lookup (new)) == NULL) + goto out; + + if ((oipt = lookup_opaque_info_by_type (new)) == NULL + && (oipt = register_opaque_info_per_type (functab, new)) == NULL) + goto out; + + if ((oipi = register_opaque_info_per_id (oipt, new)) == NULL) + goto out; + +out: + return oipi; +} + +/*------------------------------------------------------------------------* + * Followings are (vty) configuration functions for Opaque-LSAs handling. + *------------------------------------------------------------------------*/ + +DEFUN (capability_opaque, + capability_opaque_cmd, + "capability opaque", + "Enable specific OSPF feature\n" + "Opaque LSA\n") +{ + struct ospf *ospf = (struct ospf *) vty->index; + + /* Turn on the "master switch" of opaque-lsa capability. */ + if (!CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Opaque capability: OFF -> ON"); + + SET_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE); + ospf_renegotiate_optional_capabilities (ospf); + } + return CMD_SUCCESS; +} + +ALIAS (capability_opaque, + ospf_opaque_capable_cmd, + "ospf opaque-lsa", + "OSPF specific commands\n" + "Enable the Opaque-LSA capability (rfc2370)\n") + +DEFUN (no_capability_opaque, + no_capability_opaque_cmd, + "no capability opaque", + NO_STR + "Enable specific OSPF feature\n" + "Opaque LSA\n") +{ + struct ospf *ospf = (struct ospf *) vty->index; + + /* Turn off the "master switch" of opaque-lsa capability. */ + if (CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Opaque capability: ON -> OFF"); + + UNSET_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE); + ospf_renegotiate_optional_capabilities (ospf); + } + return CMD_SUCCESS; +} + +ALIAS (no_capability_opaque, + no_ospf_opaque_capable_cmd, + "no ospf opaque-lsa", + NO_STR + "OSPF specific commands\n" + "Disable the Opaque-LSA capability (rfc2370)\n") + +static void +ospf_opaque_register_vty (void) +{ + install_element (OSPF_NODE, &capability_opaque_cmd); + install_element (OSPF_NODE, &no_capability_opaque_cmd); + install_element (OSPF_NODE, &ospf_opaque_capable_cmd); + install_element (OSPF_NODE, &no_ospf_opaque_capable_cmd); + return; +} + +/*------------------------------------------------------------------------* + * Followings are collection of user-registered function callers. + *------------------------------------------------------------------------*/ + +static int +opaque_lsa_new_if_callback (list funclist, struct interface *ifp) +{ + listnode node; + struct ospf_opaque_functab *functab; + int rc = -1; + + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->new_if_hook != NULL) + if ((* functab->new_if_hook)(ifp) != 0) + goto out; + rc = 0; +out: + return rc; +} + +static int +opaque_lsa_del_if_callback (list funclist, struct interface *ifp) +{ + listnode node; + struct ospf_opaque_functab *functab; + int rc = -1; + + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->del_if_hook != NULL) + if ((* functab->del_if_hook)(ifp) != 0) + goto out; + rc = 0; +out: + return rc; +} + +static void +opaque_lsa_ism_change_callback (list funclist, + struct ospf_interface *oi, int old_status) +{ + listnode node; + struct ospf_opaque_functab *functab; + + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->ism_change_hook != NULL) + (* functab->ism_change_hook)(oi, old_status); + return; +} + +static void +opaque_lsa_nsm_change_callback (list funclist, + struct ospf_neighbor *nbr, int old_status) +{ + listnode node; + struct ospf_opaque_functab *functab; + + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->nsm_change_hook != NULL) + (* functab->nsm_change_hook)(nbr, old_status); + return; +} + +static void +opaque_lsa_config_write_router_callback (list funclist, struct vty *vty) +{ + listnode node; + struct ospf_opaque_functab *functab; + + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->config_write_router != NULL) + (* functab->config_write_router)(vty); + return; +} + +static void +opaque_lsa_config_write_if_callback (list funclist, + struct vty *vty, struct interface *ifp) +{ + listnode node; + struct ospf_opaque_functab *functab; + + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->config_write_if != NULL) + (* functab->config_write_if)(vty, ifp); + return; +} + +static void +opaque_lsa_config_write_debug_callback (list funclist, struct vty *vty) +{ + listnode node; + struct ospf_opaque_functab *functab; + + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->config_write_debug != NULL) + (* functab->config_write_debug)(vty); + return; +} + +static int +opaque_lsa_originate_callback (list funclist, void *lsa_type_dependent) +{ + listnode node; + struct ospf_opaque_functab *functab; + int rc = -1; + + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->lsa_originator != NULL) + if ((* functab->lsa_originator)(lsa_type_dependent) != 0) + goto out; + rc = 0; +out: + return rc; +} + +static int +new_lsa_callback (list funclist, struct ospf_lsa *lsa) +{ + listnode node; + struct ospf_opaque_functab *functab; + int rc = -1; + + /* This function handles ALL types of LSAs, not only opaque ones. */ + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->new_lsa_hook != NULL) + if ((* functab->new_lsa_hook)(lsa) != 0) + goto out; + rc = 0; +out: + return rc; +} + +static int +del_lsa_callback (list funclist, struct ospf_lsa *lsa) +{ + listnode node; + struct ospf_opaque_functab *functab; + int rc = -1; + + /* This function handles ALL types of LSAs, not only opaque ones. */ + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->del_lsa_hook != NULL) + if ((* functab->del_lsa_hook)(lsa) != 0) + goto out; + rc = 0; +out: + return rc; +} + +/*------------------------------------------------------------------------* + * Followings are glue functions to call Opaque-LSA specific processing. + *------------------------------------------------------------------------*/ + +int +ospf_opaque_new_if (struct interface *ifp) +{ + list funclist; + int rc = -1; + + funclist = ospf_opaque_type9_funclist; + if (opaque_lsa_new_if_callback (funclist, ifp) != 0) + goto out; + + funclist = ospf_opaque_type10_funclist; + if (opaque_lsa_new_if_callback (funclist, ifp) != 0) + goto out; + + funclist = ospf_opaque_type11_funclist; + if (opaque_lsa_new_if_callback (funclist, ifp) != 0) + goto out; + + rc = 0; +out: + return rc; +} + +int +ospf_opaque_del_if (struct interface *ifp) +{ + list funclist; + int rc = -1; + + funclist = ospf_opaque_type9_funclist; + if (opaque_lsa_del_if_callback (funclist, ifp) != 0) + goto out; + + funclist = ospf_opaque_type10_funclist; + if (opaque_lsa_del_if_callback (funclist, ifp) != 0) + goto out; + + funclist = ospf_opaque_type11_funclist; + if (opaque_lsa_del_if_callback (funclist, ifp) != 0) + goto out; + + rc = 0; +out: + return rc; +} + +void +ospf_opaque_ism_change (struct ospf_interface *oi, int old_status) +{ + list funclist; + + funclist = ospf_opaque_type9_funclist; + opaque_lsa_ism_change_callback (funclist, oi, old_status); + + funclist = ospf_opaque_type10_funclist; + opaque_lsa_ism_change_callback (funclist, oi, old_status); + + funclist = ospf_opaque_type11_funclist; + opaque_lsa_ism_change_callback (funclist, oi, old_status); + + return; +} + +void +ospf_opaque_nsm_change (struct ospf_neighbor *nbr, int old_state) +{ + struct ospf *top; + list funclist; + + if ((top = oi_to_top (nbr->oi)) == NULL) + goto out; + + if (old_state != NSM_Full && nbr->state == NSM_Full) + { + if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) + { + if (! CHECK_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Opaque-LSA: Now get operational!"); + + SET_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT); + } + + ospf_opaque_lsa_originate_schedule (nbr->oi, NULL); + } + } + else + if (old_state == NSM_Full && nbr->state != NSM_Full) + { +#ifdef NOTYET + /* + * If no more opaque-capable full-state neighbor remains in the + * flooding scope which corresponds to Opaque-LSA type, periodic + * LS flooding should be stopped. + */ +#endif /* NOTYET */ + ; + } + + funclist = ospf_opaque_type9_funclist; + opaque_lsa_nsm_change_callback (funclist, nbr, old_state); + + funclist = ospf_opaque_type10_funclist; + opaque_lsa_nsm_change_callback (funclist, nbr, old_state); + + funclist = ospf_opaque_type11_funclist; + opaque_lsa_nsm_change_callback (funclist, nbr, old_state); + +out: + return; +} + +void +ospf_opaque_config_write_router (struct vty *vty, struct ospf *ospf) +{ + list funclist; + + if (CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE)) + vty_out (vty, " capability opaque%s", VTY_NEWLINE); + + funclist = ospf_opaque_type9_funclist; + opaque_lsa_config_write_router_callback (funclist, vty); + + funclist = ospf_opaque_type10_funclist; + opaque_lsa_config_write_router_callback (funclist, vty); + + funclist = ospf_opaque_type11_funclist; + opaque_lsa_config_write_router_callback (funclist, vty); + + return; +} + +void +ospf_opaque_config_write_if (struct vty *vty, struct interface *ifp) +{ + list funclist; + + funclist = ospf_opaque_type9_funclist; + opaque_lsa_config_write_if_callback (funclist, vty, ifp); + + funclist = ospf_opaque_type10_funclist; + opaque_lsa_config_write_if_callback (funclist, vty, ifp); + + funclist = ospf_opaque_type11_funclist; + opaque_lsa_config_write_if_callback (funclist, vty, ifp); + + return; +} + +void +ospf_opaque_config_write_debug (struct vty *vty) +{ + list funclist; + + funclist = ospf_opaque_type9_funclist; + opaque_lsa_config_write_debug_callback (funclist, vty); + + funclist = ospf_opaque_type10_funclist; + opaque_lsa_config_write_debug_callback (funclist, vty); + + funclist = ospf_opaque_type11_funclist; + opaque_lsa_config_write_debug_callback (funclist, vty); + + return; +} + +void +show_opaque_info_detail (struct vty *vty, struct ospf_lsa *lsa) +{ + struct lsa_header *lsah = (struct lsa_header *) lsa->data; + u_int32_t lsid = ntohl (lsah->id.s_addr); + u_char opaque_type = GET_OPAQUE_TYPE (lsid); + u_int32_t opaque_id = GET_OPAQUE_ID (lsid); + struct ospf_opaque_functab *functab; + + /* Switch output functionality by vty address. */ + if (vty != NULL) + { + vty_out (vty, " Opaque-Type %u (%s)%s", opaque_type, ospf_opaque_type_name (opaque_type), VTY_NEWLINE); + vty_out (vty, " Opaque-ID 0x%x%s", opaque_id, VTY_NEWLINE); + + vty_out (vty, " Opaque-Info: %u octets of data%s%s", + ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE, + VALID_OPAQUE_INFO_LEN(lsah) ? "" : "(Invalid length?)", + VTY_NEWLINE); + } + else + { + zlog_info (" Opaque-Type %u (%s)", opaque_type, ospf_opaque_type_name (opaque_type)); + zlog_info (" Opaque-ID 0x%x", opaque_id); + + zlog_info (" Opaque-Info: %u octets of data%s", + ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE, + VALID_OPAQUE_INFO_LEN(lsah) ? "" : "(Invalid length?)"); + } + + /* Call individual output functions. */ + if ((functab = ospf_opaque_functab_lookup (lsa)) != NULL) + if (functab->show_opaque_info != NULL) + (* functab->show_opaque_info)(vty, lsa); + + return; +} + +void +ospf_opaque_lsa_dump (struct stream *s, u_int16_t length) +{ + struct ospf_lsa lsa; + + lsa.data = (struct lsa_header *) STREAM_PNT (s); + show_opaque_info_detail (NULL, &lsa); + return; +} + +static int +ospf_opaque_lsa_install_hook (struct ospf_lsa *lsa) +{ + list funclist; + int rc = -1; + + /* + * Some Opaque-LSA user may want to monitor every LSA installation + * into the LSDB, regardless with target LSA type. + */ + funclist = ospf_opaque_type9_funclist; + if (new_lsa_callback (funclist, lsa) != 0) + goto out; + + funclist = ospf_opaque_type10_funclist; + if (new_lsa_callback (funclist, lsa) != 0) + goto out; + + funclist = ospf_opaque_type11_funclist; + if (new_lsa_callback (funclist, lsa) != 0) + goto out; + + rc = 0; +out: + return rc; +} + +static int +ospf_opaque_lsa_delete_hook (struct ospf_lsa *lsa) +{ + list funclist; + int rc = -1; + + /* + * Some Opaque-LSA user may want to monitor every LSA deletion + * from the LSDB, regardless with target LSA type. + */ + funclist = ospf_opaque_type9_funclist; + if (del_lsa_callback (funclist, lsa) != 0) + goto out; + + funclist = ospf_opaque_type10_funclist; + if (del_lsa_callback (funclist, lsa) != 0) + goto out; + + funclist = ospf_opaque_type11_funclist; + if (del_lsa_callback (funclist, lsa) != 0) + goto out; + + rc = 0; +out: + return rc; +} + +/*------------------------------------------------------------------------* + * Followings are Opaque-LSA origination/refresh management functions. + *------------------------------------------------------------------------*/ + +static int ospf_opaque_type9_lsa_originate (struct thread *t); +static int ospf_opaque_type10_lsa_originate (struct thread *t); +static int ospf_opaque_type11_lsa_originate (struct thread *t); +static void ospf_opaque_lsa_reoriginate_resume (list listtop, void *arg); + +void +ospf_opaque_lsa_originate_schedule (struct ospf_interface *oi, int *delay0) +{ + struct ospf *top; + struct ospf_area *area; + listnode node; + struct opaque_info_per_type *oipt; + int delay = 0; + + if ((top = oi_to_top (oi)) == NULL || (area = oi->area) == NULL) + { + zlog_warn ("ospf_opaque_lsa_originate_schedule: Invalid argument?"); + goto out; + } + + /* It may not a right time to schedule origination now. */ + if (! CHECK_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_opaque_lsa_originate_schedule: Not operational."); + goto out; /* This is not an error. */ + } + if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_opaque_lsa_originate_schedule: Under blockade."); + goto out; /* This is not an error, too. */ + } + + if (delay0 != NULL) + delay = *delay0; + + /* + * There might be some entries that have been waiting for triggering + * of per opaque-type re-origination get resumed. + */ + ospf_opaque_lsa_reoriginate_resume ( oi->opaque_lsa_self, (void *) oi); + ospf_opaque_lsa_reoriginate_resume (area->opaque_lsa_self, (void *) area); + ospf_opaque_lsa_reoriginate_resume ( top->opaque_lsa_self, (void *) top); + + /* + * Now, schedule origination of all Opaque-LSAs per opaque-type. + */ + if (! list_isempty (ospf_opaque_type9_funclist) + && list_isempty (oi->opaque_lsa_self) + && oi->t_opaque_lsa_self == NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Schedule Type-9 Opaque-LSA origination in %d sec later.", delay); + oi->t_opaque_lsa_self = + thread_add_timer (master, ospf_opaque_type9_lsa_originate, oi, delay); + delay += OSPF_MIN_LS_INTERVAL; + } + + if (! list_isempty (ospf_opaque_type10_funclist) + && list_isempty (area->opaque_lsa_self) + && area->t_opaque_lsa_self == NULL) + { + /* + * One AREA may contain multiple OIs, but above 2nd and 3rd + * conditions prevent from scheduling the originate function + * again and again. + */ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Schedule Type-10 Opaque-LSA origination in %d sec later.", delay); + area->t_opaque_lsa_self = + thread_add_timer (master, ospf_opaque_type10_lsa_originate, + area, delay); + delay += OSPF_MIN_LS_INTERVAL; + } + + if (! list_isempty (ospf_opaque_type11_funclist) + && list_isempty (top->opaque_lsa_self) + && top->t_opaque_lsa_self == NULL) + { + /* + * One OSPF may contain multiple AREAs, but above 2nd and 3rd + * conditions prevent from scheduling the originate function + * again and again. + */ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Schedule Type-11 Opaque-LSA origination in %d sec later.", delay); + top->t_opaque_lsa_self = + thread_add_timer (master, ospf_opaque_type11_lsa_originate, + top, delay); + delay += OSPF_MIN_LS_INTERVAL; + } + + /* + * Following section treats a special situation that this node's + * opaque capability has changed as "ON -> OFF -> ON". + */ + if (! list_isempty (ospf_opaque_type9_funclist) + && ! list_isempty (oi->opaque_lsa_self)) + { + for (node = listhead (oi->opaque_lsa_self); node; nextnode (node)) + { + if ((oipt = getdata (node)) == NULL /* Something wrong? */ + || oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */ + || oipt->status == PROC_SUSPEND /* Cannot originate now. */ + || ! list_isempty (oipt->id_list)) /* Handler is already active. */ + continue; + + ospf_opaque_lsa_reoriginate_schedule ((void *) oi, + OSPF_OPAQUE_LINK_LSA, oipt->opaque_type); + } + } + + if (! list_isempty (ospf_opaque_type10_funclist) + && ! list_isempty (area->opaque_lsa_self)) + { + for (node = listhead (area->opaque_lsa_self); node; nextnode (node)) + { + if ((oipt = getdata (node)) == NULL /* Something wrong? */ + || oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */ + || oipt->status == PROC_SUSPEND /* Cannot originate now. */ + || ! list_isempty (oipt->id_list)) /* Handler is already active. */ + continue; + + ospf_opaque_lsa_reoriginate_schedule ((void *) area, + OSPF_OPAQUE_AREA_LSA, oipt->opaque_type); + } + } + + if (! list_isempty (ospf_opaque_type11_funclist) + && ! list_isempty (top->opaque_lsa_self)) + { + for (node = listhead (top->opaque_lsa_self); node; nextnode (node)) + { + if ((oipt = getdata (node)) == NULL /* Something wrong? */ + || oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */ + || oipt->status == PROC_SUSPEND /* Cannot originate now. */ + || ! list_isempty (oipt->id_list)) /* Handler is already active. */ + continue; + + ospf_opaque_lsa_reoriginate_schedule ((void *) top, + OSPF_OPAQUE_AS_LSA, oipt->opaque_type); + } + } + + if (delay0 != NULL) + *delay0 = delay; + +out: + return; +} + +static int +ospf_opaque_type9_lsa_originate (struct thread *t) +{ + struct ospf_interface *oi; + int rc; + + oi = THREAD_ARG (t); + oi->t_opaque_lsa_self = NULL; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Timer[Type9-LSA]: Originate Opaque-LSAs for OI %s", + IF_NAME (oi)); + + rc = opaque_lsa_originate_callback (ospf_opaque_type9_funclist, oi); + + return rc; +} + +static int +ospf_opaque_type10_lsa_originate (struct thread *t) +{ + struct ospf_area *area; + int rc; + + area = THREAD_ARG (t); + area->t_opaque_lsa_self = NULL; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Timer[Type10-LSA]: Originate Opaque-LSAs for Area %s", + inet_ntoa (area->area_id)); + + rc = opaque_lsa_originate_callback (ospf_opaque_type10_funclist, area); + + return rc; +} + +static int +ospf_opaque_type11_lsa_originate (struct thread *t) +{ + struct ospf *top; + int rc; + + top = THREAD_ARG (t); + top->t_opaque_lsa_self = NULL; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Timer[Type11-LSA]: Originate AS-External Opaque-LSAs"); + + rc = opaque_lsa_originate_callback (ospf_opaque_type11_funclist, top); + + return rc; +} + +static void +ospf_opaque_lsa_reoriginate_resume (list listtop, void *arg) +{ + listnode node; + struct opaque_info_per_type *oipt; + struct ospf_opaque_functab *functab; + + if (listtop == NULL) + goto out; + + /* + * Pickup oipt entries those which in SUSPEND status, and give + * them a chance to start re-origination now. + */ + for (node = listhead (listtop); node; nextnode (node)) + { + if ((oipt = getdata (node)) == NULL + || oipt->status != PROC_SUSPEND) + continue; + + oipt->status = PROC_NORMAL; + + if ((functab = oipt->functab) == NULL + || functab->lsa_originator == NULL) + continue; + + if ((* functab->lsa_originator)(arg) != 0) + { + zlog_warn ("ospf_opaque_lsa_reoriginate_resume: Failed (opaque-type=%u)", oipt->opaque_type); + continue; + } + } + +out: + return; +} + +struct ospf_lsa * +ospf_opaque_lsa_install (struct ospf_lsa *lsa, int rt_recalc) +{ + struct ospf_lsa *new = NULL; + struct opaque_info_per_type *oipt; + struct opaque_info_per_id *oipi; + struct ospf *top; + + /* Don't take "rt_recalc" into consideration for now. *//* XXX */ + + if (! IS_LSA_SELF (lsa)) + { + new = lsa; /* Don't touch this LSA. */ + goto out; + } + + if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) + zlog_info ("Install Type-%u Opaque-LSA: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); + + /* Replace the existing lsa with the new one. */ + if ((oipt = lookup_opaque_info_by_type (lsa)) != NULL + && (oipi = lookup_opaque_info_by_id (oipt, lsa)) != NULL) + { + ospf_lsa_unlock (oipi->lsa); + oipi->lsa = ospf_lsa_lock (lsa); + } + /* Register the new lsa entry and get its control info. */ + else + if ((oipi = register_opaque_lsa (lsa)) == NULL) + { + zlog_warn ("ospf_opaque_lsa_install: register_opaque_lsa() ?"); + goto out; + } + + /* + * Make use of a common mechanism (ospf_lsa_refresh_walker) + * for periodic refresh of self-originated Opaque-LSAs. + */ + switch (lsa->data->type) + { + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + if (lsa->area == NULL || (top = lsa->area->top) == NULL) + { + /* Above conditions must have passed. */ + zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?"); + goto out; + } + break; + case OSPF_OPAQUE_AS_LSA: + top = ospf_top; + if (lsa->area != NULL && (top = lsa->area->top) == NULL) + { + /* Above conditions must have passed. */ + zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?"); + goto out; + } + break; + default: + zlog_warn ("ospf_opaque_lsa_install: Unexpected LSA-type(%u)", lsa->data->type); + goto out; + } + + ospf_refresher_register_lsa (top, lsa); + new = lsa; + +out: + return new; +} + +void +ospf_opaque_lsa_refresh (struct ospf_lsa *lsa) +{ + struct ospf_opaque_functab *functab; + + if ((functab = ospf_opaque_functab_lookup (lsa)) == NULL + || functab->lsa_refresher == NULL) + { + /* + * Though this LSA seems to have originated on this node, the + * handling module for this "lsa-type and opaque-type" was + * already deleted sometime ago. + * Anyway, this node still has a responsibility to flush this + * LSA from the routing domain. + */ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type%d:%s]: Flush stray Opaque-LSA", lsa->data->type, inet_ntoa (lsa->data->id)); + + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); + ospf_lsa_maxage (lsa); + } + else + (* functab->lsa_refresher)(lsa); + + return; +} + +/*------------------------------------------------------------------------* + * Followings are re-origination/refresh/flush operations of Opaque-LSAs, + * triggered by external interventions (vty session, signaling, etc). + *------------------------------------------------------------------------*/ + +#define OSPF_OPAQUE_TIMER_ON(T,F,L,V) \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), (L), (V)) + +static struct ospf_lsa *pseudo_lsa (struct ospf_interface *oi, struct ospf_area *area, u_char lsa_type, u_char opaque_type); +static int ospf_opaque_type9_lsa_reoriginate_timer (struct thread *t); +static int ospf_opaque_type10_lsa_reoriginate_timer (struct thread *t); +static int ospf_opaque_type11_lsa_reoriginate_timer (struct thread *t); +static int ospf_opaque_lsa_refresh_timer (struct thread *t); + +void +ospf_opaque_lsa_reoriginate_schedule (void *lsa_type_dependent, + u_char lsa_type, u_char opaque_type) +{ + struct ospf *top; + struct ospf_area dummy, *area = NULL; + struct ospf_interface *oi = NULL; + + struct ospf_lsa *lsa; + struct opaque_info_per_type *oipt; + int (* func)(struct thread *t) = NULL; + int delay; + + switch (lsa_type) + { + case OSPF_OPAQUE_LINK_LSA: + if ((oi = (struct ospf_interface *) lsa_type_dependent) == NULL) + { + zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Type-9 Opaque-LSA: Invalid parameter?"); + goto out; + } + if ((top = oi_to_top (oi)) == NULL) + { + zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: OI(%s) -> TOP?", IF_NAME (oi)); + goto out; + } + if (! list_isempty (ospf_opaque_type9_funclist) + && list_isempty (oi->opaque_lsa_self) + && oi->t_opaque_lsa_self != NULL) + { + zlog_warn ("Type-9 Opaque-LSA (opaque_type=%u): Common origination for OI(%s) has already started", opaque_type, IF_NAME (oi)); + goto out; + } + func = ospf_opaque_type9_lsa_reoriginate_timer; + break; + case OSPF_OPAQUE_AREA_LSA: + if ((area = (struct ospf_area *) lsa_type_dependent) == NULL) + { + zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Type-10 Opaque-LSA: Invalid parameter?"); + goto out; + } + if ((top = area->top) == NULL) + { + zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: AREA(%s) -> TOP?", inet_ntoa (area->area_id)); + goto out; + } + if (! list_isempty (ospf_opaque_type10_funclist) + && list_isempty (area->opaque_lsa_self) + && area->t_opaque_lsa_self != NULL) + { + zlog_warn ("Type-10 Opaque-LSA (opaque_type=%u): Common origination for AREA(%s) has already started", opaque_type, inet_ntoa (area->area_id)); + goto out; + } + func = ospf_opaque_type10_lsa_reoriginate_timer; + break; + case OSPF_OPAQUE_AS_LSA: + if ((top = (struct ospf *) lsa_type_dependent) == NULL) + { + zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Type-11 Opaque-LSA: Invalid parameter?"); + goto out; + } + if (! list_isempty (ospf_opaque_type11_funclist) + && list_isempty (top->opaque_lsa_self) + && top->t_opaque_lsa_self != NULL) + { + zlog_warn ("Type-11 Opaque-LSA (opaque_type=%u): Common origination has already started", opaque_type); + goto out; + } + + /* Fake "area" to pass "ospf" to a lookup function later. */ + dummy.top = top; + area = &dummy; + + func = ospf_opaque_type11_lsa_reoriginate_timer; + break; + default: + zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Unexpected LSA-type(%u)", lsa_type); + goto out; + } + + /* It may not a right time to schedule reorigination now. */ + if (! CHECK_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_opaque_lsa_reoriginate_schedule: Not operational."); + goto out; /* This is not an error. */ + } + if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_opaque_lsa_reoriginate_schedule: Under blockade."); + goto out; /* This is not an error, too. */ + } + + /* Generate a dummy lsa to be passed for a lookup function. */ + lsa = pseudo_lsa (oi, area, lsa_type, opaque_type); + + if ((oipt = lookup_opaque_info_by_type (lsa)) == NULL) + { + struct ospf_opaque_functab *functab; + if ((functab = ospf_opaque_functab_lookup (lsa)) == NULL) + { + zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: No associated function?: lsa_type(%u), opaque_type(%u)", lsa_type, opaque_type); + goto out; + } + if ((oipt = register_opaque_info_per_type (functab, lsa)) == NULL) + { + zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Cannot get a control info?: lsa_type(%u), opaque_type(%u)", lsa_type, opaque_type); + goto out; + } + } + + if (oipt->t_opaque_lsa_self != NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Type-%u Opaque-LSA has already scheduled to RE-ORIGINATE: [opaque-type=%u]", lsa_type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr))); + goto out; + } + + /* + * Different from initial origination time, in which various conditions + * (opaque capability, neighbor status etc) are assured by caller of + * the originating function "ospf_opaque_lsa_originate_schedule ()", + * it is highly possible that these conditions might not be satisfied + * at the time of re-origination function is to be called. + */ + delay = OSPF_MIN_LS_INTERVAL; /* XXX */ + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Schedule Type-%u Opaque-LSA to RE-ORIGINATE in %d sec later: [opaque-type=%u]", lsa_type, delay, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr))); + + OSPF_OPAQUE_TIMER_ON (oipt->t_opaque_lsa_self, func, oipt, delay); + +out: + return; +} + +static struct ospf_lsa * +pseudo_lsa (struct ospf_interface *oi, struct ospf_area *area, + u_char lsa_type, u_char opaque_type) +{ + static struct ospf_lsa lsa = { 0 }; + static struct lsa_header lsah = { 0 }; + u_int32_t tmp; + + lsa.oi = oi; + lsa.area = area; + lsa.data = &lsah; + + lsah.type = lsa_type; + tmp = SET_OPAQUE_LSID (opaque_type, 0); /* Opaque-ID is unused here. */ + lsah.id.s_addr = htonl (tmp); + + return &lsa; +} + +static int +ospf_opaque_type9_lsa_reoriginate_timer (struct thread *t) +{ + struct opaque_info_per_type *oipt; + struct ospf_opaque_functab *functab; + struct ospf *top; + struct ospf_interface *oi; + int rc = -1; + + oipt = THREAD_ARG (t); + oipt->t_opaque_lsa_self = NULL; + + if ((functab = oipt->functab) == NULL + || functab->lsa_originator == NULL) + { + zlog_warn ("ospf_opaque_type9_lsa_reoriginate_timer: No associated function?"); + goto out; + } + + oi = (struct ospf_interface *) oipt->owner; + if ((top = oi_to_top (oi)) == NULL) + { + zlog_warn ("ospf_opaque_type9_lsa_reoriginate_timer: Something wrong?"); + goto out; + } + + if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE) + || ! ospf_if_is_enable (oi) + || ospf_opaque_capable_nbr_count (oi->nbrs, NSM_Full) == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Suspend re-origination of Type-9 Opaque-LSAs (opaque-type=%u) for a while...", oipt->opaque_type); + + oipt->status = PROC_SUSPEND; + rc = 0; + goto out; + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Timer[Type9-LSA]: Re-originate Opaque-LSAs (opaque-type=%u) for OI (%s)", oipt->opaque_type, IF_NAME (oi)); + + rc = (* functab->lsa_originator)(oi); +out: + return rc; +} + +static int +ospf_opaque_type10_lsa_reoriginate_timer (struct thread *t) +{ + struct opaque_info_per_type *oipt; + struct ospf_opaque_functab *functab; + listnode node; + struct ospf *top; + struct ospf_area *area; + struct ospf_interface *oi; + int n, rc = -1; + + oipt = THREAD_ARG (t); + oipt->t_opaque_lsa_self = NULL; + + if ((functab = oipt->functab) == NULL + || functab->lsa_originator == NULL) + { + zlog_warn ("ospf_opaque_type10_lsa_reoriginate_timer: No associated function?"); + goto out; + } + + area = (struct ospf_area *) oipt->owner; + if (area == NULL || (top = area->top) == NULL) + { + zlog_warn ("ospf_opaque_type10_lsa_reoriginate_timer: Something wrong?"); + goto out; + } + + /* There must be at least one "opaque-capable, full-state" neighbor. */ + n = 0; + for (node = listhead (area->oiflist); node; nextnode (node)) + { + if ((oi = getdata (node)) == NULL) + continue; + if ((n = ospf_opaque_capable_nbr_count (oi->nbrs, NSM_Full)) > 0) + break; + } + + if (n == 0 || ! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Suspend re-origination of Type-10 Opaque-LSAs (opaque-type=%u) for a while...", oipt->opaque_type); + + oipt->status = PROC_SUSPEND; + rc = 0; + goto out; + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Timer[Type10-LSA]: Re-originate Opaque-LSAs (opaque-type=%u) for Area %s", oipt->opaque_type, inet_ntoa (area->area_id)); + + rc = (* functab->lsa_originator)(area); +out: + return rc; +} + +static int +ospf_opaque_type11_lsa_reoriginate_timer (struct thread *t) +{ + struct opaque_info_per_type *oipt; + struct ospf_opaque_functab *functab; + struct ospf *top; + int rc = -1; + + oipt = THREAD_ARG (t); + oipt->t_opaque_lsa_self = NULL; + + if ((functab = oipt->functab) == NULL + || functab->lsa_originator == NULL) + { + zlog_warn ("ospf_opaque_type11_lsa_reoriginate_timer: No associated function?"); + goto out; + } + + if ((top = (struct ospf *) oipt->owner) == NULL) + { + zlog_warn ("ospf_opaque_type11_lsa_reoriginate_timer: Something wrong?"); + goto out; + } + + if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Suspend re-origination of Type-11 Opaque-LSAs (opaque-type=%u) for a while...", oipt->opaque_type); + + oipt->status = PROC_SUSPEND; + rc = 0; + goto out; + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Timer[Type11-LSA]: Re-originate Opaque-LSAs (opaque-type=%u).", oipt->opaque_type); + + rc = (* functab->lsa_originator)(top); +out: + return rc; +} + +extern int ospf_lsa_refresh_delay (struct ospf_lsa *); /* ospf_lsa.c */ + +void +ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa0) +{ + struct opaque_info_per_type *oipt; + struct opaque_info_per_id *oipi; + struct ospf_lsa *lsa; + int delay; + + if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL + || (oipi = lookup_opaque_info_by_id (oipt, lsa0)) == NULL) + { + zlog_warn ("ospf_opaque_lsa_refresh_schedule: Invalid parameter?"); + goto out; + } + + /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */ + if ((lsa = oipi->lsa) == NULL) + { + zlog_warn ("ospf_opaque_lsa_refresh_schedule: Something wrong?"); + goto out; + } + + if (oipi->t_opaque_lsa_self != NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Type-%u Opaque-LSA has already scheduled to REFRESH: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); + goto out; + } + + /* Delete this lsa from neighbor retransmit-list. */ + switch (lsa->data->type) + { + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + ospf_ls_retransmit_delete_nbr_all (lsa->area, lsa); + break; + case OSPF_OPAQUE_AS_LSA: + ospf_ls_retransmit_delete_nbr_all (NULL, lsa); + break; + default: + zlog_warn ("ospf_opaque_lsa_refresh_schedule: Unexpected LSA-type(%u)", lsa->data->type); + goto out; + } + + delay = ospf_lsa_refresh_delay (lsa); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Schedule Type-%u Opaque-LSA to REFRESH in %d sec later: [opaque-type=%u, opaque-id=%x]", lsa->data->type, delay, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); + + OSPF_OPAQUE_TIMER_ON (oipi->t_opaque_lsa_self, + ospf_opaque_lsa_refresh_timer, oipi, delay); +out: + return; +} + +static int +ospf_opaque_lsa_refresh_timer (struct thread *t) +{ + struct opaque_info_per_id *oipi; + struct ospf_opaque_functab *functab; + struct ospf_lsa *lsa; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Timer[Opaque-LSA]: (Opaque-LSA Refresh expire)"); + + oipi = THREAD_ARG (t); + oipi->t_opaque_lsa_self = NULL; + + if ((lsa = oipi->lsa) != NULL) + if ((functab = oipi->opqctl_type->functab) != NULL) + if (functab->lsa_refresher != NULL) + (* functab->lsa_refresher)(lsa); + + return 0; +} + +void +ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa0) +{ + struct opaque_info_per_type *oipt; + struct opaque_info_per_id *oipi; + struct ospf_lsa *lsa; + + if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL + || (oipi = lookup_opaque_info_by_id (oipt, lsa0)) == NULL) + { + zlog_warn ("ospf_opaque_lsa_flush_schedule: Invalid parameter?"); + goto out; + } + + /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */ + if ((lsa = oipi->lsa) == NULL) + { + zlog_warn ("ospf_opaque_lsa_flush_schedule: Something wrong?"); + goto out; + } + + /* Delete this lsa from neighbor retransmit-list. */ + switch (lsa->data->type) + { + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + ospf_ls_retransmit_delete_nbr_all (lsa->area, lsa); + break; + case OSPF_OPAQUE_AS_LSA: + ospf_ls_retransmit_delete_nbr_all (NULL, lsa); + break; + default: + zlog_warn ("ospf_opaque_lsa_flush_schedule: Unexpected LSA-type(%u)", lsa->data->type); + goto out; + } + + /* Dequeue listnode entry from the list. */ + listnode_delete (oipt->id_list, oipi); + + /* Avoid misjudgement in the next lookup. */ + if (listcount (oipt->id_list) == 0) + oipt->id_list->head = oipt->id_list->tail = NULL; + + /* Disassociate internal control information with the given lsa. */ + oipi->lsa = NULL; + free_opaque_info_per_id ((void *) oipi); + + /* Force given lsa's age to MaxAge. */ + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Schedule Type-%u Opaque-LSA to FLUSH: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); + + /* This lsa will be flushed and removed eventually. */ + ospf_lsa_maxage (lsa); + +out: + return; +} + +/*------------------------------------------------------------------------* + * Followings are control functions to block origination after restart. + *------------------------------------------------------------------------*/ + +static void ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs, struct ospf_neighbor *inbr, struct ospf_lsa *lsa); +static void ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi); +static void ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area); +static void ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top); +static unsigned long ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type); + +void +ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, list lsas) +{ + struct ospf *top; + struct ospf_area *area; + struct ospf_interface *oi; + listnode node1, node2; + struct ospf_lsa *lsa; + + if ((top = oi_to_top (nbr->oi)) == NULL) + goto out; + + /* + * If an instance of self-originated Opaque-LSA is found in the given + * LSA list, and it is not installed to LSDB yet, exclude it from the + * list "nbr->ls_req". In this way, it is assured that an LSReq message, + * which might be sent in the process of flooding, will not request for + * the LSA to be flushed immediately; otherwise, depending on timing, + * an LSUpd message will carry instances of target LSAs with MaxAge, + * while other LSUpd message might carry old LSA instances (non-MaxAge). + * Obviously, the latter would trigger miserable situations that repeat + * installation and removal of unwanted LSAs indefinitely. + */ + for (node1 = listhead (lsas); node1; nextnode (node1)) + { + if ((lsa = getdata (node1)) == NULL) + continue; + + /* Filter out unwanted LSAs. */ + if (! IS_OPAQUE_LSA (lsa->data->type)) + continue; + if (! IPV4_ADDR_SAME (&lsa->data->adv_router, &top->router_id)) + continue; + + /* + * Don't touch an LSA which has MaxAge; two possible cases. + * + * 1) This LSA has originally flushed by myself (received LSUpd + * message's router-id is equal to my router-id), and flooded + * back by an opaque-capable router. + * + * 2) This LSA has expired in an opaque-capable router and thus + * flushed by the router. + */ + if (IS_LSA_MAXAGE (lsa)) + continue; + + /* If the LSA has installed in the LSDB, nothing to do here. */ + if (ospf_lsa_lookup_by_header (nbr->oi->area, lsa->data) != NULL) + continue; + + /* Ok, here we go. */ + switch (lsa->data->type) + { + case OSPF_OPAQUE_LINK_LSA: + oi = nbr->oi; + ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa); + break; + case OSPF_OPAQUE_AREA_LSA: + area = nbr->oi->area; + for (node2 = listhead (area->oiflist); node2; nextnode (node2)) + { + if ((oi = getdata (node2)) == NULL) + continue; + ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa); + } + break; + case OSPF_OPAQUE_AS_LSA: + for (node2 = listhead (top->oiflist); node2; nextnode (node2)) + { + if ((oi = getdata (node2)) == NULL) + continue; + ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa); + } + break; + default: + break; + } + } + +out: + return; +} + +static void +ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs, + struct ospf_neighbor *inbr, + struct ospf_lsa *lsa) +{ + struct route_node *rn; + struct ospf_neighbor *onbr; + struct ospf_lsa *ls_req; + + for (rn = route_top (nbrs); rn; rn = route_next (rn)) + { + if ((onbr = rn->info) == NULL) + continue; + if (onbr == inbr) + continue; + if ((ls_req = ospf_ls_request_lookup (onbr, lsa)) == NULL) + continue; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[%s]: Exclude this entry from LSReq to send.", dump_lsa_key (lsa)); + + ospf_ls_request_delete (onbr, ls_req); +/* ospf_check_nbr_loading (onbr);*//* XXX */ + } + + return; +} + +void +ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, list lsas) +{ + struct ospf *top; + listnode node, next; + struct ospf_lsa *lsa; + u_char before; + + if ((top = oi_to_top (nbr->oi)) == NULL) + goto out; + + before = IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque); + + for (node = listhead (lsas); node; node = next) + { + next = node->next; + + if ((lsa = getdata (node)) == NULL) + continue; + + listnode_delete (lsas, lsa); + + /* + * Since these LSA entries are not yet installed into corresponding + * LSDB, just flush them without calling ospf_ls_maxage() afterward. + */ + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); + switch (lsa->data->type) + { + case OSPF_OPAQUE_LINK_LSA: + SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT); + ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa); + break; + case OSPF_OPAQUE_AREA_LSA: + SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT); + ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa); + break; + case OSPF_OPAQUE_AS_LSA: + SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT); + ospf_flood_through_as (NULL/*inbr*/, lsa); + break; + default: + zlog_warn ("ospf_opaque_self_originated_lsa_received: Unexpected LSA-type(%u)", lsa->data->type); + goto out; + } + + ospf_lsa_discard (lsa); /* List "lsas" will be deleted by caller. */ + } + + if (before == 0 && IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Block Opaque-LSA origination: OFF -> ON"); + } + +out: + return; +} + +void +ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, list acks) +{ + struct ospf *top; + listnode node; + struct ospf_lsa *lsa; + char type9_lsa_rcv = 0, type10_lsa_rcv = 0, type11_lsa_rcv = 0; + + if ((top = oi_to_top (nbr->oi)) == NULL) + goto out; + + for (node = listhead (acks); node; nextnode (node)) + { + if ((lsa = getdata (node)) == NULL) + continue; + + switch (lsa->data->type) + { + case OSPF_OPAQUE_LINK_LSA: + type9_lsa_rcv = 1; + /* Callback function... */ + break; + case OSPF_OPAQUE_AREA_LSA: + type10_lsa_rcv = 1; + /* Callback function... */ + break; + case OSPF_OPAQUE_AS_LSA: + type11_lsa_rcv = 1; + /* Callback function... */ + break; + default: + zlog_warn ("ospf_opaque_ls_ack_received: Unexpected LSA-type(%u)", lsa->data->type); + goto out; + } + } + + if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) + { + int delay; + struct ospf_interface *oi; + + if (type9_lsa_rcv + && CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT)) + ospf_opaque_type9_lsa_rxmt_nbr_check (nbr->oi); + + if (type10_lsa_rcv + && CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT)) + ospf_opaque_type10_lsa_rxmt_nbr_check (nbr->oi->area); + + if (type11_lsa_rcv + && CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT)) + ospf_opaque_type11_lsa_rxmt_nbr_check (top); + + if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) + goto out; /* Blocking still in progress. */ + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Block Opaque-LSA origination: ON -> OFF"); + + if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE)) + goto out; /* Opaque capability condition must have changed. */ + + /* Ok, let's start origination of Opaque-LSAs. */ + delay = OSPF_MIN_LS_INTERVAL; + for (node = listhead (top->oiflist); node; nextnode (node)) + { + if ((oi = getdata (node)) == NULL) + continue; + + if (! ospf_if_is_enable (oi) + || ospf_opaque_capable_nbr_count (oi->nbrs, NSM_Full) == 0) + continue; + + ospf_opaque_lsa_originate_schedule (oi, &delay); + } + } + +out: + return; +} + +static void +ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi) +{ + unsigned long n; + + n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_LINK_LSA); + if (n == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Self-originated type-9 Opaque-LSAs: OI(%s): Flush completed", IF_NAME (oi)); + + UNSET_FLAG (oi->area->top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT); + } + return; +} + +static void +ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area) +{ + listnode node; + struct ospf_interface *oi; + unsigned long n = 0; + + for (node = listhead (area->oiflist); node; nextnode (node)) + { + if ((oi = getdata (node)) == NULL) + continue; + + if (area->area_id.s_addr != OSPF_AREA_BACKBONE + && oi->type == OSPF_IFTYPE_VIRTUALLINK) + continue; + + n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_AREA_LSA); + if (n > 0) + break; + } + + if (n == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Self-originated type-10 Opaque-LSAs: AREA(%s): Flush completed", inet_ntoa (area->area_id)); + + UNSET_FLAG (area->top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT); + } + + return; +} + +static void +ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top) +{ + listnode node; + struct ospf_interface *oi; + unsigned long n = 0; + + for (node = listhead (top->oiflist); node; nextnode (node)) + { + if ((oi = getdata (node)) == NULL) + continue; + + switch (oi->type) + { + case OSPF_IFTYPE_VIRTUALLINK: + continue; + default: + break; + } + + n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_AS_LSA); + if (n > 0) + goto out; + } + + if (n == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Self-originated type-11 Opaque-LSAs: Flush completed"); + + UNSET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT); + } + +out: + return; +} + +static unsigned long +ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type) +{ + struct route_node *rn; + struct ospf_neighbor *nbr; + struct ospf *top; + unsigned long n = 0; + + for (rn = route_top (nbrs); rn; rn = route_next (rn)) + { + if ((nbr = rn->info) == NULL) + continue; + if ((top = oi_to_top (nbr->oi)) == NULL) + continue; + if (IPV4_ADDR_SAME (&nbr->router_id, &top->router_id)) + continue; + n += ospf_ls_retransmit_count_self (nbr, lsa_type); + } + + return n; +} + +/*------------------------------------------------------------------------* + * Followings are util functions; probably be used by Opaque-LSAs only... + *------------------------------------------------------------------------*/ + +void +htonf (float *src, float *dst) +{ + u_int32_t lu1, lu2; + + memcpy (&lu1, src, sizeof (u_int32_t)); + lu2 = htonl (lu1); + memcpy (dst, &lu2, sizeof (u_int32_t)); + return; +} + +void +ntohf (float *src, float *dst) +{ + u_int32_t lu1, lu2; + + memcpy (&lu1, src, sizeof (u_int32_t)); + lu2 = ntohl (lu1); + memcpy (dst, &lu2, sizeof (u_int32_t)); + return; +} + +struct ospf * +oi_to_top (struct ospf_interface *oi) +{ + struct ospf *top = NULL; + struct ospf_area *area; + + if (oi == NULL || (area = oi->area) == NULL || (top = area->top) == NULL) + zlog_warn ("Broken relationship for \"OI -> AREA -> OSPF\"?"); + + return top; +} + +#endif /* HAVE_OPAQUE_LSA */ diff --git a/ospfd/ospf_opaque.h b/ospfd/ospf_opaque.h new file mode 100644 index 00000000..9aa08e5c --- /dev/null +++ b/ospfd/ospf_opaque.h @@ -0,0 +1,155 @@ +/* + * This is an implementation of rfc2370. + * Copyright (C) 2001 KDD R&D Laboratories, Inc. + * http://www.kddlabs.co.jp/ + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_OPAQUE_H +#define _ZEBRA_OSPF_OPAQUE_H + +#define IS_OPAQUE_LSA(type) \ + ((type) == OSPF_OPAQUE_LINK_LSA || \ + (type) == OSPF_OPAQUE_AREA_LSA || \ + (type) == OSPF_OPAQUE_AS_LSA) + +/* + * Usage of Opaque-LSA administrative flags in "struct ospf". + * + * 7 6 5 4 3 2 1 0 + * +---+---+---+---+---+---+---+---+ + * |///|///|///|///|B11|B10|B09| O | + * +---+---+---+---+---+---+---+---+ + * |<--------->| A + * | +--- Operation status (operational = 1) + * +----------- Blocking status for each LSA type + */ + +#define IS_OPAQUE_LSA_ORIGINATION_BLOCKED(V) \ + CHECK_FLAG((V), (OPAQUE_BLOCK_TYPE_09_LSA_BIT | \ + OPAQUE_BLOCK_TYPE_10_LSA_BIT | \ + OPAQUE_BLOCK_TYPE_11_LSA_BIT)) + +/* + * Opaque LSA's link state ID is redefined as follows. + * + * 24 16 8 0 + * +--------+--------+--------+--------+ + * |tttttttt|........|........|........| + * +--------+--------+--------+--------+ + * |<-Type->|<------- Opaque ID ------>| + */ +#define LSID_OPAQUE_TYPE_MASK 0xff000000 /* 8 bits */ +#define LSID_OPAQUE_ID_MASK 0x00ffffff /* 24 bits */ + +#define GET_OPAQUE_TYPE(lsid) \ + (((u_int32_t)(lsid) & LSID_OPAQUE_TYPE_MASK) >> 24) + +#define GET_OPAQUE_ID(lsid) \ + ((u_int32_t)(lsid) & LSID_OPAQUE_ID_MASK) + +#define SET_OPAQUE_LSID(type, id) \ + ((((type) << 24) & LSID_OPAQUE_TYPE_MASK) \ + | ((id) & LSID_OPAQUE_ID_MASK)) + +/* + * Opaque LSA types will be assigned by IANA. + * + */ +#define OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA 1 +#define OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC 2 +#define OPAQUE_TYPE_GRACE_LSA 3 + +/* Followings types are proposed in internet-draft documents. */ +#define OPAQUE_TYPE_8021_QOSPF 129 +#define OPAQUE_TYPE_SECONDARY_NEIGHBOR_DISCOVERY 224 +#define OPAQUE_TYPE_FLOODGATE 225 + +/* Ugly hack to make use of an unallocated value for wildcard matching! */ +#define OPAQUE_TYPE_WILDCARD 0 + +#define OPAQUE_TYPE_RANGE_UNASSIGNED(type) \ + ( 4 <= (type) && (type) <= 127) + +#define OPAQUE_TYPE_RANGE_RESERVED(type) \ + (127 < (type) && (type) <= 255) + +#define VALID_OPAQUE_INFO_LEN(lsahdr) \ + ((ntohs((lsahdr)->length) >= sizeof (struct lsa_header)) && \ + ((ntohs((lsahdr)->length) % sizeof (u_int32_t)) == 0)) + +/* Prototypes. */ +struct vty; +struct stream; + +extern void ospf_opaque_init (void); +extern void ospf_opaque_term (void); +extern int ospf_opaque_type9_lsa_init (struct ospf_interface *oi); +extern void ospf_opaque_type9_lsa_term (struct ospf_interface *oi); +extern int ospf_opaque_type10_lsa_init (struct ospf_area *area); +extern void ospf_opaque_type10_lsa_term (struct ospf_area *area); +extern int ospf_opaque_type11_lsa_init (struct ospf *ospf); +extern void ospf_opaque_type11_lsa_term (struct ospf *ospf); + +extern int +ospf_register_opaque_functab ( + u_char lsa_type, + u_char opaque_type, + int (* new_if_hook)(struct interface *ifp), + int (* del_if_hook)(struct interface *ifp), + void (* ism_change_hook)(struct ospf_interface *oi, int old_status), + void (* nsm_change_hook)(struct ospf_neighbor *nbr, int old_status), + void (* config_write_router)(struct vty *vty), + void (* config_write_if )(struct vty *vty, struct interface *ifp), + void (* config_write_debug )(struct vty *vty), + void (* show_opaque_info )(struct vty *vty, struct ospf_lsa *lsa), + int (* lsa_originator)(void *arg), + void (* lsa_refresher )(struct ospf_lsa *lsa), + int (* new_lsa_hook)(struct ospf_lsa *lsa), + int (* del_lsa_hook)(struct ospf_lsa *lsa) +); +extern void ospf_delete_opaque_functab (u_char lsa_type, u_char opaque_type); + +extern int ospf_opaque_new_if (struct interface *ifp); +extern int ospf_opaque_del_if (struct interface *ifp); +extern void ospf_opaque_ism_change (struct ospf_interface *oi, int old_status); +extern void ospf_opaque_nsm_change (struct ospf_neighbor *nbr, int old_status); +extern void ospf_opaque_config_write_router (struct vty *vty, struct ospf *); +extern void ospf_opaque_config_write_if (struct vty *vty, struct interface *ifp); +extern void ospf_opaque_config_write_debug (struct vty *vty); +extern void show_opaque_info_detail (struct vty *vty, struct ospf_lsa *lsa); +extern void ospf_opaque_lsa_dump (struct stream *s, u_int16_t length); + +extern void ospf_opaque_lsa_originate_schedule (struct ospf_interface *oi, int *init_delay); +extern struct ospf_lsa *ospf_opaque_lsa_install (struct ospf_lsa *new, int rt_recalc); +extern void ospf_opaque_lsa_refresh (struct ospf_lsa *lsa); + +extern void ospf_opaque_lsa_reoriginate_schedule (void *lsa_type_dependent, u_char lsa_type, u_char opaque_type); +extern void ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa); +extern void ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa); + +extern void ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, list lsas); +extern void ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, list lsas); +extern void ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, list acks); + +extern void htonf (float *src, float *dst); +extern void ntohf (float *src, float *dst); +extern struct ospf *oi_to_top (struct ospf_interface *oi); + +#endif /* _ZEBRA_OSPF_OPAQUE_H */ diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c new file mode 100644 index 00000000..2156ce33 --- /dev/null +++ b/ospfd/ospf_packet.c @@ -0,0 +1,3243 @@ +/* + * OSPF Sending and Receiving OSPF Packets. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "thread.h" +#include "memory.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "sockunion.h" +#include "stream.h" +#include "log.h" +#include "md5-gnu.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_network.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_dump.h" + +static void ospf_ls_ack_send_list (struct ospf_interface *, list, + struct in_addr); + +/* Packet Type String. */ +char *ospf_packet_type_str[] = +{ + "unknown", + "Hello", + "Database Description", + "Link State Request", + "Link State Update", + "Link State Acknowledgment", +}; + +extern int in_cksum (void *ptr, int nbytes); + +/* OSPF authentication checking function */ +int +ospf_auth_type (struct ospf_interface *oi) +{ + int auth_type; + + if (OSPF_IF_PARAM (oi, auth_type) == OSPF_AUTH_NOTSET) + auth_type = oi->area->auth_type; + else + auth_type = OSPF_IF_PARAM (oi, auth_type); + + /* Handle case where MD5 key list is not configured aka Cisco */ + if (auth_type == OSPF_AUTH_CRYPTOGRAPHIC && + list_isempty (OSPF_IF_PARAM (oi, auth_crypt))) + return OSPF_AUTH_NULL; + + return auth_type; + +} + +/* forward output pointer. */ +void +ospf_output_forward (struct stream *s, int size) +{ + s->putp += size; +} + +struct ospf_packet * +ospf_packet_new (size_t size) +{ + struct ospf_packet *new; + + new = XCALLOC (MTYPE_OSPF_PACKET, sizeof (struct ospf_packet)); + new->s = stream_new (size); + + return new; +} + +void +ospf_packet_free (struct ospf_packet *op) +{ + if (op->s) + stream_free (op->s); + + XFREE (MTYPE_OSPF_PACKET, op); + + op = NULL; +} + +struct ospf_fifo * +ospf_fifo_new () +{ + struct ospf_fifo *new; + + new = XCALLOC (MTYPE_OSPF_FIFO, sizeof (struct ospf_fifo)); + return new; +} + +/* Add new packet to fifo. */ +void +ospf_fifo_push (struct ospf_fifo *fifo, struct ospf_packet *op) +{ + if (fifo->tail) + fifo->tail->next = op; + else + fifo->head = op; + + fifo->tail = op; + + fifo->count++; +} + +/* Delete first packet from fifo. */ +struct ospf_packet * +ospf_fifo_pop (struct ospf_fifo *fifo) +{ + struct ospf_packet *op; + + op = fifo->head; + + if (op) + { + fifo->head = op->next; + + if (fifo->head == NULL) + fifo->tail = NULL; + + fifo->count--; + } + + return op; +} + +/* Return first fifo entry. */ +struct ospf_packet * +ospf_fifo_head (struct ospf_fifo *fifo) +{ + return fifo->head; +} + +/* Flush ospf packet fifo. */ +void +ospf_fifo_flush (struct ospf_fifo *fifo) +{ + struct ospf_packet *op; + struct ospf_packet *next; + + for (op = fifo->head; op; op = next) + { + next = op->next; + ospf_packet_free (op); + } + fifo->head = fifo->tail = NULL; + fifo->count = 0; +} + +/* Free ospf packet fifo. */ +void +ospf_fifo_free (struct ospf_fifo *fifo) +{ + ospf_fifo_flush (fifo); + + XFREE (MTYPE_OSPF_FIFO, fifo); +} + +void +ospf_packet_add (struct ospf_interface *oi, struct ospf_packet *op) +{ + /* Add packet to end of queue. */ + ospf_fifo_push (oi->obuf, op); + + /* Debug of packet fifo*/ + /* ospf_fifo_debug (oi->obuf); */ +} + +void +ospf_packet_delete (struct ospf_interface *oi) +{ + struct ospf_packet *op; + + op = ospf_fifo_pop (oi->obuf); + + if (op) + ospf_packet_free (op); +} + +struct stream * +ospf_stream_copy (struct stream *new, struct stream *s) +{ + new->endp = s->endp; + new->putp = s->putp; + new->getp = s->getp; + + memcpy (new->data, s->data, stream_get_endp (s)); + + return new; +} + +struct ospf_packet * +ospf_packet_dup (struct ospf_packet *op) +{ + struct ospf_packet *new; + + new = ospf_packet_new (op->length); + ospf_stream_copy (new->s, op->s); + + new->dst = op->dst; + new->length = op->length; + + return new; +} + +int +ospf_packet_max (struct ospf_interface *oi) +{ + int max; + + if ( ospf_auth_type (oi) == OSPF_AUTH_CRYPTOGRAPHIC) + max = oi->ifp->mtu - OSPF_AUTH_MD5_SIZE - 88; + else + max = oi->ifp->mtu - 88; + + return max; +} + + +int +ospf_check_md5_digest (struct ospf_interface *oi, struct stream *s, + u_int16_t length) +{ + void *ibuf; + struct md5_ctx ctx; + unsigned char digest[OSPF_AUTH_MD5_SIZE]; + unsigned char *pdigest; + struct crypt_key *ck; + struct ospf_header *ospfh; + struct ospf_neighbor *nbr; + + + ibuf = STREAM_PNT (s); + ospfh = (struct ospf_header *) ibuf; + + /* Get pointer to the end of the packet. */ + pdigest = ibuf + length; + + /* Get secret key. */ + ck = ospf_crypt_key_lookup (OSPF_IF_PARAM (oi, auth_crypt), + ospfh->u.crypt.key_id); + if (ck == NULL) + { + zlog_warn ("interface %s: ospf_check_md5 no key %d", + IF_NAME (oi), ospfh->u.crypt.key_id); + return 0; + } + + /* check crypto seqnum. */ + nbr = ospf_nbr_lookup_by_routerid (oi->nbrs, &ospfh->router_id); + + if (nbr && ntohl(nbr->crypt_seqnum) > ntohl(ospfh->u.crypt.crypt_seqnum)) + { + zlog_warn ("interface %s: ospf_check_md5 bad sequence %d (expect %d)", + IF_NAME (oi), + ntohl(ospfh->u.crypt.crypt_seqnum), + ntohl(nbr->crypt_seqnum)); + return 0; + } + + /* Generate a digest for the ospf packet - their digest + our digest. */ + md5_init_ctx (&ctx); + md5_process_bytes (ibuf, length, &ctx); + md5_process_bytes (ck->auth_key, OSPF_AUTH_MD5_SIZE, &ctx); + md5_finish_ctx (&ctx, digest); + + /* compare the two */ + if (memcmp (pdigest, digest, OSPF_AUTH_MD5_SIZE)) + { + zlog_warn ("interface %s: ospf_check_md5 checksum mismatch", + IF_NAME (oi)); + return 0; + } + + /* save neighbor's crypt_seqnum */ + if (nbr) + nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum; + return 1; +} + +/* This function is called from ospf_write(), it will detect the + authentication scheme and if it is MD5, it will change the sequence + and update the MD5 digest. */ +int +ospf_make_md5_digest (struct ospf_interface *oi, struct ospf_packet *op) +{ + struct ospf_header *ospfh; + unsigned char digest[OSPF_AUTH_MD5_SIZE]; + struct md5_ctx ctx; + void *ibuf; + unsigned long oldputp; + struct crypt_key *ck; + char *auth_key; + + ibuf = STREAM_DATA (op->s); + ospfh = (struct ospf_header *) ibuf; + + if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC) + return 0; + + /* We do this here so when we dup a packet, we don't have to + waste CPU rewriting other headers. */ + ospfh->u.crypt.crypt_seqnum = htonl (oi->crypt_seqnum++); + + /* Get MD5 Authentication key from auth_key list. */ + if (list_isempty (OSPF_IF_PARAM (oi, auth_crypt))) + auth_key = ""; + else + { + ck = getdata (OSPF_IF_PARAM (oi, auth_crypt)->tail); + auth_key = ck->auth_key; + } + + /* Generate a digest for the entire packet + our secret key. */ + md5_init_ctx (&ctx); + md5_process_bytes (ibuf, ntohs (ospfh->length), &ctx); + md5_process_bytes (auth_key, OSPF_AUTH_MD5_SIZE, &ctx); + md5_finish_ctx (&ctx, digest); + + /* Append md5 digest to the end of the stream. */ + oldputp = stream_get_putp (op->s); + stream_set_putp (op->s, ntohs (ospfh->length)); + stream_put (op->s, digest, OSPF_AUTH_MD5_SIZE); + stream_set_putp (op->s, oldputp); + + /* We do *NOT* increment the OSPF header length. */ + op->length += OSPF_AUTH_MD5_SIZE; + + return OSPF_AUTH_MD5_SIZE; +} + + +int +ospf_ls_req_timer (struct thread *thread) +{ + struct ospf_neighbor *nbr; + + nbr = THREAD_ARG (thread); + nbr->t_ls_req = NULL; + + /* Send Link State Request. */ + if (ospf_ls_request_count (nbr)) + ospf_ls_req_send (nbr); + + /* Set Link State Request retransmission timer. */ + OSPF_NSM_TIMER_ON (nbr->t_ls_req, ospf_ls_req_timer, nbr->v_ls_req); + + return 0; +} + +void +ospf_ls_req_event (struct ospf_neighbor *nbr) +{ + if (nbr->t_ls_req) + { + thread_cancel (nbr->t_ls_req); + nbr->t_ls_req = NULL; + } + nbr->t_ls_req = thread_add_event (master, ospf_ls_req_timer, nbr, 0); +} + +/* Cyclic timer function. Fist registered in ospf_nbr_new () in + ospf_neighbor.c */ +int +ospf_ls_upd_timer (struct thread *thread) +{ + struct ospf_neighbor *nbr; + + nbr = THREAD_ARG (thread); + nbr->t_ls_upd = NULL; + + /* Send Link State Update. */ + if (ospf_ls_retransmit_count (nbr) > 0) + { + list update; + struct ospf_lsdb *lsdb; + int i; + struct timeval now; + int retransmit_interval; + + gettimeofday (&now, NULL); + retransmit_interval = OSPF_IF_PARAM (nbr->oi, retransmit_interval); + + lsdb = &nbr->ls_rxmt; + update = list_new (); + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + { + struct route_table *table = lsdb->type[i].db; + struct route_node *rn; + + for (rn = route_top (table); rn; rn = route_next (rn)) + { + struct ospf_lsa *lsa; + + if ((lsa = rn->info) != NULL) + /* Don't retransmit an LSA if we received it within + the last RxmtInterval seconds - this is to allow the + neighbour a chance to acknowledge the LSA as it may + have ben just received before the retransmit timer + fired. This is a small tweak to what is in the RFC, + but it will cut out out a lot of retransmit traffic + - MAG */ + if (tv_cmp (tv_sub (now, lsa->tv_recv), + int2tv (retransmit_interval)) >= 0) + listnode_add (update, rn->info); + } + } + + if (listcount (update) > 0) + ospf_ls_upd_send (nbr, update, OSPF_SEND_PACKET_DIRECT); + list_delete (update); + } + + /* Set LS Update retransmission timer. */ + OSPF_NSM_TIMER_ON (nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd); + + return 0; +} + +int +ospf_ls_ack_timer (struct thread *thread) +{ + struct ospf_interface *oi; + + oi = THREAD_ARG (thread); + oi->t_ls_ack = NULL; + + /* Send Link State Acknowledgment. */ + if (listcount (oi->ls_ack) > 0) + ospf_ls_ack_send_delayed (oi); + + /* Set LS Ack timer. */ + OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack); + + return 0; +} + +int +ospf_write (struct thread *thread) +{ + struct ospf_interface *oi; + struct ospf_packet *op; + struct sockaddr_in sa_dst; + u_char type; + int ret; + int flags = 0; + struct ip iph; + struct msghdr msg; + struct iovec iov[2]; + struct ospf *top; + listnode node; + + top = THREAD_ARG (thread); + top->t_write = NULL; + + node = listhead (top->oi_write_q); + assert (node); + oi = getdata (node); + assert (oi); + + /* Get one packet from queue. */ + op = ospf_fifo_head (oi->obuf); + assert (op); + assert (op->length >= OSPF_HEADER_SIZE); + + if (op->dst.s_addr == htonl (OSPF_ALLSPFROUTERS) || + op->dst.s_addr == htonl (OSPF_ALLDROUTERS)) + ospf_if_ipmulticast (top, oi->address, oi->ifp->ifindex); + + /* Rewrite the md5 signature & update the seq */ + ospf_make_md5_digest (oi, op); + + memset (&sa_dst, 0, sizeof (sa_dst)); + sa_dst.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + sa_dst.sin_len = sizeof(sa_dst); +#endif /* HAVE_SIN_LEN */ + sa_dst.sin_addr = op->dst; + sa_dst.sin_port = htons (0); + + /* Set DONTROUTE flag if dst is unicast. */ + if (oi->type != OSPF_IFTYPE_VIRTUALLINK) + if (!IN_MULTICAST (htonl (op->dst.s_addr))) + flags = MSG_DONTROUTE; + + iph.ip_hl = sizeof (struct ip) >> 2; + iph.ip_v = IPVERSION; + iph.ip_tos = 0; +#if defined(__NetBSD__) || defined(__FreeBSD__) + iph.ip_len = iph.ip_hl*4 + op->length; +#else + iph.ip_len = htons (iph.ip_hl*4 + op->length); +#endif + iph.ip_id = 0; + iph.ip_off = 0; + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + iph.ip_ttl = OSPF_VL_IP_TTL; + else + iph.ip_ttl = OSPF_IP_TTL; + iph.ip_p = IPPROTO_OSPFIGP; + iph.ip_sum = 0; + iph.ip_src.s_addr = oi->address->u.prefix4.s_addr; + iph.ip_dst.s_addr = op->dst.s_addr; + + memset (&msg, 0, sizeof (msg)); + msg.msg_name = &sa_dst; + msg.msg_namelen = sizeof (sa_dst); + msg.msg_iov = iov; + msg.msg_iovlen = 2; + iov[0].iov_base = (char*)&iph; + iov[0].iov_len = iph.ip_hl*4; + iov[1].iov_base = STREAM_DATA (op->s); + iov[1].iov_len = op->length; + + ret = sendmsg (top->fd, &msg, flags); + + if (ret < 0) + zlog_warn ("*** sendmsg in ospf_write failed with %s", strerror (errno)); + + /* Retrieve OSPF packet type. */ + stream_set_getp (op->s, 1); + type = stream_getc (op->s); + + /* Show debug sending packet. */ + if (IS_DEBUG_OSPF_PACKET (type - 1, SEND)) + { + if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL)) + { + zlog_info ("-----------------------------------------------------"); + stream_set_getp (op->s, 0); + ospf_packet_dump (op->s); + } + + zlog_info ("%s sent to [%s] via [%s].", + ospf_packet_type_str[type], inet_ntoa (op->dst), + IF_NAME (oi)); + + if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL)) + zlog_info ("-----------------------------------------------------"); + } + + /* Now delete packet from queue. */ + ospf_packet_delete (oi); + + if (ospf_fifo_head (oi->obuf) == NULL) + { + oi->on_write_q = 0; + list_delete_node (top->oi_write_q, node); + } + + /* If packets still remain in queue, call write thread. */ + if (!list_isempty (top->oi_write_q)) + ospf_top->t_write = + thread_add_write (master, ospf_write, top, top->fd); + + return 0; +} + +/* OSPF Hello message read -- RFC2328 Section 10.5. */ +void +ospf_hello (struct ip *iph, struct ospf_header *ospfh, + struct stream * s, struct ospf_interface *oi, int size) +{ + struct ospf_hello *hello; + struct ospf_neighbor *nbr; + struct route_node *rn; + struct prefix p, key; + int old_state; + + /* increment statistics. */ + oi->hello_in++; + + hello = (struct ospf_hello *) STREAM_PNT (s); + + /* If Hello is myself, silently discard. */ + if (IPV4_ADDR_SAME (&ospfh->router_id, &ospf_top->router_id)) + return; + + /* If incoming interface is passive one, ignore Hello. */ + if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE) + return; + + /* get neighbor prefix. */ + p.family = AF_INET; + p.prefixlen = ip_masklen (hello->network_mask); + p.u.prefix4 = iph->ip_src; + + /* Compare network mask. */ + /* Checking is ignored for Point-to-Point and Virtual link. */ + if (oi->type != OSPF_IFTYPE_POINTOPOINT + && oi->type != OSPF_IFTYPE_VIRTUALLINK) + if (oi->address->prefixlen != p.prefixlen) + { + zlog_warn ("Packet %s [Hello:RECV]: NetworkMask mismatch.", + inet_ntoa (ospfh->router_id)); + return; + } + + /* Compare Hello Interval. */ + if (OSPF_IF_PARAM (oi, v_hello) != ntohs (hello->hello_interval)) + { + zlog_warn ("Packet %s [Hello:RECV]: HelloInterval mismatch.", + inet_ntoa (ospfh->router_id)); + return; + } + + /* Compare Router Dead Interval. */ + if (OSPF_IF_PARAM (oi, v_wait) != ntohl (hello->dead_interval)) + { + zlog_warn ("Packet %s [Hello:RECV]: RouterDeadInterval mismatch.", + inet_ntoa (ospfh->router_id)); + return; + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Packet %s [Hello:RECV]: Options %s", + inet_ntoa (ospfh->router_id), + ospf_options_dump (hello->options)); + + /* Compare options. */ +#define REJECT_IF_TBIT_ON 1 /* XXX */ +#ifdef REJECT_IF_TBIT_ON + if (CHECK_FLAG (hello->options, OSPF_OPTION_T)) + { + /* + * This router does not support non-zero TOS. + * Drop this Hello packet not to establish neighbor relationship. + */ + zlog_warn ("Packet %s [Hello:RECV]: T-bit on, drop it.", + inet_ntoa (ospfh->router_id)); + return; + } +#endif /* REJECT_IF_TBIT_ON */ + +#ifdef HAVE_OPAQUE_LSA + if (CHECK_FLAG (ospf_top->config, OSPF_OPAQUE_CAPABLE) + && CHECK_FLAG (hello->options, OSPF_OPTION_O)) + { + /* + * This router does know the correct usage of O-bit + * the bit should be set in DD packet only. + */ + zlog_warn ("Packet %s [Hello:RECV]: O-bit abuse?", + inet_ntoa (ospfh->router_id)); +#ifdef STRICT_OBIT_USAGE_CHECK + return; /* Reject this packet. */ +#else /* STRICT_OBIT_USAGE_CHECK */ + UNSET_FLAG (hello->options, OSPF_OPTION_O); /* Ignore O-bit. */ +#endif /* STRICT_OBIT_USAGE_CHECK */ + } +#endif /* HAVE_OPAQUE_LSA */ + + /* new for NSSA is to ensure that NP is on and E is off */ + +#ifdef HAVE_NSSA + if (oi->area->external_routing == OSPF_AREA_NSSA) + { + if (! (CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_NP) + && CHECK_FLAG (hello->options, OSPF_OPTION_NP) + && ! CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_E) + && ! CHECK_FLAG (hello->options, OSPF_OPTION_E))) + { + zlog_warn ("NSSA-Packet-%s[Hello:RECV]: my options: %x, his options %x", inet_ntoa (ospfh->router_id), OPTIONS (oi), hello->options); + return; + } + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("NSSA-Hello:RECV:Packet from %s:", inet_ntoa(ospfh->router_id)); + } + else +#endif /* HAVE_NSSA */ + /* The setting of the E-bit found in the Hello Packet's Options + field must match this area's ExternalRoutingCapability A + mismatch causes processing to stop and the packet to be + dropped. The setting of the rest of the bits in the Hello + Packet's Options field should be ignored. */ + if (CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_E) != + CHECK_FLAG (hello->options, OSPF_OPTION_E)) + { + zlog_warn ("Packet[Hello:RECV]: my options: %x, his options %x", + OPTIONS (oi), hello->options); + return; + } + + + /* Get neighbor information from table. */ + key.family = AF_INET; + key.prefixlen = IPV4_MAX_BITLEN; + key.u.prefix4 = iph->ip_src; + + rn = route_node_get (oi->nbrs, &key); + if (rn->info) + { + route_unlock_node (rn); + nbr = rn->info; + + if (oi->type == OSPF_IFTYPE_NBMA && nbr->state == NSM_Attempt) + { + nbr->src = iph->ip_src; + nbr->address = p; + } + } + else + { + /* Create new OSPF Neighbor structure. */ + nbr = ospf_nbr_new (oi); + nbr->state = NSM_Down; + nbr->src = iph->ip_src; + nbr->address = p; + + rn->info = nbr; + + nbr->nbr_nbma = NULL; + + if (oi->type == OSPF_IFTYPE_NBMA) + { + struct ospf_nbr_nbma *nbr_nbma; + listnode node; + + for (node = listhead (oi->nbr_nbma); node; nextnode (node)) + { + nbr_nbma = getdata (node); + assert (nbr_nbma); + + if (IPV4_ADDR_SAME(&nbr_nbma->addr, &iph->ip_src)) + { + nbr_nbma->nbr = nbr; + nbr->nbr_nbma = nbr_nbma; + + if (nbr_nbma->t_poll) + OSPF_POLL_TIMER_OFF (nbr_nbma->t_poll); + + nbr->state_change = nbr_nbma->state_change + 1; + } + } + } + + /* New nbr, save the crypto sequence number if necessary */ + if (ntohs (ospfh->auth_type) == OSPF_AUTH_CRYPTOGRAPHIC) + nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("NSM[%s:%s]: start", IF_NAME (nbr->oi), + inet_ntoa (nbr->router_id)); + } + + nbr->router_id = ospfh->router_id; + + old_state = nbr->state; + + /* Add event to thread. */ + OSPF_NSM_EVENT_EXECUTE (nbr, NSM_HelloReceived); + + /* RFC2328 Section 9.5.1 + If the router is not eligible to become Designated Router, + (snip) It must also send an Hello Packet in reply to an + Hello Packet received from any eligible neighbor (other than + the current Designated Router and Backup Designated Router). */ + if (oi->type == OSPF_IFTYPE_NBMA) + if (PRIORITY(oi) == 0 && hello->priority > 0 + && IPV4_ADDR_CMP(&DR(oi), &iph->ip_src) + && IPV4_ADDR_CMP(&BDR(oi), &iph->ip_src)) + OSPF_NSM_TIMER_ON (nbr->t_hello_reply, ospf_hello_reply_timer, + OSPF_HELLO_REPLY_DELAY); + + /* on NBMA network type, it happens to receive bidirectional Hello packet + without advance 1-Way Received event. + To avoid incorrect DR-seletion, raise 1-Way Received event.*/ + if (oi->type == OSPF_IFTYPE_NBMA && + (old_state == NSM_Down || old_state == NSM_Attempt)) + { + OSPF_NSM_EVENT_EXECUTE (nbr, NSM_OneWayReceived); + nbr->priority = hello->priority; + nbr->d_router = hello->d_router; + nbr->bd_router = hello->bd_router; + return; + } + + if (ospf_nbr_bidirectional (&ospf_top->router_id, hello->neighbors, + size - OSPF_HELLO_MIN_SIZE)) + { + OSPF_NSM_EVENT_EXECUTE (nbr, NSM_TwoWayReceived); + nbr->options |= hello->options; + } + else + { + OSPF_NSM_EVENT_EXECUTE (nbr, NSM_OneWayReceived); + /* Set neighbor information. */ + nbr->priority = hello->priority; + nbr->d_router = hello->d_router; + nbr->bd_router = hello->bd_router; + return; + } + + /* If neighbor itself declares DR and no BDR exists, + cause event BackupSeen */ + if (IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->d_router)) + if (hello->bd_router.s_addr == 0 && oi->state == ISM_Waiting) + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_BackupSeen); + + /* neighbor itself declares BDR. */ + if (oi->state == ISM_Waiting && + IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->bd_router)) + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_BackupSeen); + + /* had not previously. */ + if ((IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->d_router) && + IPV4_ADDR_CMP (&nbr->address.u.prefix4, &nbr->d_router)) || + (IPV4_ADDR_CMP (&nbr->address.u.prefix4, &hello->d_router) && + IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->d_router))) + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange); + + /* had not previously. */ + if ((IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->bd_router) && + IPV4_ADDR_CMP (&nbr->address.u.prefix4, &nbr->bd_router)) || + (IPV4_ADDR_CMP (&nbr->address.u.prefix4, &hello->bd_router) && + IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->bd_router))) + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange); + + /* Neighbor priority check. */ + if (nbr->priority >= 0 && nbr->priority != hello->priority) + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange); + + /* Set neighbor information. */ + nbr->priority = hello->priority; + nbr->d_router = hello->d_router; + nbr->bd_router = hello->bd_router; +} + +/* Save DD flags/options/Seqnum received. */ +void +ospf_db_desc_save_current (struct ospf_neighbor *nbr, + struct ospf_db_desc *dd) +{ + nbr->last_recv.flags = dd->flags; + nbr->last_recv.options = dd->options; + nbr->last_recv.dd_seqnum = ntohl (dd->dd_seqnum); +} + +/* Process rest of DD packet. */ +static void +ospf_db_desc_proc (struct stream *s, struct ospf_interface *oi, + struct ospf_neighbor *nbr, struct ospf_db_desc *dd, + u_int16_t size) +{ + struct ospf_lsa *new, *find; + struct lsa_header *lsah; + + stream_forward (s, OSPF_DB_DESC_MIN_SIZE); + for (size -= OSPF_DB_DESC_MIN_SIZE; + size >= OSPF_LSA_HEADER_SIZE; size -= OSPF_LSA_HEADER_SIZE) + { + lsah = (struct lsa_header *) STREAM_PNT (s); + stream_forward (s, OSPF_LSA_HEADER_SIZE); + + /* Unknown LS type. */ + if (lsah->type < OSPF_MIN_LSA || lsah->type >= OSPF_MAX_LSA) + { + zlog_warn ("Pakcet [DD:RECV]: Unknown LS type %d.", lsah->type); + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); + return; + } + +#ifdef HAVE_OPAQUE_LSA + if (IS_OPAQUE_LSA (lsah->type) + && ! CHECK_FLAG (nbr->options, OSPF_OPTION_O)) + { + zlog_warn ("LSA[Type%d:%s]: Opaque capability mismatch?", lsah->type, inet_ntoa (lsah->id)); + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); + return; + } +#endif /* HAVE_OPAQUE_LSA */ + + switch (lsah->type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ +#ifdef HAVE_NSSA + /* Check for stub area. Reject if AS-External from stub but + allow if from NSSA. */ + if (oi->area->external_routing == OSPF_AREA_STUB) +#else /* ! HAVE_NSSA */ + if (oi->area->external_routing != OSPF_AREA_DEFAULT) +#endif /* HAVE_NSSA */ + { + zlog_warn ("Packet [DD:RECV]: LSA[Type%d:%s] from %s area.", + lsah->type, inet_ntoa (lsah->id), + (oi->area->external_routing == OSPF_AREA_STUB) ?\ + "STUB" : "NSSA"); + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); + return; + } + break; + default: + break; + } + + /* Create LS-request object. */ + new = ospf_ls_request_new (lsah); + + /* Lookup received LSA, then add LS request list. */ + find = ospf_lsa_lookup_by_header (oi->area, lsah); + if (!find || ospf_lsa_more_recent (find, new) < 0) + { + ospf_ls_request_add (nbr, new); + ospf_lsa_discard (new); + } + else + { + /* Received LSA is not recent. */ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Packet [DD:RECV]: LSA received Type %d, " + "ID %s is not recent.", lsah->type, inet_ntoa (lsah->id)); + ospf_lsa_discard (new); + continue; + } + } + + /* Master */ + if (IS_SET_DD_MS (nbr->dd_flags)) + { + nbr->dd_seqnum++; + /* Entire DD packet sent. */ + if (!IS_SET_DD_M (dd->flags) && !IS_SET_DD_M (nbr->dd_flags)) + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_ExchangeDone); + else + /* Send new DD packet. */ + ospf_db_desc_send (nbr); + } + /* Slave */ + else + { + nbr->dd_seqnum = ntohl (dd->dd_seqnum); + + /* When master's more flags is not set. */ + if (!IS_SET_DD_M (dd->flags) && ospf_db_summary_isempty (nbr)) + { + nbr->dd_flags &= ~(OSPF_DD_FLAG_M); + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_ExchangeDone); + } + + /* Send DD pakcet in reply. */ + ospf_db_desc_send (nbr); + } + + /* Save received neighbor values from DD. */ + ospf_db_desc_save_current (nbr, dd); +} + +int +ospf_db_desc_is_dup (struct ospf_db_desc *dd, struct ospf_neighbor *nbr) +{ + /* Is DD duplicated? */ + if (dd->options == nbr->last_recv.options && + dd->flags == nbr->last_recv.flags && + dd->dd_seqnum == htonl (nbr->last_recv.dd_seqnum)) + return 1; + + return 0; +} + +/* OSPF Database Description message read -- RFC2328 Section 10.6. */ +void +ospf_db_desc (struct ip *iph, struct ospf_header *ospfh, + struct stream *s, struct ospf_interface *oi, u_int16_t size) +{ + struct ospf_db_desc *dd; + struct ospf_neighbor *nbr; + + /* Increment statistics. */ + oi->db_desc_in++; + + dd = (struct ospf_db_desc *) STREAM_PNT (s); + + nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src); + if (nbr == NULL) + { + zlog_warn ("Packet[DD]: Unknown Neighbor %s", + inet_ntoa (ospfh->router_id)); + return; + } + + /* Check MTU. */ + if (ntohs (dd->mtu) > oi->ifp->mtu) + { + zlog_warn ("Packet[DD]: MTU is larger than [%s]'s MTU", IF_NAME (oi)); + return; + } + +#ifdef REJECT_IF_TBIT_ON + if (CHECK_FLAG (dd->options, OSPF_OPTION_T)) + { + /* + * In Hello protocol, optional capability must have checked + * to prevent this T-bit enabled router be my neighbor. + */ + zlog_warn ("Packet[DD]: Neighbor %s: T-bit on?", inet_ntoa (nbr->router_id)); + return; + } +#endif /* REJECT_IF_TBIT_ON */ + +#ifdef HAVE_OPAQUE_LSA + if (CHECK_FLAG (dd->options, OSPF_OPTION_O) + && !CHECK_FLAG (ospf_top->config, OSPF_OPAQUE_CAPABLE)) + { + /* + * This node is not configured to handle O-bit, for now. + * Clear it to ignore unsupported capability proposed by neighbor. + */ + UNSET_FLAG (dd->options, OSPF_OPTION_O); + } +#endif /* HAVE_OPAQUE_LSA */ + + /* Process DD packet by neighbor status. */ + switch (nbr->state) + { + case NSM_Down: + case NSM_Attempt: + case NSM_TwoWay: + zlog_warn ("Packet[DD]: Neighbor state is %s, packet discarded.", + LOOKUP (ospf_nsm_state_msg, nbr->state)); + break; + case NSM_Init: + OSPF_NSM_EVENT_EXECUTE (nbr, NSM_TwoWayReceived); + /* If the new state is ExStart, the processing of the current + packet should then continue in this new state by falling + through to case ExStart below. */ + if (nbr->state != NSM_ExStart) + break; + case NSM_ExStart: + /* Initial DBD */ + if ((IS_SET_DD_ALL (dd->flags) == OSPF_DD_FLAG_ALL) && + (size == OSPF_DB_DESC_MIN_SIZE)) + { + if (IPV4_ADDR_CMP (&nbr->router_id, &ospf_top->router_id) > 0) + { + /* We're Slave---obey */ + zlog_warn ("Packet[DD]: Negotiation done (Slave)."); + nbr->dd_seqnum = ntohl (dd->dd_seqnum); + nbr->dd_flags &= ~(OSPF_DD_FLAG_MS|OSPF_DD_FLAG_I); /* Reset I/MS */ + } + else + { + /* We're Master, ignore the initial DBD from Slave */ + zlog_warn ("Packet[DD]: Initial DBD from Slave, ignoring."); + break; + } + } + /* Ack from the Slave */ + else if (!IS_SET_DD_MS (dd->flags) && !IS_SET_DD_I (dd->flags) && + ntohl (dd->dd_seqnum) == nbr->dd_seqnum && + IPV4_ADDR_CMP (&nbr->router_id, &ospf_top->router_id) < 0) + { + zlog_warn ("Packet[DD]: Negotiation done (Master)."); + nbr->dd_flags &= ~OSPF_DD_FLAG_I; + } + else + { + zlog_warn ("Packet[DD]: Negotiation fails."); + break; + } + + /* This is where the real Options are saved */ + nbr->options = dd->options; + +#ifdef HAVE_OPAQUE_LSA + if (CHECK_FLAG (ospf_top->config, OSPF_OPAQUE_CAPABLE)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Neighbor[%s] is %sOpaque-capable.", + inet_ntoa (nbr->router_id), + CHECK_FLAG (nbr->options, OSPF_OPTION_O) ? "" : "NOT "); + + if (! CHECK_FLAG (nbr->options, OSPF_OPTION_O) + && IPV4_ADDR_SAME (&DR (oi), &nbr->address.u.prefix4)) + { + zlog_warn ("DR-neighbor[%s] is NOT opaque-capable; Opaque-LSAs cannot be reliably advertised in this network.", inet_ntoa (nbr->router_id)); + /* This situation is undesirable, but not a real error. */ + } + } +#endif /* HAVE_OPAQUE_LSA */ + + OSPF_NSM_EVENT_EXECUTE (nbr, NSM_NegotiationDone); + + /* continue processing rest of packet. */ + ospf_db_desc_proc (s, oi, nbr, dd, size); + break; + case NSM_Exchange: + if (ospf_db_desc_is_dup (dd, nbr)) + { + if (IS_SET_DD_MS (nbr->dd_flags)) + /* Master: discard duplicated DD packet. */ + zlog_warn ("Packet[DD] (Master): packet duplicated."); + else + /* Slave: cause to retransmit the last Database Description. */ + { + zlog_warn ("Packet[DD] [Slave]: packet duplicated."); + ospf_db_desc_resend (nbr); + } + break; + } + + /* Otherwise DD packet should be checked. */ + /* Check Master/Slave bit mismatch */ + if (IS_SET_DD_MS (dd->flags) != IS_SET_DD_MS (nbr->last_recv.flags)) + { + zlog_warn ("Packet[DD]: MS-bit mismatch."); + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Packet[DD]: dd->flags=%d, nbr->dd_flags=%d", + dd->flags, nbr->dd_flags); + break; + } + + /* Check initialize bit is set. */ + if (IS_SET_DD_I (dd->flags)) + { + zlog_warn ("Packet[DD]: I-bit set."); + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); + break; + } + + /* Check DD Options. */ + if (dd->options != nbr->options) + { +#ifdef ORIGINAL_CODING + /* Save the new options for debugging */ + nbr->options = dd->options; +#endif /* ORIGINAL_CODING */ + zlog_warn ("Packet[DD]: options mismatch."); + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); + break; + } + + /* Check DD sequence number. */ + if ((IS_SET_DD_MS (nbr->dd_flags) && + ntohl (dd->dd_seqnum) != nbr->dd_seqnum) || + (!IS_SET_DD_MS (nbr->dd_flags) && + ntohl (dd->dd_seqnum) != nbr->dd_seqnum + 1)) + { + zlog_warn ("Pakcet[DD]: sequence number mismatch."); + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); + break; + } + + /* Continue processing rest of packet. */ + ospf_db_desc_proc (s, oi, nbr, dd, size); + break; + case NSM_Loading: + case NSM_Full: + if (ospf_db_desc_is_dup (dd, nbr)) + { + if (IS_SET_DD_MS (nbr->dd_flags)) + { + /* Master should discard duplicate DD packet. */ + zlog_warn ("Pakcet[DD]: duplicated, packet discarded."); + break; + } + else + { + struct timeval t, now; + gettimeofday (&now, NULL); + t = tv_sub (now, nbr->last_send_ts); + if (tv_cmp (t, int2tv (nbr->v_inactivity)) < 0) + { + /* In states Loading and Full the slave must resend + its last Database Description packet in response to + duplicate Database Description packets received + from the master. For this reason the slave must + wait RouterDeadInterval seconds before freeing the + last Database Description packet. Reception of a + Database Description packet from the master after + this interval will generate a SeqNumberMismatch + neighbor event. RFC2328 Section 10.8 */ + ospf_db_desc_resend (nbr); + break; + } + } + } + + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); + break; + default: + zlog_warn ("Packet[DD]: NSM illegal status."); + break; + } +} + +#define OSPF_LSA_KEY_SIZE 12 /* type(4) + id(4) + ar(4) */ + +/* OSPF Link State Request Read -- RFC2328 Section 10.7. */ +void +ospf_ls_req (struct ip *iph, struct ospf_header *ospfh, + struct stream *s, struct ospf_interface *oi, u_int16_t size) +{ + struct ospf_neighbor *nbr; + u_int32_t ls_type; + struct in_addr ls_id; + struct in_addr adv_router; + struct ospf_lsa *find; + list ls_upd; + int length; + + /* Increment statistics. */ + oi->ls_req_in++; + + nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src); + if (nbr == NULL) + { + zlog_warn ("Link State Request: Unknown Neighbor %s.", + inet_ntoa (ospfh->router_id)); + return; + } + + /* Neighbor State should be Exchange or later. */ + if (nbr->state != NSM_Exchange && + nbr->state != NSM_Loading && + nbr->state != NSM_Full) + { + zlog_warn ("Link State Request: Neighbor state is %s, packet discarded.", + LOOKUP (ospf_nsm_state_msg, nbr->state)); + return; + } + + /* Send Link State Update for ALL requested LSAs. */ + ls_upd = list_new (); + length = OSPF_HEADER_SIZE + OSPF_LS_UPD_MIN_SIZE; + + while (size >= OSPF_LSA_KEY_SIZE) + { + /* Get one slice of Link State Request. */ + ls_type = stream_getl (s); + ls_id.s_addr = stream_get_ipv4 (s); + adv_router.s_addr = stream_get_ipv4 (s); + + /* Verify LSA type. */ + if (ls_type < OSPF_MIN_LSA || ls_type >= OSPF_MAX_LSA) + { + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_BadLSReq); + list_delete (ls_upd); + return; + } + + /* Search proper LSA in LSDB. */ + find = ospf_lsa_lookup (oi->area, ls_type, ls_id, adv_router); + if (find == NULL) + { + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_BadLSReq); + list_delete (ls_upd); + return; + } + + /* Packet overflows MTU size, send immediatly. */ + if (length + ntohs (find->data->length) > OSPF_PACKET_MAX (oi)) + { + if (oi->type == OSPF_IFTYPE_NBMA) + ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_DIRECT); + else + ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_INDIRECT); + + /* Only remove list contents. Keep ls_upd. */ + list_delete_all_node (ls_upd); + + length = OSPF_HEADER_SIZE + OSPF_LS_UPD_MIN_SIZE; + } + + /* Append LSA to update list. */ + listnode_add (ls_upd, find); + length += ntohs (find->data->length); + + size -= OSPF_LSA_KEY_SIZE; + } + + /* Send rest of Link State Update. */ + if (listcount (ls_upd) > 0) + { + if (oi->type == OSPF_IFTYPE_NBMA) + ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_DIRECT); + else + ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_INDIRECT); + + list_delete (ls_upd); + } + else + list_free (ls_upd); +} + +/* Get the list of LSAs from Link State Update packet. + And process some validation -- RFC2328 Section 13. (1)-(2). */ +static list +ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s, + struct ospf_interface *oi, size_t size) +{ + u_int16_t count, sum; + u_int32_t length; + struct lsa_header *lsah; + struct ospf_lsa *lsa; + list lsas; + + lsas = list_new (); + + count = stream_getl (s); + size -= OSPF_LS_UPD_MIN_SIZE; /* # LSAs */ + + for (; size >= OSPF_LSA_HEADER_SIZE && count > 0; + size -= length, stream_forward (s, length), count--) + { + lsah = (struct lsa_header *) STREAM_PNT (s); + length = ntohs (lsah->length); + + if (length > size) + { + zlog_warn ("Link State Update: LSA length exceeds packet size."); + break; + } + + /* Validate the LSA's LS checksum. */ + sum = lsah->checksum; + if (sum != ospf_lsa_checksum (lsah)) + { + zlog_warn ("Link State Update: LSA checksum error %x, %x.", + sum, lsah->checksum); + continue; + } + + /* Examine the LSA's LS type. */ + if (lsah->type < OSPF_MIN_LSA || lsah->type >= OSPF_MAX_LSA) + { + zlog_warn ("Link State Update: Unknown LS type %d", lsah->type); + continue; + } + + /* + * What if the received LSA's age is greater than MaxAge? + * Treat it as a MaxAge case -- endo. + */ + if (ntohs (lsah->ls_age) > OSPF_LSA_MAXAGE) + lsah->ls_age = htons (OSPF_LSA_MAXAGE); + +#ifdef HAVE_OPAQUE_LSA + if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) + { +#ifdef STRICT_OBIT_USAGE_CHECK + if ((IS_OPAQUE_LSA(lsah->type) && + ! CHECK_FLAG (lsah->options, OSPF_OPTION_O)) + || (! IS_OPAQUE_LSA(lsah->type) && + CHECK_FLAG (lsah->options, OSPF_OPTION_O))) + { + /* + * This neighbor must know the exact usage of O-bit; + * the bit will be set in Type-9,10,11 LSAs only. + */ + zlog_warn ("LSA[Type%d:%s]: O-bit abuse?", lsah->type, inet_ntoa (lsah->id)); + continue; + } +#endif /* STRICT_OBIT_USAGE_CHECK */ + + /* Do not take in AS External Opaque-LSAs if we are a stub. */ + if (lsah->type == OSPF_OPAQUE_AS_LSA + && nbr->oi->area->external_routing != OSPF_AREA_DEFAULT) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type%d:%s]: We are a stub, don't take this LSA.", lsah->type, inet_ntoa (lsah->id)); + continue; + } + } + else if (IS_OPAQUE_LSA(lsah->type)) + { + zlog_warn ("LSA[Type%d:%s]: Opaque capability mismatch?", lsah->type, inet_ntoa (lsah->id)); + continue; + } +#endif /* HAVE_OPAQUE_LSA */ + + /* Create OSPF LSA instance. */ + lsa = ospf_lsa_new (); + + /* We may wish to put some error checking if type NSSA comes in + and area not in NSSA mode */ + switch (lsah->type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: + lsa->area = NULL; + break; + case OSPF_OPAQUE_LINK_LSA: + lsa->oi = oi; /* Remember incoming interface for flooding control. */ + /* Fallthrough */ +#endif /* HAVE_OPAQUE_LSA */ + default: + lsa->area = oi->area; + break; + } + + lsa->data = ospf_lsa_data_new (length); + memcpy (lsa->data, lsah, length); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info("LSA[Type%d:%s]: %p new LSA created with Link State Update", + lsa->data->type, inet_ntoa (lsa->data->id), lsa); + listnode_add (lsas, lsa); + } + + return lsas; +} + +/* Cleanup Update list. */ +void +ospf_upd_list_clean (list lsas) +{ + listnode node; + struct ospf_lsa *lsa; + + for (node = listhead (lsas); node; nextnode (node)) + if ((lsa = getdata (node)) != NULL) + ospf_lsa_discard (lsa); + + list_delete (lsas); +} + +/* OSPF Link State Update message read -- RFC2328 Section 13. */ +void +ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh, + struct stream *s, struct ospf_interface *oi, u_int16_t size) +{ + struct ospf_neighbor *nbr; + list lsas; +#ifdef HAVE_OPAQUE_LSA + list mylsa_acks, mylsa_upds; +#endif /* HAVE_OPAQUE_LSA */ + listnode node, next; + struct ospf_lsa *lsa = NULL; + /* unsigned long ls_req_found = 0; */ + + /* Dis-assemble the stream, update each entry, re-encapsulate for flooding */ + + /* Increment statistics. */ + oi->ls_upd_in++; + + /* Check neighbor. */ + nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src); + if (nbr == NULL) + { + zlog_warn ("Link State Update: Unknown Neighbor %s on int: %s", + inet_ntoa (ospfh->router_id), IF_NAME (oi)); + return; + } + + /* Check neighbor state. */ + if (nbr->state < NSM_Exchange) + { + zlog_warn ("Link State Update: Neighbor[%s] state is less than Exchange", + inet_ntoa (ospfh->router_id)); + return; + } + + /* Get list of LSAs from Link State Update packet. - Also perorms Stages + * 1 (validate LSA checksum) and 2 (check for LSA consistent type) + * of section 13. + */ + lsas = ospf_ls_upd_list_lsa (nbr, s, oi, size); + +#ifdef HAVE_OPAQUE_LSA + /* + * Prepare two kinds of lists to clean up unwanted self-originated + * Opaque-LSAs from the routing domain as soon as possible. + */ + mylsa_acks = list_new (); /* Let the sender cease retransmission. */ + mylsa_upds = list_new (); /* Flush target LSAs if necessary. */ + + /* + * If self-originated Opaque-LSAs that have flooded before restart + * are contained in the received LSUpd message, corresponding LSReq + * messages to be sent may have to be modified. + * To eliminate possible race conditions such that flushing and normal + * updating for the same LSA would take place alternately, this trick + * must be done before entering to the loop below. + */ + ospf_opaque_adjust_lsreq (nbr, lsas); +#endif /* HAVE_OPAQUE_LSA */ + +#define DISCARD_LSA(L,N) {\ + if (IS_DEBUG_OSPF_EVENT) \ + zlog_info ("ospf_lsa_discard() in ospf_ls_upd() point %d: lsa %p Type-%d", N, lsa, (int) lsa->data->type); \ + ospf_lsa_discard (L); \ + continue; } + + /* Process each LSA received in the one packet. */ + for (node = listhead (lsas); node; node = next) + { + struct ospf_lsa *ls_ret, *current; + int ret = 1; + + next = node->next; + + lsa = getdata (node); + +#ifdef HAVE_NSSA + if (IS_DEBUG_OSPF_NSSA) + { + char buf1[INET_ADDRSTRLEN]; + char buf2[INET_ADDRSTRLEN]; + char buf3[INET_ADDRSTRLEN]; + + zlog_info("LSA Type-%d from %s, ID: %s, ADV: %s", + lsa->data->type, + inet_ntop (AF_INET, &ospfh->router_id, + buf1, INET_ADDRSTRLEN), + inet_ntop (AF_INET, &lsa->data->id, + buf2, INET_ADDRSTRLEN), + inet_ntop (AF_INET, &lsa->data->adv_router, + buf3, INET_ADDRSTRLEN)); + } +#endif /* HAVE_NSSA */ + + listnode_delete (lsas, lsa); /* We don't need it in list anymore */ + + /* Validate Checksum - Done above by ospf_ls_upd_list_lsa() */ + + /* LSA Type - Done above by ospf_ls_upd_list_lsa() */ + + /* Do not take in AS External LSAs if we are a stub or NSSA. */ + + /* Do not take in AS NSSA if this neighbor and we are not NSSA */ + + /* Do take in Type-7's if we are an NSSA */ + + /* If we are also an ABR, later translate them to a Type-5 packet */ + + /* Later, an NSSA Re-fresh can Re-fresh Type-7's and an ABR will + translate them to a separate Type-5 packet. */ + + if (lsa->data->type == OSPF_AS_EXTERNAL_LSA) + /* Reject from STUB or NSSA */ + if (nbr->oi->area->external_routing != OSPF_AREA_DEFAULT) + { + DISCARD_LSA (lsa, 1); +#ifdef HAVE_NSSA + if (IS_DEBUG_OSPF_NSSA) + zlog_info("Incoming External LSA Discarded: We are NSSA/STUB Area"); +#endif /* HAVE_NSSA */ + } + +#ifdef HAVE_NSSA + if (lsa->data->type == OSPF_AS_NSSA_LSA) + if (nbr->oi->area->external_routing != OSPF_AREA_NSSA) + { + DISCARD_LSA (lsa,2); + if (IS_DEBUG_OSPF_NSSA) + zlog_info("Incoming NSSA LSA Discarded: Not NSSA Area"); + } +#endif /* HAVE_NSSA */ + + /* Find the LSA in the current database. */ + + current = ospf_lsa_lookup_by_header (oi->area, lsa->data); + + /* If the LSA's LS age is equal to MaxAge, and there is currently + no instance of the LSA in the router's link state database, + and none of router's neighbors are in states Exchange or Loading, + then take the following actions. */ + + if (IS_LSA_MAXAGE (lsa) && !current && + (ospf_nbr_count (oi->nbrs, NSM_Exchange) + + ospf_nbr_count (oi->nbrs, NSM_Loading)) == 0) + { + /* Response Link State Acknowledgment. */ + ospf_ls_ack_send (nbr, lsa); + + /* Discard LSA. */ + zlog_warn ("Link State Update: LS age is equal to MaxAge."); + DISCARD_LSA (lsa, 3); + } + +#ifdef HAVE_OPAQUE_LSA + if (IS_OPAQUE_LSA (lsa->data->type) + && IPV4_ADDR_SAME (&lsa->data->adv_router, &ospf_top->router_id)) + { + /* + * Even if initial flushing seems to be completed, there might + * be a case that self-originated LSA with MaxAge still remain + * in the routing domain. + * Just send an LSAck message to cease retransmission. + */ + if (IS_LSA_MAXAGE (lsa)) + { + zlog_warn ("LSA[%s]: Boomerang effect?", dump_lsa_key (lsa)); + ospf_ls_ack_send (nbr, lsa); + ospf_lsa_discard (lsa); + + if (current != NULL && ! IS_LSA_MAXAGE (current)) + ospf_opaque_lsa_refresh_schedule (current); + continue; + } + + /* + * If an instance of self-originated Opaque-LSA is not found + * in the LSDB, there are some possible cases here. + * + * 1) This node lost opaque-capability after restart. + * 2) Else, a part of opaque-type is no more supported. + * 3) Else, a part of opaque-id is no more supported. + * + * Anyway, it is still this node's responsibility to flush it. + * Otherwise, the LSA instance remains in the routing domain + * until its age reaches to MaxAge. + */ + if (current == NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[%s]: Previously originated Opaque-LSA, not found in the LSDB.", dump_lsa_key (lsa)); + + SET_FLAG (lsa->flags, OSPF_LSA_SELF); + listnode_add (mylsa_upds, ospf_lsa_dup (lsa)); + listnode_add (mylsa_acks, ospf_lsa_lock (lsa)); + continue; + } + } +#endif /* HAVE_OPAQUE_LSA */ + + /* (5) Find the instance of this LSA that is currently contained + in the router's link state database. If there is no + database copy, or the received LSA is more recent than + the database copy the following steps must be performed. */ + + if (current == NULL || + (ret = ospf_lsa_more_recent (current, lsa)) < 0) + { + /* Actual flooding procedure. */ + if (ospf_flood (nbr, current, lsa) < 0) /* Trap NSSA later. */ + DISCARD_LSA (lsa, 4); + continue; + } + + /* (6) Else, If there is an instance of the LSA on the sending + neighbor's Link state request list, an error has occurred in + the Database Exchange process. In this case, restart the + Database Exchange process by generating the neighbor event + BadLSReq for the sending neighbor and stop processing the + Link State Update packet. */ + + if (ospf_ls_request_lookup (nbr, lsa)) + { + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_BadLSReq); + zlog_warn ("LSA instance exists on Link state request list"); + + /* Clean list of LSAs. */ + ospf_upd_list_clean (lsas); + /* this lsa is not on lsas list already. */ + ospf_lsa_discard (lsa); +#ifdef HAVE_OPAQUE_LSA + list_delete (mylsa_acks); + list_delete (mylsa_upds); +#endif /* HAVE_OPAQUE_LSA */ + return; + } + + /* If the received LSA is the same instance as the database copy + (i.e., neither one is more recent) the following two steps + should be performed: */ + + if (ret == 0) + { + /* If the LSA is listed in the Link state retransmission list + for the receiving adjacency, the router itself is expecting + an acknowledgment for this LSA. The router should treat the + received LSA as an acknowledgment by removing the LSA from + the Link state retransmission list. This is termed an + "implied acknowledgment". */ + + ls_ret = ospf_ls_retransmit_lookup (nbr, lsa); + + if (ls_ret != NULL) + { + ospf_ls_retransmit_delete (nbr, ls_ret); + + /* Delayed acknowledgment sent if advertisement received + from Designated Router, otherwise do nothing. */ + if (oi->state == ISM_Backup) + if (NBR_IS_DR (nbr)) + listnode_add (oi->ls_ack, ospf_lsa_lock (lsa)); + + DISCARD_LSA (lsa, 5); + } + else + /* Acknowledge the receipt of the LSA by sending a + Link State Acknowledgment packet back out the receiving + interface. */ + { + ospf_ls_ack_send (nbr, lsa); + DISCARD_LSA (lsa, 6); + } + } + + /* The database copy is more recent. If the database copy + has LS age equal to MaxAge and LS sequence number equal to + MaxSequenceNumber, simply discard the received LSA without + acknowledging it. (In this case, the LSA's LS sequence number is + wrapping, and the MaxSequenceNumber LSA must be completely + flushed before any new LSA instance can be introduced). */ + + else if (ret > 0) /* Database copy is more recent */ + { + if (IS_LSA_MAXAGE (current) && + current->data->ls_seqnum == htonl (OSPF_MAX_SEQUENCE_NUMBER)) + { + DISCARD_LSA (lsa, 7); + } + /* Otherwise, as long as the database copy has not been sent in a + Link State Update within the last MinLSArrival seconds, send the + database copy back to the sending neighbor, encapsulated within + a Link State Update Packet. The Link State Update Packet should + be sent directly to the neighbor. In so doing, do not put the + database copy of the LSA on the neighbor's link state + retransmission list, and do not acknowledge the received (less + recent) LSA instance. */ + else + { + struct timeval now; + + gettimeofday (&now, NULL); + + if (tv_cmp (tv_sub (now, current->tv_orig), + int2tv (OSPF_MIN_LS_ARRIVAL)) > 0) + /* Trap NSSA type later.*/ + ospf_ls_upd_send_lsa (nbr, current, OSPF_SEND_PACKET_DIRECT); + DISCARD_LSA (lsa, 8); + } + } + } + +#ifdef HAVE_OPAQUE_LSA + /* + * Now that previously originated Opaque-LSAs those which not yet + * installed into LSDB are captured, take several steps to clear + * them completely from the routing domain, before proceeding to + * origination for the current target Opaque-LSAs. + */ + while (listcount (mylsa_acks) > 0) + ospf_ls_ack_send_list (oi, mylsa_acks, nbr->address.u.prefix4); + + if (listcount (mylsa_upds) > 0) + ospf_opaque_self_originated_lsa_received (nbr, mylsa_upds); + + list_delete (mylsa_upds); +#endif /* HAVE_OPAQUE_LSA */ + + assert (listcount (lsas) == 0); + list_delete (lsas); +} + +/* OSPF Link State Acknowledgment message read -- RFC2328 Section 13.7. */ +void +ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh, + struct stream *s, struct ospf_interface *oi, u_int16_t size) +{ + struct ospf_neighbor *nbr; +#ifdef HAVE_OPAQUE_LSA + list opaque_acks; +#endif /* HAVE_OPAQUE_LSA */ + + /* increment statistics. */ + oi->ls_ack_in++; + + nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src); + if (nbr == NULL) + { + zlog_warn ("Link State Acknowledgment: Unknown Neighbor %s.", + inet_ntoa (ospfh->router_id)); + return; + } + + if (nbr->state < NSM_Exchange) + { + zlog_warn ("Link State Acknowledgment: State is less than Exchange."); + return; + } + +#ifdef HAVE_OPAQUE_LSA + opaque_acks = list_new (); +#endif /* HAVE_OPAQUE_LSA */ + + while (size >= OSPF_LSA_HEADER_SIZE) + { + struct ospf_lsa *lsa, *lsr; + + lsa = ospf_lsa_new (); + lsa->data = (struct lsa_header *) STREAM_PNT (s); + + /* lsah = (struct lsa_header *) STREAM_PNT (s); */ + size -= OSPF_LSA_HEADER_SIZE; + stream_forward (s, OSPF_LSA_HEADER_SIZE); + + if (lsa->data->type < OSPF_MIN_LSA || lsa->data->type >= OSPF_MAX_LSA) + { + lsa->data = NULL; + ospf_lsa_discard (lsa); + continue; + } + + lsr = ospf_ls_retransmit_lookup (nbr, lsa); + + if (lsr != NULL && lsr->data->ls_seqnum == lsa->data->ls_seqnum) + { +#ifdef HAVE_OPAQUE_LSA + /* Keep this LSA entry for later reference. */ + if (IS_OPAQUE_LSA (lsr->data->type)) + listnode_add (opaque_acks, ospf_lsa_dup (lsr)); +#endif /* HAVE_OPAQUE_LSA */ + + ospf_ls_retransmit_delete (nbr, lsr); + } + + lsa->data = NULL; + ospf_lsa_discard (lsa); + } + +#ifdef HAVE_OPAQUE_LSA + if (listcount (opaque_acks) > 0) + ospf_opaque_ls_ack_received (nbr, opaque_acks); + + list_delete (opaque_acks); + return; +#endif /* HAVE_OPAQUE_LSA */ +} + +struct stream * +ospf_recv_packet (int fd, struct interface **ifp) +{ + int ret; + struct ip iph; + u_int16_t ip_len; + struct stream *ibuf; + unsigned int ifindex = 0; + struct iovec iov; + struct cmsghdr *cmsg; +#if defined (IP_PKTINFO) + struct in_pktinfo *pktinfo; +#elif defined (IP_RECVIF) + struct sockaddr_dl *pktinfo; +#else + char *pktinfo; /* dummy */ +#endif + char buff [sizeof (*cmsg) + sizeof (*pktinfo)]; + struct msghdr msgh = {NULL, 0, &iov, 1, buff, + sizeof (*cmsg) + sizeof (*pktinfo), 0}; + + ret = recvfrom (fd, (void *)&iph, sizeof (iph), MSG_PEEK, NULL, 0); + + if (ret != sizeof (iph)) + { + zlog_warn ("ospf_recv_packet packet smaller than ip header"); + return NULL; + } + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + ip_len = iph.ip_len; +#else + ip_len = ntohs (iph.ip_len); +#endif + +#if !defined(GNU_LINUX) + /* + * Kernel network code touches incoming IP header parameters, + * before protocol specific processing. + * + * 1) Convert byteorder to host representation. + * --> ip_len, ip_id, ip_off + * + * 2) Adjust ip_len to strip IP header size! + * --> If user process receives entire IP packet via RAW + * socket, it must consider adding IP header size to + * the "ip_len" field of "ip" structure. + * + * For more details, see . + */ + ip_len = ip_len + (iph.ip_hl << 2); +#endif + + ibuf = stream_new (ip_len); + iov.iov_base = STREAM_DATA (ibuf); + iov.iov_len = ip_len; + ret = recvmsg (fd, &msgh, 0); + + cmsg = CMSG_FIRSTHDR (&msgh); + + if (cmsg != NULL && //cmsg->cmsg_len == sizeof (*pktinfo) && + cmsg->cmsg_level == IPPROTO_IP && +#if defined (IP_PKTINFO) + cmsg->cmsg_type == IP_PKTINFO +#elif defined (IP_RECVIF) + cmsg->cmsg_type == IP_RECVIF +#else + 0 +#endif + ) + { +#if defined (IP_PKTINFO) + pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); + ifindex = pktinfo->ipi_ifindex; +#elif defined (IP_RECVIF) + pktinfo = (struct sockaddr_dl *)CMSG_DATA(cmsg); + ifindex = pktinfo->sdl_index; +#else + ifindex = 0; +#endif + } + + *ifp = if_lookup_by_index (ifindex); + + if (ret != ip_len) + { + zlog_warn ("ospf_recv_packet short read. " + "ip_len %d bytes read %d", ip_len, ret); + stream_free (ibuf); + return NULL; + } + + return ibuf; +} + +struct ospf_interface * +ospf_associate_packet_vl (struct interface *ifp, struct ospf_interface *oi, + struct ip *iph, struct ospf_header *ospfh) +{ + struct ospf_interface *rcv_oi; + listnode node; + struct ospf_vl_data *vl_data; + struct ospf_area *vl_area; + + if (IN_MULTICAST (ntohl (iph->ip_dst.s_addr)) || + !OSPF_IS_AREA_BACKBONE (ospfh)) + return oi; + + if ((rcv_oi = oi) == NULL) + { + if ((rcv_oi = ospf_if_lookup_by_local_addr (ifp, iph->ip_dst)) == NULL) + return NULL; + } + + for (node = listhead (ospf_top->vlinks); node; nextnode (node)) + { + if ((vl_data = getdata (node)) == NULL) + continue; + + vl_area = ospf_area_lookup_by_area_id (vl_data->vl_area_id); + if (!vl_area) + continue; + + if (OSPF_AREA_SAME (&vl_area, &rcv_oi->area) && + IPV4_ADDR_SAME (&vl_data->vl_peer, &ospfh->router_id)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("associating packet with %s", + IF_NAME (vl_data->vl_oi)); + if (! CHECK_FLAG (vl_data->vl_oi->ifp->flags, IFF_UP)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("This VL is not up yet, sorry"); + return NULL; + } + + return vl_data->vl_oi; + } + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("couldn't find any VL to associate the packet with"); + + return oi; +} + +int +ospf_check_area_id (struct ospf_interface *oi, struct ospf_header *ospfh) +{ + /* Check match the Area ID of the receiving interface. */ + if (OSPF_AREA_SAME (&oi->area, &ospfh)) + return 1; + + return 0; +} + +/* Unbound socket will accept any Raw IP packets if proto is matched. + To prevent it, compare src IP address and i/f address with masking + i/f network mask. */ +int +ospf_check_network_mask (struct ospf_interface *oi, struct in_addr ip_src) +{ + struct in_addr mask, me, him; + + if (oi->type == OSPF_IFTYPE_POINTOPOINT || + oi->type == OSPF_IFTYPE_VIRTUALLINK) + return 1; + + masklen2ip (oi->address->prefixlen, &mask); + + me.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; + him.s_addr = ip_src.s_addr & mask.s_addr; + + if (IPV4_ADDR_SAME (&me, &him)) + return 1; + + return 0; +} + +int +ospf_check_auth (struct ospf_interface *oi, struct stream *ibuf, + struct ospf_header *ospfh) +{ + int ret = 0; + struct crypt_key *ck; + + switch (ntohs (ospfh->auth_type)) + { + case OSPF_AUTH_NULL: + ret = 1; + break; + case OSPF_AUTH_SIMPLE: + if (!memcmp (OSPF_IF_PARAM (oi, auth_simple), ospfh->u.auth_data, OSPF_AUTH_SIMPLE_SIZE)) + ret = 1; + else + ret = 0; + break; + case OSPF_AUTH_CRYPTOGRAPHIC: + if ((ck = getdata (OSPF_IF_PARAM (oi,auth_crypt)->tail)) == NULL) + { + ret = 0; + break; + } + + /* This is very basic, the digest processing is elsewhere */ + if (ospfh->u.crypt.auth_data_len == OSPF_AUTH_MD5_SIZE && + ospfh->u.crypt.key_id == ck->key_id && + ntohs (ospfh->length) + OSPF_AUTH_SIMPLE_SIZE <= stream_get_size (ibuf)) + ret = 1; + else + ret = 0; + break; + default: + ret = 0; + break; + } + + return ret; +} + +int +ospf_check_sum (struct ospf_header *ospfh) +{ + u_int32_t ret; + u_int16_t sum; + int in_cksum (void *ptr, int nbytes); + + /* clear auth_data for checksum. */ + memset (ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE); + + /* keep checksum and clear. */ + sum = ospfh->checksum; + memset (&ospfh->checksum, 0, sizeof (u_int16_t)); + + /* calculate checksum. */ + ret = in_cksum (ospfh, ntohs (ospfh->length)); + + if (ret != sum) + { + zlog_info ("ospf_check_sum(): checksum mismatch, my %X, his %X", + ret, sum); + return 0; + } + + return 1; +} + +/* OSPF Header verification. */ +int +ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi, + struct ip *iph, struct ospf_header *ospfh) +{ + /* check version. */ + if (ospfh->version != OSPF_VERSION) + { + zlog_warn ("interface %s: ospf_read version number mismatch.", + IF_NAME (oi)); + return -1; + } + + /* Check Area ID. */ + if (!ospf_check_area_id (oi, ospfh)) + { + zlog_warn ("interface %s: ospf_read invalid Area ID %s.", + IF_NAME (oi), inet_ntoa (ospfh->area_id)); + return -1; + } + + /* Check network mask, Silently discarded. */ + if (! ospf_check_network_mask (oi, iph->ip_src)) + { + zlog_warn ("interface %s: ospf_read network address is not same [%s]", + IF_NAME (oi), inet_ntoa (iph->ip_src)); + return -1; + } + + /* Check authentication. */ + if (ospf_auth_type (oi) != ntohs (ospfh->auth_type)) + { + zlog_warn ("interface %s: ospf_read authentication type mismatch.", + IF_NAME (oi)); + return -1; + } + + if (! ospf_check_auth (oi, ibuf, ospfh)) + { + zlog_warn ("interface %s: ospf_read authentication failed.", + IF_NAME (oi)); + return -1; + } + + /* if check sum is invalid, packet is discarded. */ + if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC) + { + if (! ospf_check_sum (ospfh)) + { + zlog_warn ("interface %s: ospf_read packet checksum error %s", + IF_NAME (oi), inet_ntoa (ospfh->router_id)); + return -1; + } + } + else + { + if (ospfh->checksum != 0) + return -1; + if (ospf_check_md5_digest (oi, ibuf, ntohs (ospfh->length)) == 0) + { + zlog_warn ("interface %s: ospf_read md5 authentication failed.", + IF_NAME (oi)); + return -1; + } + } + + return 0; +} + +/* Starting point of packet process function. */ +int +ospf_read (struct thread *thread) +{ + int ret; + struct stream *ibuf; + struct ospf *top; + struct ospf_interface *oi; + struct ip *iph; + struct ospf_header *ospfh; + u_int16_t length; + struct interface *ifp; + + /* first of all get interface pointer. */ + top = THREAD_ARG (thread); + top->t_read = NULL; + + /* read OSPF packet. */ + ibuf = ospf_recv_packet (top->fd, &ifp); + if (ibuf == NULL) + return -1; + + iph = (struct ip *) STREAM_DATA (ibuf); + + /* prepare for next packet. */ + top->t_read = thread_add_read (master, ospf_read, top, top->fd); + + /* IP Header dump. */ + /* + if (ospf_debug_packet & OSPF_DEBUG_RECV) + ospf_ip_header_dump (ibuf); + */ + /* Self-originated packet should be discarded silently. */ + if (ospf_if_lookup_by_local_addr (NULL, iph->ip_src)) + { + stream_free (ibuf); + return 0; + } + + /* Adjust size to message length. */ + stream_forward (ibuf, iph->ip_hl * 4); + + /* Get ospf packet header. */ + ospfh = (struct ospf_header *) STREAM_PNT (ibuf); + + /* associate packet with ospf interface */ + oi = ospf_if_lookup_recv_interface (iph->ip_src); + if (ifp && oi && oi->ifp != ifp) + { + zlog_warn ("Packet from [%s] received on wrong link %s", + inet_ntoa (iph->ip_src), ifp->name); + stream_free (ibuf); + return 0; + } + + if ((oi = ospf_associate_packet_vl (ifp, oi, iph, ospfh)) == NULL) + { + stream_free (ibuf); + return 0; + } + + /* + * If the received packet is destined for AllDRouters, the packet + * should be accepted only if the received ospf interface state is + * either DR or Backup -- endo. + */ + if (iph->ip_dst.s_addr == htonl (OSPF_ALLDROUTERS) + && (oi->state != ISM_DR && oi->state != ISM_Backup)) + { + zlog_info ("Packet for AllDRouters from [%s] via [%s] (ISM: %s)", + inet_ntoa (iph->ip_src), IF_NAME (oi), + LOOKUP (ospf_ism_state_msg, oi->state)); + stream_free (ibuf); + return 0; + } + + /* Show debug receiving packet. */ + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) + { + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL)) + { + zlog_info ("-----------------------------------------------------"); + ospf_packet_dump (ibuf); + } + + zlog_info ("%s received from [%s] via [%s]", + ospf_packet_type_str[ospfh->type], + inet_ntoa (ospfh->router_id), IF_NAME (oi)); + zlog_info (" src [%s],", inet_ntoa (iph->ip_src)); + zlog_info (" dst [%s]", inet_ntoa (iph->ip_dst)); + + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL)) + zlog_info ("-----------------------------------------------------"); + } + + /* Some header verification. */ + ret = ospf_verify_header (ibuf, oi, iph, ospfh); + if (ret < 0) + { + stream_free (ibuf); + return ret; + } + + stream_forward (ibuf, OSPF_HEADER_SIZE); + + /* Adjust size to message length. */ + length = ntohs (ospfh->length) - OSPF_HEADER_SIZE; + + /* Read rest of the packet and call each sort of packet routine. */ + switch (ospfh->type) + { + case OSPF_MSG_HELLO: + ospf_hello (iph, ospfh, ibuf, oi, length); + break; + case OSPF_MSG_DB_DESC: + ospf_db_desc (iph, ospfh, ibuf, oi, length); + break; + case OSPF_MSG_LS_REQ: + ospf_ls_req (iph, ospfh, ibuf, oi, length); + break; + case OSPF_MSG_LS_UPD: + ospf_ls_upd (iph, ospfh, ibuf, oi, length); + break; + case OSPF_MSG_LS_ACK: + ospf_ls_ack (iph, ospfh, ibuf, oi, length); + break; + default: + zlog (NULL, LOG_WARNING, + "interface %s: OSPF packet header type %d is illegal", + IF_NAME (oi), ospfh->type); + break; + } + + stream_free (ibuf); + return 0; +} + +/* Make OSPF header. */ +void +ospf_make_header (int type, struct ospf_interface *oi, struct stream *s) +{ + struct ospf_header *ospfh; + + ospfh = (struct ospf_header *) STREAM_DATA (s); + + ospfh->version = (u_char) OSPF_VERSION; + ospfh->type = (u_char) type; + + ospfh->router_id = ospf_top->router_id; + + ospfh->checksum = 0; + ospfh->area_id = oi->area->area_id; + ospfh->auth_type = htons (ospf_auth_type (oi)); + + memset (ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE); + + ospf_output_forward (s, OSPF_HEADER_SIZE); +} + +/* Make Authentication Data. */ +int +ospf_make_auth (struct ospf_interface *oi, struct ospf_header *ospfh) +{ + struct crypt_key *ck; + + switch (ospf_auth_type (oi)) + { + case OSPF_AUTH_NULL: + /* memset (ospfh->u.auth_data, 0, sizeof (ospfh->u.auth_data)); */ + break; + case OSPF_AUTH_SIMPLE: + memcpy (ospfh->u.auth_data, OSPF_IF_PARAM (oi, auth_simple), + OSPF_AUTH_SIMPLE_SIZE); + break; + case OSPF_AUTH_CRYPTOGRAPHIC: + /* If key is not set, then set 0. */ + if (list_isempty (OSPF_IF_PARAM (oi, auth_crypt))) + { + ospfh->u.crypt.zero = 0; + ospfh->u.crypt.key_id = 0; + ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE; + } + else + { + ck = getdata (OSPF_IF_PARAM (oi, auth_crypt)->tail); + ospfh->u.crypt.zero = 0; + ospfh->u.crypt.key_id = ck->key_id; + ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE; + } + /* note: the seq is done in ospf_make_md5_digest() */ + break; + default: + /* memset (ospfh->u.auth_data, 0, sizeof (ospfh->u.auth_data)); */ + break; + } + + return 0; +} + +/* Fill rest of OSPF header. */ +void +ospf_fill_header (struct ospf_interface *oi, + struct stream *s, u_int16_t length) +{ + struct ospf_header *ospfh; + + ospfh = (struct ospf_header *) STREAM_DATA (s); + + /* Fill length. */ + ospfh->length = htons (length); + + /* Calculate checksum. */ + if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC) + ospfh->checksum = in_cksum (ospfh, length); + else + ospfh->checksum = 0; + + /* Add Authentication Data. */ + ospf_make_auth (oi, ospfh); +} + +int +ospf_make_hello (struct ospf_interface *oi, struct stream *s) +{ + struct ospf_neighbor *nbr; + struct route_node *rn; + u_int16_t length = OSPF_HELLO_MIN_SIZE; + struct in_addr mask; + unsigned long p; + int flag = 0; + + /* Set netmask of interface. */ + if (oi->type != OSPF_IFTYPE_POINTOPOINT && + oi->type != OSPF_IFTYPE_VIRTUALLINK) + masklen2ip (oi->address->prefixlen, &mask); + else + memset ((char *) &mask, 0, sizeof (struct in_addr)); + stream_put_ipv4 (s, mask.s_addr); + + /* Set Hello Interval. */ + stream_putw (s, OSPF_IF_PARAM (oi, v_hello)); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("make_hello: options: %x, int: %s", + OPTIONS(oi), IF_NAME (oi)); + + /* Set Options. */ + stream_putc (s, OPTIONS (oi)); + + /* Set Router Priority. */ + stream_putc (s, PRIORITY (oi)); + + /* Set Router Dead Interval. */ + stream_putl (s, OSPF_IF_PARAM (oi, v_wait)); + + /* Set Designated Router. */ + stream_put_ipv4 (s, DR (oi).s_addr); + + p = s->putp; + + /* Set Backup Designated Router. */ + stream_put_ipv4 (s, BDR (oi).s_addr); + + /* Add neighbor seen. */ + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL) + /* ignore 0.0.0.0 node. */ + if (nbr->router_id.s_addr != 0) + if (nbr->state != NSM_Attempt) + /* ignore Down neighbor. */ + if (nbr->state != NSM_Down) + /* this is myself for DR election. */ + if (!IPV4_ADDR_SAME (&nbr->router_id, &ospf_top->router_id)) + { + /* Check neighbor is sane? */ + if (nbr->d_router.s_addr != 0 && + IPV4_ADDR_SAME (&nbr->d_router, &oi->address->u.prefix4) && + IPV4_ADDR_SAME (&nbr->bd_router, &oi->address->u.prefix4)) + flag = 1; + + stream_put_ipv4 (s, nbr->router_id.s_addr); + length += 4; + } + + /* Let neighbor generate BackupSeen. */ + if (flag == 1) + { + stream_set_putp (s, p); + stream_put_ipv4 (s, 0); + } + + return length; +} + +int +ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr, + struct stream *s) +{ + struct ospf_lsa *lsa; + u_int16_t length = OSPF_DB_DESC_MIN_SIZE; + u_char options; + unsigned long pp; + int i; + struct ospf_lsdb *lsdb; + + /* Set Interface MTU. */ + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + stream_putw (s, 0); + else + stream_putw (s, oi->ifp->mtu); + + /* Set Options. */ + options = OPTIONS (oi); +#ifdef HAVE_OPAQUE_LSA + if (CHECK_FLAG (ospf_top->config, OSPF_OPAQUE_CAPABLE)) + { + if (IS_SET_DD_I (nbr->dd_flags) + || CHECK_FLAG (nbr->options, OSPF_OPTION_O)) + /* + * Set O-bit in the outgoing DD packet for capablity negotiation, + * if one of following case is applicable. + * + * 1) WaitTimer expiration event triggered the neighbor state to + * change to Exstart, but no (valid) DD packet has received + * from the neighbor yet. + * + * 2) At least one DD packet with O-bit on has received from the + * neighbor. + */ + SET_FLAG (options, OSPF_OPTION_O); + } +#endif /* HAVE_OPAQUE_LSA */ + stream_putc (s, options); + + /* Keep pointer to flags. */ + pp = stream_get_putp (s); + stream_putc (s, nbr->dd_flags); + + /* Set DD Sequence Number. */ + stream_putl (s, nbr->dd_seqnum); + + if (ospf_db_summary_isempty (nbr)) + { + if (nbr->state >= NSM_Exchange) + { + nbr->dd_flags &= ~OSPF_DD_FLAG_M; + /* Set DD flags again */ + stream_set_putp (s, pp); + stream_putc (s, nbr->dd_flags); + } + return length; + } + + /* Describe LSA Header from Database Summary List. */ + lsdb = &nbr->db_sum; + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + { + struct route_table *table = lsdb->type[i].db; + struct route_node *rn; + + for (rn = route_top (table); rn; rn = route_next (rn)) + if ((lsa = rn->info) != NULL) + { +#ifdef HAVE_OPAQUE_LSA + if (IS_OPAQUE_LSA (lsa->data->type) + && (! CHECK_FLAG (options, OSPF_OPTION_O))) + { + /* Suppress advertising opaque-informations. */ + /* Remove LSA from DB summary list. */ + ospf_lsdb_delete (lsdb, lsa); + continue; + } +#endif /* HAVE_OPAQUE_LSA */ + + if (!CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD)) + { + struct lsa_header *lsah; + u_int16_t ls_age; + + /* DD packet overflows interface MTU. */ + if (length + OSPF_LSA_HEADER_SIZE > OSPF_PACKET_MAX (oi)) + break; + + /* Keep pointer to LS age. */ + lsah = (struct lsa_header *) (STREAM_DATA (s) + + stream_get_putp (s)); + + /* Proceed stream pointer. */ + stream_put (s, lsa->data, OSPF_LSA_HEADER_SIZE); + length += OSPF_LSA_HEADER_SIZE; + + /* Set LS age. */ + ls_age = LS_AGE (lsa); + lsah->ls_age = htons (ls_age); + + } + + /* Remove LSA from DB summary list. */ + ospf_lsdb_delete (lsdb, lsa); + } + } + + return length; +} + +int +ospf_make_ls_req_func (struct stream *s, u_int16_t *length, + unsigned long delta, struct ospf_neighbor *nbr, + struct ospf_lsa *lsa) +{ + struct ospf_interface *oi; + + oi = nbr->oi; + + /* LS Request packet overflows interface MTU. */ + if (*length + delta > OSPF_PACKET_MAX(oi)) + return 0; + + stream_putl (s, lsa->data->type); + stream_put_ipv4 (s, lsa->data->id.s_addr); + stream_put_ipv4 (s, lsa->data->adv_router.s_addr); + + ospf_lsa_unlock (nbr->ls_req_last); + nbr->ls_req_last = ospf_lsa_lock (lsa); + + *length += 12; + return 1; +} + +int +ospf_make_ls_req (struct ospf_neighbor *nbr, struct stream *s) +{ + struct ospf_lsa *lsa; + u_int16_t length = OSPF_LS_REQ_MIN_SIZE; + unsigned long delta = stream_get_putp(s)+12; + struct route_table *table; + struct route_node *rn; + int i; + struct ospf_lsdb *lsdb; + + lsdb = &nbr->ls_req; + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + { + table = lsdb->type[i].db; + for (rn = route_top (table); rn; rn = route_next (rn)) + if ((lsa = (rn->info)) != NULL) + if (ospf_make_ls_req_func (s, &length, delta, nbr, lsa) == 0) + { + route_unlock_node (rn); + break; + } + } + return length; +} + +int +ls_age_increment (struct ospf_lsa *lsa, int delay) +{ + int age; + + age = IS_LSA_MAXAGE (lsa) ? OSPF_LSA_MAXAGE : LS_AGE (lsa) + delay; + + return (age > OSPF_LSA_MAXAGE ? OSPF_LSA_MAXAGE : age); +} + +int +ospf_make_ls_upd (struct ospf_interface *oi, list update, struct stream *s) +{ + struct ospf_lsa *lsa; + listnode node; + u_int16_t length = OSPF_LS_UPD_MIN_SIZE; + unsigned long delta = stream_get_putp (s); + unsigned long pp; + int count = 0; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info("ospf_make_ls_upd: Start"); + + pp = stream_get_putp (s); + ospf_output_forward (s, 4); + + while ((node = listhead (update)) != NULL) + { + struct lsa_header *lsah; + u_int16_t ls_age; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info("ospf_make_ls_upd: List Iteration"); + + lsa = getdata (node); + assert (lsa); + assert (lsa->data); + + /* Check packet size. */ + if (length + delta + ntohs (lsa->data->length) > OSPF_PACKET_MAX (oi)) + break; + + /* Keep pointer to LS age. */ + lsah = (struct lsa_header *) (STREAM_DATA (s) + stream_get_putp (s)); + + /* Put LSA to Link State Request. */ + stream_put (s, lsa->data, ntohs (lsa->data->length)); + + /* Set LS age. */ + /* each hop must increment an lsa_age by transmit_delay + of OSPF interface */ + ls_age = ls_age_increment (lsa, OSPF_IF_PARAM (oi, transmit_delay)); + lsah->ls_age = htons (ls_age); + + length += ntohs (lsa->data->length); + count++; + + list_delete_node (update, node); + ospf_lsa_unlock (lsa); + } + + /* Now set #LSAs. */ + stream_set_putp (s, pp); + stream_putl (s, count); + + stream_set_putp (s, s->endp); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info("ospf_make_ls_upd: Stop"); + return length; +} + +int +ospf_make_ls_ack (struct ospf_interface *oi, list ack, struct stream *s) +{ + list rm_list; + listnode node; + u_int16_t length = OSPF_LS_ACK_MIN_SIZE; + unsigned long delta = stream_get_putp(s) + 24; + struct ospf_lsa *lsa; + + rm_list = list_new (); + + for (node = listhead (ack); node; nextnode (node)) + { + lsa = getdata (node); + assert (lsa); + + if (length + delta > OSPF_PACKET_MAX (oi)) + break; + + stream_put (s, lsa->data, OSPF_LSA_HEADER_SIZE); + length += OSPF_LSA_HEADER_SIZE; + + listnode_add (rm_list, lsa); + } + + /* Remove LSA from LS-Ack list. */ + for (node = listhead (rm_list); node; nextnode (node)) + { + lsa = (struct ospf_lsa *) getdata (node); + + listnode_delete (ack, lsa); + ospf_lsa_unlock (lsa); + } + + list_delete (rm_list); + + return length; +} + +void +ospf_hello_send_sub (struct ospf_interface *oi, struct in_addr *addr) +{ + struct ospf_packet *op; + u_int16_t length = OSPF_HEADER_SIZE; + + op = ospf_packet_new (oi->ifp->mtu); + + /* Prepare OSPF common header. */ + ospf_make_header (OSPF_MSG_HELLO, oi, op->s); + + /* Prepare OSPF Hello body. */ + length += ospf_make_hello (oi, op->s); + + /* Fill OSPF header. */ + ospf_fill_header (oi, op->s, length); + + /* Set packet length. */ + op->length = length; + + op->dst.s_addr = addr->s_addr; + + /* Add packet to the interface output queue. */ + ospf_packet_add (oi, op); + + /* Hook thread to write packet. */ + OSPF_ISM_WRITE_ON (); +} + +void +ospf_poll_send (struct ospf_nbr_nbma *nbr_nbma) +{ + struct ospf_interface *oi; + + oi = nbr_nbma->oi; + assert(oi); + + /* If this is passive interface, do not send OSPF Hello. */ + if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE) + return; + + if (oi->type != OSPF_IFTYPE_NBMA) + return; + + if (nbr_nbma->nbr != NULL && nbr_nbma->nbr->state != NSM_Down) + return; + + if (PRIORITY(oi) == 0) + return; + + if (nbr_nbma->priority == 0 + && oi->state != ISM_DR && oi->state != ISM_Backup) + return; + + ospf_hello_send_sub (oi, &nbr_nbma->addr); +} + +int +ospf_poll_timer (struct thread *thread) +{ + struct ospf_nbr_nbma *nbr_nbma; + + nbr_nbma = THREAD_ARG (thread); + nbr_nbma->t_poll = NULL; + + if (IS_DEBUG_OSPF (nsm, NSM_TIMERS)) + zlog (NULL, LOG_INFO, "NSM[%s:%s]: Timer (Poll timer expire)", + IF_NAME (nbr_nbma->oi), inet_ntoa (nbr_nbma->addr)); + + ospf_poll_send (nbr_nbma); + + if (nbr_nbma->v_poll > 0) + OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer, + nbr_nbma->v_poll); + + return 0; +} + + +int +ospf_hello_reply_timer (struct thread *thread) +{ + struct ospf_neighbor *nbr; + + nbr = THREAD_ARG (thread); + nbr->t_hello_reply = NULL; + + assert (nbr->oi); + + if (IS_DEBUG_OSPF (nsm, NSM_TIMERS)) + zlog (NULL, LOG_INFO, "NSM[%s:%s]: Timer (hello-reply timer expire)", + IF_NAME (nbr->oi), inet_ntoa (nbr->router_id)); + + ospf_hello_send_sub (nbr->oi, &nbr->address.u.prefix4); + + return 0; +} + +/* Send OSPF Hello. */ +void +ospf_hello_send (struct ospf_interface *oi) +{ + struct ospf_packet *op; + u_int16_t length = OSPF_HEADER_SIZE; + + /* If this is passive interface, do not send OSPF Hello. */ + if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE) + return; + + op = ospf_packet_new (oi->ifp->mtu); + + /* Prepare OSPF common header. */ + ospf_make_header (OSPF_MSG_HELLO, oi, op->s); + + /* Prepare OSPF Hello body. */ + length += ospf_make_hello (oi, op->s); + + /* Fill OSPF header. */ + ospf_fill_header (oi, op->s, length); + + /* Set packet length. */ + op->length = length; + + if (oi->type == OSPF_IFTYPE_NBMA) + { + struct ospf_neighbor *nbr; + struct route_node *rn; + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info)) + if (nbr != oi->nbr_self) + if (nbr->state != NSM_Down) + { + /* RFC 2328 Section 9.5.1 + If the router is not eligible to become Designated Router, + it must periodically send Hello Packets to both the + Designated Router and the Backup Designated Router (if they + exist). */ + if (PRIORITY(oi) == 0 && + IPV4_ADDR_CMP(&DR(oi), &nbr->address.u.prefix4) && + IPV4_ADDR_CMP(&BDR(oi), &nbr->address.u.prefix4)) + continue; + + /* If the router is eligible to become Designated Router, it + must periodically send Hello Packets to all neighbors that + are also eligible. In addition, if the router is itself the + Designated Router or Backup Designated Router, it must also + send periodic Hello Packets to all other neighbors. */ + + if (nbr->priority == 0 && oi->state == ISM_DROther) + continue; + /* if oi->state == Waiting, send hello to all neighbors */ + { + struct ospf_packet *op_dup; + + op_dup = ospf_packet_dup(op); + op_dup->dst = nbr->address.u.prefix4; + + /* Add packet to the interface output queue. */ + ospf_packet_add (oi, op_dup); + + OSPF_ISM_WRITE_ON (); + } + + } + ospf_packet_free (op); + } + else + { + /* Decide destination address. */ + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + op->dst.s_addr = oi->vl_data->peer_addr.s_addr; + else + op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS); + + /* Add packet to the interface output queue. */ + ospf_packet_add (oi, op); + + /* Hook thread to write packet. */ + OSPF_ISM_WRITE_ON (); + } +} + +/* Send OSPF Database Description. */ +void +ospf_db_desc_send (struct ospf_neighbor *nbr) +{ + struct ospf_interface *oi; + struct ospf_packet *op; + u_int16_t length = OSPF_HEADER_SIZE; + + oi = nbr->oi; + op = ospf_packet_new (oi->ifp->mtu); + + /* Prepare OSPF common header. */ + ospf_make_header (OSPF_MSG_DB_DESC, oi, op->s); + + /* Prepare OSPF Database Description body. */ + length += ospf_make_db_desc (oi, nbr, op->s); + + /* Fill OSPF header. */ + ospf_fill_header (oi, op->s, length); + + /* Set packet length. */ + op->length = length; + + /* Decide destination address. */ + op->dst = nbr->address.u.prefix4; + + /* Add packet to the interface output queue. */ + ospf_packet_add (oi, op); + + /* Hook thread to write packet. */ + OSPF_ISM_WRITE_ON (); + + /* Remove old DD packet, then copy new one and keep in neighbor structure. */ + if (nbr->last_send) + ospf_packet_free (nbr->last_send); + nbr->last_send = ospf_packet_dup (op); + gettimeofday (&nbr->last_send_ts, NULL); +} + +/* Re-send Database Description. */ +void +ospf_db_desc_resend (struct ospf_neighbor *nbr) +{ + struct ospf_interface *oi; + + oi = nbr->oi; + + /* Add packet to the interface output queue. */ + ospf_packet_add (oi, ospf_packet_dup (nbr->last_send)); + + /* Hook thread to write packet. */ + OSPF_ISM_WRITE_ON (); +} + +/* Send Link State Request. */ +void +ospf_ls_req_send (struct ospf_neighbor *nbr) +{ + struct ospf_interface *oi; + struct ospf_packet *op; + u_int16_t length = OSPF_HEADER_SIZE; + + oi = nbr->oi; + op = ospf_packet_new (oi->ifp->mtu); + + /* Prepare OSPF common header. */ + ospf_make_header (OSPF_MSG_LS_REQ, oi, op->s); + + /* Prepare OSPF Link State Request body. */ + length += ospf_make_ls_req (nbr, op->s); + if (length == OSPF_HEADER_SIZE) + { + ospf_packet_free (op); + return; + } + + /* Fill OSPF header. */ + ospf_fill_header (oi, op->s, length); + + /* Set packet length. */ + op->length = length; + + /* Decide destination address. */ + op->dst = nbr->address.u.prefix4; + + /* Add packet to the interface output queue. */ + ospf_packet_add (oi, op); + + /* Hook thread to write packet. */ + OSPF_ISM_WRITE_ON (); + + /* Add Link State Request Retransmission Timer. */ + OSPF_NSM_TIMER_ON (nbr->t_ls_req, ospf_ls_req_timer, nbr->v_ls_req); +} + +/* Send Link State Update with an LSA. */ +void +ospf_ls_upd_send_lsa (struct ospf_neighbor *nbr, struct ospf_lsa *lsa, + int flag) +{ + list update; + + update = list_new (); + + listnode_add (update, lsa); + ospf_ls_upd_send (nbr, update, flag); + + list_delete (update); +} + +static void +ospf_ls_upd_queue_send (struct ospf_interface *oi, list update, + struct in_addr addr) +{ + struct ospf_packet *op; + u_int16_t length = OSPF_HEADER_SIZE; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("listcount = %d, dst %s", listcount (update), inet_ntoa(addr)); + + op = ospf_packet_new (oi->ifp->mtu); + + /* Prepare OSPF common header. */ + ospf_make_header (OSPF_MSG_LS_UPD, oi, op->s); + + /* Prepare OSPF Link State Update body. */ + /* Includes Type-7 translation. */ + length += ospf_make_ls_upd (oi, update, op->s); + + /* Fill OSPF header. */ + ospf_fill_header (oi, op->s, length); + + /* Set packet length. */ + op->length = length; + + /* Decide destination address. */ + op->dst.s_addr = addr.s_addr; + + /* Add packet to the interface output queue. */ + ospf_packet_add (oi, op); + + /* Hook thread to write packet. */ + OSPF_ISM_WRITE_ON (); +} + +static int +ospf_ls_upd_send_queue_event (struct thread *thread) +{ + struct ospf_interface *oi = THREAD_ARG(thread); + struct route_node *rn; + + oi->t_ls_upd_event = NULL; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ls_upd_send_queue start"); + + for (rn = route_top (oi->ls_upd_queue); rn; rn = route_next (rn)) + { + if (rn->info == NULL) + continue; + + while (!list_isempty ((list)rn->info)) + ospf_ls_upd_queue_send (oi, rn->info, rn->p.u.prefix4); + + list_delete (rn->info); + rn->info = NULL; + + route_unlock_node (rn); + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ls_upd_send_queue stop"); + return 0; +} + +void +ospf_ls_upd_send (struct ospf_neighbor *nbr, list update, int flag) +{ + struct ospf_interface *oi; + struct prefix_ipv4 p; + struct route_node *rn; + listnode n; + + oi = nbr->oi; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + + /* Decide destination address. */ + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + p.prefix = oi->vl_data->peer_addr; + else if (flag == OSPF_SEND_PACKET_DIRECT) + p.prefix = nbr->address.u.prefix4; + else if (oi->state == ISM_DR || oi->state == ISM_Backup) + p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS); + else if ((oi->type == OSPF_IFTYPE_POINTOPOINT) + && (flag == OSPF_SEND_PACKET_INDIRECT)) + p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS); + else + p.prefix.s_addr = htonl (OSPF_ALLDROUTERS); + + if (oi->type == OSPF_IFTYPE_NBMA) + { + if (flag == OSPF_SEND_PACKET_INDIRECT) + zlog_warn ("* LS-Update is directly sent on NBMA network."); + if (IPV4_ADDR_SAME(&oi->address->u.prefix4, &p.prefix.s_addr)) + zlog_warn ("* LS-Update is sent to myself."); + } + + rn = route_node_get (oi->ls_upd_queue, (struct prefix *) &p); + + if (rn->info == NULL) + rn->info = list_new (); + + for (n = listhead (update); n; nextnode (n)) + listnode_add (rn->info, ospf_lsa_lock (getdata (n))); + + if (oi->t_ls_upd_event == NULL) + oi->t_ls_upd_event = + thread_add_event (master, ospf_ls_upd_send_queue_event, oi, 0); +} + +static void +ospf_ls_ack_send_list (struct ospf_interface *oi, list ack, struct in_addr dst) +{ + struct ospf_packet *op; + u_int16_t length = OSPF_HEADER_SIZE; + + op = ospf_packet_new (oi->ifp->mtu); + + /* Prepare OSPF common header. */ + ospf_make_header (OSPF_MSG_LS_ACK, oi, op->s); + + /* Prepare OSPF Link State Acknowledgment body. */ + length += ospf_make_ls_ack (oi, ack, op->s); + + /* Fill OSPF header. */ + ospf_fill_header (oi, op->s, length); + + /* Set packet length. */ + op->length = length; + + /* Set destination IP address. */ + op->dst = dst; + + /* Add packet to the interface output queue. */ + ospf_packet_add (oi, op); + + /* Hook thread to write packet. */ + OSPF_ISM_WRITE_ON (); +} + +static int +ospf_ls_ack_send_event (struct thread *thread) +{ + struct ospf_interface *oi = THREAD_ARG (thread); + + oi->t_ls_ack_direct = NULL; + + while (listcount (oi->ls_ack_direct.ls_ack)) + ospf_ls_ack_send_list (oi, oi->ls_ack_direct.ls_ack, + oi->ls_ack_direct.dst); + + return 0; +} + +void +ospf_ls_ack_send (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + struct ospf_interface *oi = nbr->oi; + + if (listcount (oi->ls_ack_direct.ls_ack) == 0) + oi->ls_ack_direct.dst = nbr->address.u.prefix4; + + listnode_add (oi->ls_ack_direct.ls_ack, ospf_lsa_lock (lsa)); + + if (oi->t_ls_ack_direct == NULL) + oi->t_ls_ack_direct = + thread_add_event (master, ospf_ls_ack_send_event, oi, 0); +} + +/* Send Link State Acknowledgment delayed. */ +void +ospf_ls_ack_send_delayed (struct ospf_interface *oi) +{ + struct in_addr dst; + + /* Decide destination address. */ + /* RFC2328 Section 13.5 On non-broadcast + networks, delayed Link State Acknowledgment packets must be + unicast separately over each adjacency (i.e., neighbor whose + state is >= Exchange). */ + if (oi->type == OSPF_IFTYPE_NBMA) + { + struct ospf_neighbor *nbr; + struct route_node *rn; + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL) + if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange) + while (listcount (oi->ls_ack)) + ospf_ls_ack_send_list (oi, oi->ls_ack, nbr->address.u.prefix4); + return; + } + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + dst.s_addr = oi->vl_data->peer_addr.s_addr; + else if (oi->state == ISM_DR || oi->state == ISM_Backup) + dst.s_addr = htonl (OSPF_ALLSPFROUTERS); + else if (oi->type == OSPF_IFTYPE_POINTOPOINT) + dst.s_addr = htonl (OSPF_ALLSPFROUTERS); + else + dst.s_addr = htonl (OSPF_ALLDROUTERS); + + while (listcount (oi->ls_ack)) + ospf_ls_ack_send_list (oi, oi->ls_ack, dst); +} diff --git a/ospfd/ospf_packet.h b/ospfd/ospf_packet.h new file mode 100644 index 00000000..81a104c6 --- /dev/null +++ b/ospfd/ospf_packet.h @@ -0,0 +1,171 @@ +/* + * OSPF Sending and Receiving OSPF Packets. + * Copyright (C) 1999 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_PACKET_H +#define _ZEBRA_OSPF_PACKET_H + +#define OSPF_HEADER_SIZE 24 +#define OSPF_AUTH_SIMPLE_SIZE 8 +#define OSPF_AUTH_MD5_SIZE 16 + +#define OSPF_MAX_PACKET_SIZE 65535 /* includes IP Header size. */ +#define OSPF_HELLO_MIN_SIZE 20 /* not including neighbors */ +#define OSPF_DB_DESC_MIN_SIZE 8 +#define OSPF_LS_REQ_MIN_SIZE 0 +#define OSPF_LS_UPD_MIN_SIZE 4 +#define OSPF_LS_ACK_MIN_SIZE 0 + +#define OSPF_MSG_HELLO 1 /* OSPF Hello Message. */ +#define OSPF_MSG_DB_DESC 2 /* OSPF Database Descriptoin Message. */ +#define OSPF_MSG_LS_REQ 3 /* OSPF Link State Request Message. */ +#define OSPF_MSG_LS_UPD 4 /* OSPF Link State Update Message. */ +#define OSPF_MSG_LS_ACK 5 /* OSPF Link State Acknoledgement Message. */ + +#define OSPF_SEND_PACKET_DIRECT 1 +#define OSPF_SEND_PACKET_INDIRECT 2 + +#ifdef HAVE_NSSA +#define OSPF_SEND_PACKET_LOOP 3 +#endif /* HAVE_NSSA */ + +#define OSPF_HELLO_REPLY_DELAY 1 + +struct ospf_packet +{ + struct ospf_packet *next; + + /* Pointer to data stream. */ + struct stream *s; + + /* IP destination address. */ + struct in_addr dst; + + /* OSPF packet length. */ + u_int16_t length; +}; + +/* OSPF packet queue structure. */ +struct ospf_fifo +{ + unsigned long count; + + struct ospf_packet *head; + struct ospf_packet *tail; +}; + +/* OSPF packet header structure. */ +struct ospf_header +{ + u_char version; /* OSPF Version. */ + u_char type; /* Packet Type. */ + u_int16_t length; /* Packet Length. */ + struct in_addr router_id; /* Router ID. */ + struct in_addr area_id; /* Area ID. */ + u_int16_t checksum; /* Check Sum. */ + u_int16_t auth_type; /* Authentication Type. */ + /* Authentication Data. */ + union + { + /* Simple Authentication. */ + u_char auth_data [OSPF_AUTH_SIMPLE_SIZE]; + /* Cryptographic Authentication. */ + struct + { + u_int16_t zero; /* Should be 0. */ + u_char key_id; /* Key ID. */ + u_char auth_data_len; /* Auth Data Length. */ + u_int32_t crypt_seqnum; /* Cryptographic Sequence Number. */ + } crypt; + } u; +}; + +/* OSPF Hello body format. */ +struct ospf_hello +{ + struct in_addr network_mask; + u_int16_t hello_interval; + u_char options; + u_char priority; + u_int32_t dead_interval; + struct in_addr d_router; + struct in_addr bd_router; + struct in_addr neighbors[1]; +}; + +/* OSPF Database Description body format. */ +struct ospf_db_desc +{ + u_int16_t mtu; + u_char options; + u_char flags; + u_int32_t dd_seqnum; +}; + + +/* Macros. */ +#define OSPF_PACKET_MAX(oi) ospf_packet_max (oi) +/* +#define OSPF_PACKET_MAX(oi) (((oi)->ifp->mtu - ((oi)->auth_md5 ? OSPF_AUTH_MD5_SIZE : 0)) - 88) +*/ + +#define OSPF_OUTPUT_PNT(S) ((S)->data + (S)->putp) +#define OSPF_OUTPUT_LENGTH(S) ((S)->endp) + +#define IS_SET_DD_MS(X) ((X) & OSPF_DD_FLAG_MS) +#define IS_SET_DD_M(X) ((X) & OSPF_DD_FLAG_M) +#define IS_SET_DD_I(X) ((X) & OSPF_DD_FLAG_I) +#define IS_SET_DD_ALL(X) ((X) & OSPF_DD_FLAG_ALL) + +/* Prototypes. */ +void ospf_output_forward (struct stream *, int); +struct ospf_packet *ospf_packet_new (size_t); +void ospf_packet_free (struct ospf_packet *); +struct ospf_fifo *ospf_fifo_new (); +void ospf_fifo_push (struct ospf_fifo *, struct ospf_packet *); +struct ospf_packet *ospf_fifo_pop (struct ospf_fifo *); +struct ospf_packet *ospf_fifo_head (struct ospf_fifo *); +void ospf_fifo_flush (struct ospf_fifo *); +void ospf_fifo_free (struct ospf_fifo *); +void ospf_packet_add (struct ospf_interface *, struct ospf_packet *); +void ospf_packet_delete (struct ospf_interface *); +struct stream *ospf_stream_dup (struct stream *); +struct ospf_packet *ospf_packet_dup (struct ospf_packet *); + +int ospf_read (struct thread *); +void ospf_hello_send (struct ospf_interface *); +void ospf_db_desc_send (struct ospf_neighbor *); +void ospf_db_desc_resend (struct ospf_neighbor *); +void ospf_ls_req_send (struct ospf_neighbor *); +void ospf_ls_upd_send_lsa (struct ospf_neighbor *, struct ospf_lsa *, int); +void ospf_ls_upd_send (struct ospf_neighbor *, list, int); +void ospf_ls_ack_send (struct ospf_neighbor *, struct ospf_lsa *); +void ospf_ls_ack_send_delayed (struct ospf_interface *); +void ospf_ls_retransmit (struct ospf_interface *, struct ospf_lsa *); +void ospf_ls_req_event (struct ospf_neighbor *); + +int ospf_ls_upd_timer (struct thread *); +int ospf_ls_ack_timer (struct thread *); +int ospf_poll_timer (struct thread *); +int ospf_hello_reply_timer (struct thread *); +void ospf_hello_send_sub (struct ospf_interface *, struct in_addr *); + +#endif /* _ZEBRA_OSPF_PACKET_H */ diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c new file mode 100644 index 00000000..96f7531f --- /dev/null +++ b/ospfd/ospf_route.c @@ -0,0 +1,1026 @@ +/* + * OSPF routing table. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "table.h" +#include "memory.h" +#include "linklist.h" +#include "log.h" +#include "if.h" +#include "command.h" +#include "sockunion.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_dump.h" + +struct ospf_route * +ospf_route_new () +{ + struct ospf_route *new; + + new = XCALLOC (MTYPE_OSPF_ROUTE, sizeof (struct ospf_route)); + + new->ctime = time (NULL); + new->mtime = new->ctime; + + return new; +} + +void +ospf_route_free (struct ospf_route *or) +{ + listnode node; + + if (or->path) + { + for (node = listhead (or->path); node; nextnode (node)) + ospf_path_free (node->data); + + list_delete (or->path); + } + + XFREE (MTYPE_OSPF_ROUTE, or); +} + +struct ospf_path * +ospf_path_new () +{ + struct ospf_path *new; + + new = XCALLOC (MTYPE_OSPF_PATH, sizeof (struct ospf_path)); + + return new; +} + +struct ospf_path * +ospf_path_dup (struct ospf_path *path) +{ + struct ospf_path *new; + + new = ospf_path_new (); + memcpy (new, path, sizeof (struct ospf_path)); + + return new; +} + +void +ospf_path_free (struct ospf_path *op) +{ + XFREE (MTYPE_OSPF_PATH, op); +} + +void +ospf_route_delete (struct route_table *rt) +{ + struct route_node *rn; + struct ospf_route *or; + + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((or = rn->info) != NULL) + { + if (or->type == OSPF_DESTINATION_NETWORK) + ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, + or); + else if (or->type == OSPF_DESTINATION_DISCARD) + ospf_zebra_delete_discard ((struct prefix_ipv4 *) &rn->p); + } +} + +void +ospf_route_table_free (struct route_table *rt) +{ + struct route_node *rn; + struct ospf_route *or; + + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((or = rn->info) != NULL) + { + ospf_route_free (or); + + rn->info = NULL; + route_unlock_node (rn); + } + + route_table_finish (rt); +} + +/* If a prefix and a nexthop match any route in the routing table, + then return 1, otherwise return 0. */ +int +ospf_route_match_same (struct route_table *rt, struct prefix_ipv4 *prefix, + struct ospf_route *newor) +{ + struct route_node *rn; + struct ospf_route *or; + struct ospf_path *op; + struct ospf_path *newop; + listnode n1; + listnode n2; + + if (! rt || ! prefix) + return 0; + + rn = route_node_lookup (rt, (struct prefix *) prefix); + if (! rn || ! rn->info) + return 0; + + route_unlock_node (rn); + + or = rn->info; + if (or->type == newor->type && or->cost == newor->cost) + { + if (or->type == OSPF_DESTINATION_NETWORK) + { + if (or->path->count != newor->path->count) + return 0; + + /* Check each path. */ + for (n1 = listhead (or->path), n2 = listhead (newor->path); + n1 && n2; nextnode (n1), nextnode (n2)) + { + op = getdata (n1); + newop = getdata (n2); + + if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop)) + return 0; + } + return 1; + } + else if (prefix_same (&rn->p, (struct prefix *) prefix)) + return 1; + } + return 0; +} + +/* rt: Old, cmprt: New */ +void +ospf_route_delete_uniq (struct route_table *rt, struct route_table *cmprt) +{ + struct route_node *rn; + struct ospf_route *or; + + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((or = rn->info) != NULL) + if (or->path_type == OSPF_PATH_INTRA_AREA || + or->path_type == OSPF_PATH_INTER_AREA) + { + if (or->type == OSPF_DESTINATION_NETWORK) + { + if (! ospf_route_match_same (cmprt, + (struct prefix_ipv4 *) &rn->p, or)) + ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or); + } + else if (or->type == OSPF_DESTINATION_DISCARD) + if (! ospf_route_match_same (cmprt, + (struct prefix_ipv4 *) &rn->p, or)) + ospf_zebra_delete_discard ((struct prefix_ipv4 *) &rn->p); + } +} + +/* Install routes to table. */ +void +ospf_route_install (struct route_table *rt) +{ + struct route_node *rn; + struct ospf_route *or; + + /* rt contains new routing table, new_table contains an old one. + updating pointers */ + if (ospf_top->old_table) + ospf_route_table_free (ospf_top->old_table); + + ospf_top->old_table = ospf_top->new_table; + ospf_top->new_table = rt; + + /* Delete old routes. */ + if (ospf_top->old_table) + ospf_route_delete_uniq (ospf_top->old_table, rt); + + /* Install new routes. */ + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((or = rn->info) != NULL) + { + if (or->type == OSPF_DESTINATION_NETWORK) + { + if (! ospf_route_match_same (ospf_top->old_table, + (struct prefix_ipv4 *)&rn->p, or)) + ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or); + } + else if (or->type == OSPF_DESTINATION_DISCARD) + if (! ospf_route_match_same (ospf_top->old_table, + (struct prefix_ipv4 *) &rn->p, or)) + ospf_zebra_add_discard ((struct prefix_ipv4 *) &rn->p); + } +} + +void +ospf_intra_route_add (struct route_table *rt, struct vertex *v, + struct ospf_area *area) +{ + struct route_node *rn; + struct ospf_route *or; + struct prefix_ipv4 p; + struct ospf_path *path; + struct vertex_nexthop *nexthop; + listnode nnode; + + p.family = AF_INET; + p.prefix = v->id; + if (v->type == OSPF_VERTEX_ROUTER) + p.prefixlen = IPV4_MAX_BITLEN; + else + { + struct network_lsa *lsa = (struct network_lsa *) v->lsa; + p.prefixlen = ip_masklen (lsa->mask); + } + apply_mask_ipv4 (&p); + + rn = route_node_get (rt, (struct prefix *) &p); + if (rn->info) + { + zlog_warn ("Same routing information exists for %s", inet_ntoa (v->id)); + route_unlock_node (rn); + return; + } + + or = ospf_route_new (); + + if (v->type == OSPF_VERTEX_NETWORK) + { + or->type = OSPF_DESTINATION_NETWORK; + or->path = list_new (); + + for (nnode = listhead (v->nexthop); nnode; nextnode (nnode)) + { + nexthop = getdata (nnode); + path = ospf_path_new (); + path->nexthop = nexthop->router; + listnode_add (or->path, path); + } + } + else + or->type = OSPF_DESTINATION_ROUTER; + + or->id = v->id; + or->u.std.area_id = area->area_id; +#ifdef HAVE_NSSA + or->u.std.external_routing= area->external_routing; +#endif /* HAVE_NSSA */ + or->path_type = OSPF_PATH_INTRA_AREA; + or->cost = v->distance; + + rn->info = or; +} + +/* RFC2328 16.1. (4). For "router". */ +void +ospf_intra_add_router (struct route_table *rt, struct vertex *v, + struct ospf_area *area) +{ + struct route_node *rn; + struct ospf_route *or; + struct prefix_ipv4 p; + struct router_lsa *lsa; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_router: Start"); + + lsa = (struct router_lsa *) v->lsa; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_router: LS ID: %s", + inet_ntoa (lsa->header.id)); + + ospf_vl_up_check (area, lsa->header.id, v); + + if (!CHECK_FLAG (lsa->flags, ROUTER_LSA_SHORTCUT)) + area->shortcut_capability = 0; + + /* If the newly added vertex is an area border router or AS boundary + router, a routing table entry is added whose destination type is + "router". */ + if (! IS_ROUTER_LSA_BORDER (lsa) && ! IS_ROUTER_LSA_EXTERNAL (lsa)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_router: " + "this router is neither ASBR nor ABR, skipping it"); + return; + } + + /* Update ABR and ASBR count in this area. */ + if (IS_ROUTER_LSA_BORDER (lsa)) + area->abr_count++; + if (IS_ROUTER_LSA_EXTERNAL (lsa)) + area->asbr_count++; + + /* The Options field found in the associated router-LSA is copied + into the routing table entry's Optional capabilities field. Call + the newly added vertex Router X. */ + or = ospf_route_new (); + + or->id = v->id; + or->u.std.area_id = area->area_id; +#ifdef HAVE_NSSA + or->u.std.external_routing = area->external_routing; +#endif /* HAVE_NSSA */ + or->path_type = OSPF_PATH_INTRA_AREA; + or->cost = v->distance; + or->type = OSPF_DESTINATION_ROUTER; + or->u.std.origin = (struct lsa_header *) lsa; + or->u.std.options = lsa->header.options; + or->u.std.flags = lsa->flags; + + /* If Router X is the endpoint of one of the calculating router's + virtual links, and the virtual link uses Area A as Transit area: + the virtual link is declared up, the IP address of the virtual + interface is set to the IP address of the outgoing interface + calculated above for Router X, and the virtual neighbor's IP + address is set to Router X's interface address (contained in + Router X's router-LSA) that points back to the root of the + shortest- path tree; equivalently, this is the interface that + points back to Router X's parent vertex on the shortest-path tree + (similar to the calculation in Section 16.1.1). */ + + p.family = AF_INET; + p.prefix = v->id; + p.prefixlen = IPV4_MAX_BITLEN; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_router: talking about %s/%d", + inet_ntoa (p.prefix), p.prefixlen); + + rn = route_node_get (rt, (struct prefix *) &p); + + /* Note that we keep all routes to ABRs and ASBRs, not only the best */ + if (rn->info == NULL) + rn->info = list_new (); + else + route_unlock_node (rn); + + ospf_route_copy_nexthops_from_vertex (or, v); + + listnode_add (rn->info, or); + + zlog_info ("ospf_intra_add_router: Start"); +} + +/* RFC2328 16.1. (4). For transit network. */ +void +ospf_intra_add_transit (struct route_table *rt, struct vertex *v, + struct ospf_area *area) +{ + struct route_node *rn; + struct ospf_route *or; + struct prefix_ipv4 p; + struct network_lsa *lsa; + + lsa = (struct network_lsa*) v->lsa; + + /* If the newly added vertex is a transit network, the routing table + entry for the network is located. The entry's Destination ID is + the IP network number, which can be obtained by masking the + Vertex ID (Link State ID) with its associated subnet mask (found + in the body of the associated network-LSA). */ + p.family = AF_INET; + p.prefix = v->id; + p.prefixlen = ip_masklen (lsa->mask); + apply_mask_ipv4 (&p); + + rn = route_node_get (rt, (struct prefix *) &p); + + /* If the routing table entry already exists (i.e., there is already + an intra-area route to the destination installed in the routing + table), multiple vertices have mapped to the same IP network. + For example, this can occur when a new Designated Router is being + established. In this case, the current routing table entry + should be overwritten if and only if the newly found path is just + as short and the current routing table entry's Link State Origin + has a smaller Link State ID than the newly added vertex' LSA. */ + if (rn->info) + { + struct ospf_route *cur_or; + + route_unlock_node (rn); + cur_or = rn->info; + + if (v->distance > cur_or->cost || + IPV4_ADDR_CMP (&cur_or->u.std.origin->id, &lsa->header.id) > 0) + return; + + ospf_route_free (rn->info); + } + + or = ospf_route_new (); + + or->id = v->id; + or->u.std.area_id = area->area_id; +#ifdef HAVE_NSSA + or->u.std.external_routing = area->external_routing; +#endif /* HAVE_NSSA */ + or->path_type = OSPF_PATH_INTRA_AREA; + or->cost = v->distance; + or->type = OSPF_DESTINATION_NETWORK; + or->u.std.origin = (struct lsa_header *) lsa; + + ospf_route_copy_nexthops_from_vertex (or, v); + + rn->info = or; +} + +/* RFC2328 16.1. second stage. */ +void +ospf_intra_add_stub (struct route_table *rt, struct router_lsa_link *link, + struct vertex *v, struct ospf_area *area) +{ + u_int32_t cost; + struct route_node *rn; + struct ospf_route *or; + struct prefix_ipv4 p; + struct router_lsa *lsa; + struct ospf_interface *oi; + struct ospf_path *path; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): Start"); + + lsa = (struct router_lsa *) v->lsa; + + p.family = AF_INET; + p.prefix = link->link_id; + p.prefixlen = ip_masklen (link->link_data); + apply_mask_ipv4 (&p); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): processing route to %s/%d", + inet_ntoa (p.prefix), p.prefixlen); + + /* (1) Calculate the distance D of stub network from the root. D is + equal to the distance from the root to the router vertex + (calculated in stage 1), plus the stub network link's advertised + cost. */ + cost = v->distance + ntohs (link->m[0].metric); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): calculated cost is %d + %d = %d", + v->distance, ntohs(link->m[0].metric), cost); + + rn = route_node_get (rt, (struct prefix *) &p); + + /* Lookup current routing table. */ + if (rn->info) + { + struct ospf_route *cur_or; + + route_unlock_node (rn); + + cur_or = rn->info; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): " + "another route to the same prefix found"); + + /* Compare this distance to the current best cost to the stub + network. This is done by looking up the stub network's + current routing table entry. If the calculated distance D is + larger, go on to examine the next stub network link in the + LSA. */ + if (cost > cur_or->cost) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): old route is better, exit"); + return; + } + + /* (2) If this step is reached, the stub network's routing table + entry must be updated. Calculate the set of next hops that + would result from using the stub network link. This + calculation is shown in Section 16.1.1; input to this + calculation is the destination (the stub network) and the + parent vertex (the router vertex). If the distance D is the + same as the current routing table cost, simply add this set + of next hops to the routing table entry's list of next hops. + In this case, the routing table already has a Link State + Origin. If this Link State Origin is a router-LSA whose Link + State ID is smaller than V's Router ID, reset the Link State + Origin to V's router-LSA. */ + + if (cost == cur_or->cost) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): routes are equal, merge"); + + ospf_route_copy_nexthops_from_vertex (cur_or, v); + + if (IPV4_ADDR_CMP (&cur_or->u.std.origin->id, &lsa->header.id) < 0) + cur_or->u.std.origin = (struct lsa_header *) lsa; + return; + } + + /* Otherwise D is smaller than the routing table cost. + Overwrite the current routing table entry by setting the + routing table entry's cost to D, and by setting the entry's + list of next hops to the newly calculated set. Set the + routing table entry's Link State Origin to V's router-LSA. + Then go on to examine the next stub network link. */ + + if (cost < cur_or->cost) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): new route is better, set it"); + + cur_or->cost = cost; + + list_delete (cur_or->path); + cur_or->path = NULL; + + ospf_route_copy_nexthops_from_vertex (cur_or, v); + + cur_or->u.std.origin = (struct lsa_header *) lsa; + return; + } + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): installing new route"); + + or = ospf_route_new (); + + or->id = v->id; + or->u.std.area_id = area->area_id; +#ifdef HAVE_NSSA + or->u.std.external_routing = area->external_routing; +#endif /* HAVE_NSSA */ + or->path_type = OSPF_PATH_INTRA_AREA; + or->cost = cost; + or->type = OSPF_DESTINATION_NETWORK; + or->u.std.origin = (struct lsa_header *) lsa; + or->path = list_new (); + + /* Nexthop is depend on connection type. */ + if (v != area->spf) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): this network is on remote router"); + ospf_route_copy_nexthops_from_vertex (or, v); + } + else + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): this network is on this router"); + + if ((oi = ospf_if_lookup_by_prefix (&p))) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): the interface is %s", + IF_NAME (oi)); + + path = ospf_path_new (); + path->nexthop.s_addr = 0; + path->oi = oi; + listnode_add (or->path, path); + } + else + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): where's the interface ?"); + } + } + + rn->info = or; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info("ospf_intra_add_stub(): Stop"); +} + +char *ospf_path_type_str[] = +{ + "unknown-type", + "intra-area", + "inter-area", + "type1-external", + "type2-external" +}; + +void +ospf_route_table_dump (struct route_table *rt) +{ + struct route_node *rn; + struct ospf_route *or; + char buf1[BUFSIZ]; + char buf2[BUFSIZ]; + listnode pnode; + struct ospf_path *path; + +#if 0 + zlog_info ("Type Dest Area Path Type Cost Next Adv."); + zlog_info (" Hop(s) Router(s)"); +#endif /* 0 */ + + zlog_info ("========== OSPF routing table =========="); + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((or = rn->info) != NULL) + { + if (or->type == OSPF_DESTINATION_NETWORK) + { + zlog_info ("N %s/%d\t%s\t%s\t%d", + inet_ntop (AF_INET, &rn->p.u.prefix4, buf1, BUFSIZ), + rn->p.prefixlen, + inet_ntop (AF_INET, &or->u.std.area_id, buf2, + BUFSIZ), + ospf_path_type_str[or->path_type], + or->cost); + for (pnode = listhead (or->path); pnode; nextnode (pnode)) + { + path = getdata (pnode); + zlog_info (" -> %s", inet_ntoa (path->nexthop)); + } + } + else + zlog_info ("R %s\t%s\t%s\t%d", + inet_ntop (AF_INET, &rn->p.u.prefix4, buf1, BUFSIZ), + inet_ntop (AF_INET, &or->u.std.area_id, buf2, + BUFSIZ), + ospf_path_type_str[or->path_type], + or->cost); + } + zlog_info ("========================================"); +} + +void +ospf_terminate () +{ + if (ospf_top) + { + if (ospf_top->new_table) + ospf_route_delete (ospf_top->new_table); + if (ospf_top->old_external_route) + ospf_route_delete (ospf_top->old_external_route); + } +} + +/* This is 16.4.1 implementation. + o Intra-area paths using non-backbone areas are always the most preferred. + o The other paths, intra-area backbone paths and inter-area paths, + are of equal preference. */ +int +ospf_asbr_route_cmp (struct ospf_route *r1, struct ospf_route *r2) +{ + u_char r1_type, r2_type; + + r1_type = r1->path_type; + r2_type = r2->path_type; + + /* If RFC1583Compat flag is on -- all paths are equal. */ + if (CHECK_FLAG (ospf_top->config, OSPF_RFC1583_COMPATIBLE)) + return 0; + + /* r1/r2 itself is backbone, and it's Inter-area path. */ + if (OSPF_IS_AREA_ID_BACKBONE (r1->u.std.area_id)) + r1_type = OSPF_PATH_INTER_AREA; + if (OSPF_IS_AREA_ID_BACKBONE (r2->u.std.area_id)) + r2_type = OSPF_PATH_INTER_AREA; + + return (r1_type - r2_type); +} + +/* Compare two routes. + ret < 0 -- r1 is better. + ret == 0 -- r1 and r2 are the same. + ret > 0 -- r2 is better. */ +int +ospf_route_cmp (struct ospf_route *r1, struct ospf_route *r2) +{ + int ret = 0; + + /* Path types of r1 and r2 are not the same. */ + if ((ret = (r1->path_type - r2->path_type))) + return ret; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Route[Compare]: Path types are the same."); + /* Path types are the same, compare any cost. */ + switch (r1->path_type) + { + case OSPF_PATH_INTRA_AREA: + case OSPF_PATH_INTER_AREA: + break; + case OSPF_PATH_TYPE1_EXTERNAL: + if (!CHECK_FLAG (ospf_top->config, OSPF_RFC1583_COMPATIBLE)) + { + ret = ospf_asbr_route_cmp (r1->u.ext.asbr, r2->u.ext.asbr); + if (ret != 0) + return ret; + } + break; + case OSPF_PATH_TYPE2_EXTERNAL: + if ((ret = (r1->u.ext.type2_cost - r2->u.ext.type2_cost))) + return ret; + + if (!CHECK_FLAG (ospf_top->config, OSPF_RFC1583_COMPATIBLE)) + { + ret = ospf_asbr_route_cmp (r1->u.ext.asbr, r2->u.ext.asbr); + if (ret != 0) + return ret; + } + break; + } + + /* Anyway, compare the costs. */ + return (r1->cost - r2->cost); +} + +int +ospf_path_exist (struct list *plist, struct in_addr nexthop, + struct ospf_interface *oi) +{ + listnode node; + struct ospf_path *path; + + for (node = listhead (plist); node; nextnode (node)) + { + path = node->data; + + if (IPV4_ADDR_SAME (&path->nexthop, &nexthop) && path->oi == oi) + return 1; + } + return 0; +} + +void +ospf_route_copy_nexthops_from_vertex (struct ospf_route *to, + struct vertex *v) +{ + listnode nnode; + struct ospf_path *path; + struct vertex_nexthop *nexthop; + + if (to->path == NULL) + to->path = list_new (); + + for (nnode = listhead (v->nexthop); nnode; nextnode (nnode)) + { + nexthop = getdata (nnode); + + if (nexthop->oi != NULL) + { + if (! ospf_path_exist (to->path, nexthop->router, nexthop->oi)) + { + path = ospf_path_new (); + path->nexthop = nexthop->router; + path->oi = nexthop->oi; + listnode_add (to->path, path); + } + } + } +} + +struct ospf_path * +ospf_path_lookup (list plist, struct ospf_path *path) +{ + listnode node; + + for (node = listhead (plist); node; nextnode (node)) + { + struct ospf_path *op = node->data; + + if (IPV4_ADDR_SAME (&op->nexthop, &path->nexthop) && + IPV4_ADDR_SAME (&op->adv_router, &path->adv_router)) + return op; + } + + return NULL; +} + +void +ospf_route_copy_nexthops (struct ospf_route *to, list from) +{ + listnode node; + + if (to->path == NULL) + to->path = list_new (); + + for (node = listhead (from); node; nextnode (node)) + /* The same routes are just discarded. */ + if (!ospf_path_lookup (to->path, node->data)) + listnode_add (to->path, ospf_path_dup (node->data)); +} + +void +ospf_route_subst_nexthops (struct ospf_route *to, list from) +{ + listnode node; + struct ospf_path *op; + + for (node = listhead (to->path); node; nextnode (node)) + if ((op = getdata (node)) != NULL) + { + ospf_path_free (op); + node->data = NULL; + } + + list_delete_all_node (to->path); + ospf_route_copy_nexthops (to, from); +} + +void +ospf_route_subst (struct route_node *rn, struct ospf_route *new_or, + struct ospf_route *over) +{ + route_lock_node (rn); + ospf_route_free (rn->info); + + ospf_route_copy_nexthops (new_or, over->path); + rn->info = new_or; + route_unlock_node (rn); +} + +void +ospf_route_add (struct route_table *rt, struct prefix_ipv4 *p, + struct ospf_route *new_or, struct ospf_route *over) +{ + struct route_node *rn; + + rn = route_node_get (rt, (struct prefix *) p); + + ospf_route_copy_nexthops (new_or, over->path); + + if (rn->info) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_route_add(): something's wrong !"); + route_unlock_node (rn); + return; + } + + rn->info = new_or; +} + +void +ospf_prune_unreachable_networks (struct route_table *rt) +{ + struct route_node *rn, *next; + struct ospf_route *or; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Pruning unreachable networks"); + + for (rn = route_top (rt); rn; rn = next) + { + next = route_next (rn); + if (rn->info != NULL) + { + or = rn->info; + if (listcount (or->path) == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Pruning route to %s/%d", + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); + + ospf_route_free (or); + rn->info = NULL; + route_unlock_node (rn); + } + } + } +} + +void +ospf_prune_unreachable_routers (struct route_table *rtrs) +{ + struct route_node *rn, *next; + struct ospf_route *or; + listnode node, nnext; + list paths; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Pruning unreachable routers"); + + for (rn = route_top (rtrs); rn; rn = next) + { + next = route_next (rn); + if ((paths = rn->info) == NULL) + continue; + + for (node = listhead (paths); node; node = nnext) + { + nnext = node->next; + + or = getdata (node); + + if (listcount (or->path) == 0) + { + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("Pruning route to rtr %s", + inet_ntoa (rn->p.u.prefix4)); + zlog_info (" via area %s", + inet_ntoa (or->u.std.area_id)); + } + + listnode_delete (paths, or); + ospf_route_free (or); + } + } + + if (listcount (paths) == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Pruning router node %s", inet_ntoa (rn->p.u.prefix4)); + + list_delete (paths); + rn->info = NULL; + route_unlock_node (rn); + } + } +} + +int +ospf_add_discard_route (struct route_table *rt, struct ospf_area *area, + struct prefix_ipv4 *p) +{ + struct route_node *rn; + struct ospf_route *or, *new_or; + + rn = route_node_get (rt, (struct prefix *) p); + + if (rn == NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_add_discard_route(): router installation error"); + return 0; + } + + if (rn->info) /* If the route to the same destination is found */ + { + route_unlock_node (rn); + + or = rn->info; + + if (or->path_type == OSPF_PATH_INTRA_AREA) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_add_discard_route(): " + "an intra-area route exists"); + return 0; + } + + if (or->type == OSPF_DESTINATION_DISCARD) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_add_discard_route(): " + "discard entry already installed"); + return 0; + } + + ospf_route_free (rn->info); + } + + new_or = ospf_route_new (); + new_or->type = OSPF_DESTINATION_DISCARD; + new_or->id.s_addr = 0; + new_or->cost = 0; + new_or->u.std.area_id = area->area_id; +#ifdef HAVE_NSSA + new_or->u.std.external_routing = area->external_routing; +#endif /* HAVE_NSSA */ + new_or->path_type = OSPF_PATH_INTER_AREA; + rn->info = new_or; + + ospf_zebra_add_discard (p); + + return 1; +} + +void +ospf_delete_discard_route (struct prefix_ipv4 *p) +{ + ospf_zebra_delete_discard(p); +} + diff --git a/ospfd/ospf_route.h b/ospfd/ospf_route.h new file mode 100644 index 00000000..81f59c48 --- /dev/null +++ b/ospfd/ospf_route.h @@ -0,0 +1,165 @@ +/* + * OSPF routing table. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_ROUTE_H +#define _ZEBRA_OSPF_ROUTE_H + +#define OSPF_DESTINATION_ROUTER 1 +#define OSPF_DESTINATION_NETWORK 2 +#define OSPF_DESTINATION_DISCARD 3 + +#define OSPF_PATH_MIN 0 +#define OSPF_PATH_INTRA_AREA 1 +#define OSPF_PATH_INTER_AREA 2 +#define OSPF_PATH_TYPE1_EXTERNAL 3 +#define OSPF_PATH_TYPE2_EXTERNAL 4 +#define OSPF_PATH_MAX 5 + +/* OSPF Path. */ +struct ospf_path +{ + struct in_addr nexthop; + struct in_addr adv_router; + struct ospf_interface *oi; +}; + +/* Below is the structure linked to every + route node. Note that for Network routing + entries a single ospf_route is kept, while + for ABRs and ASBRs (Router routing entries), + we link an instance of ospf_router_route + where a list of paths is maintained, so + + nr->info is a (struct ospf_route *) for OSPF_DESTINATION_NETWORK + but + nr->info is a (struct ospf_router_route *) for OSPF_DESTINATION_ROUTER +*/ + +struct route_standard +{ + /* Link Sate Origin. */ + struct lsa_header *origin; + + /* Associated Area. */ + struct in_addr area_id; /* The area the route belongs to */ + +#ifdef HAVE_NSSA + /* Area Type */ + int external_routing; +#endif /* HAVE_NSSA */ + + /* Optional Capability. */ + u_char options; /* Get from LSA header. */ + + /* */ + u_char flags; /* From router-LSA */ +}; + +struct route_external +{ + /* Link State Origin. */ + struct ospf_lsa *origin; + + /* Link State Cost Type2. */ + u_int32_t type2_cost; + + /* Tag value. */ + u_int32_t tag; + + /* ASBR route. */ + struct ospf_route *asbr; +}; + +struct ospf_route +{ + /* Create time. */ + time_t ctime; + + /* Modified time. */ + time_t mtime; + + /* Destination Type. */ + u_char type; + + /* Destination ID. */ /* i.e. Link State ID. */ + struct in_addr id; + + /* Address Mask. */ + struct in_addr mask; /* Only valid for networks. */ + + /* Path Type. */ + u_char path_type; + + /* List of Paths. */ + list path; + + /* Link State Cost. */ + u_int32_t cost; /* i.e. metric. */ + + /* Route specific info. */ + union + { + struct route_standard std; + struct route_external ext; + } u; +}; + +struct ospf_path *ospf_path_new (); +void ospf_path_free (struct ospf_path *op); +struct ospf_path *ospf_path_lookup (list, struct ospf_path *); +struct ospf_route *ospf_route_new (); +void ospf_route_free (struct ospf_route *or); +void ospf_route_delete (struct route_table *rt); +void ospf_route_table_free (struct route_table *rt); + +void ospf_route_install (struct route_table *); +void ospf_route_table_dump (struct route_table *); + +void ospf_intra_add_router (struct route_table *, struct vertex *, + struct ospf_area *); + +void ospf_intra_add_transit (struct route_table *, struct vertex *, + struct ospf_area *); + +void ospf_intra_add_stub (struct route_table *, struct router_lsa_link *, + struct vertex *, struct ospf_area *); + +int ospf_route_cmp (struct ospf_route *, struct ospf_route *); +void ospf_route_copy_nexthops (struct ospf_route *, list); +void ospf_route_copy_nexthops_from_vertex (struct ospf_route *, + struct vertex * ); + +void ospf_route_subst (struct route_node *, struct ospf_route *, + struct ospf_route *); +void ospf_route_add (struct route_table *, struct prefix_ipv4 *, + struct ospf_route *, struct ospf_route *); + +void ospf_route_subst_nexthops (struct ospf_route *, list); +void ospf_prune_unreachable_networks (struct route_table *); +void ospf_prune_unreachable_routers (struct route_table *); +int ospf_add_discard_route (struct route_table *, struct ospf_area *, + struct prefix_ipv4 *); +void ospf_delete_discard_route (struct prefix_ipv4 *); +int ospf_route_match_same (struct route_table *, struct prefix_ipv4 *, + struct ospf_route *); + +#endif /* _ZEBRA_OSPF_ROUTE_H */ diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c new file mode 100644 index 00000000..a2b257fa --- /dev/null +++ b/ospfd/ospf_routemap.c @@ -0,0 +1,828 @@ +/* + * Route map function of ospfd. + * Copyright (C) 2000 IP Infusion Inc. + * + * Written by Toshiaki Takada. + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "memory.h" +#include "prefix.h" +#include "table.h" +#include "routemap.h" +#include "command.h" +#include "log.h" +#include "plist.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_zebra.h" + +/* Hook function for updating route_map assignment. */ +void +ospf_route_map_update (char *name) +{ + int type; + + /* If OSPF instatnce does not exist, return right now. */ + if (!ospf_top) + return; + + /* Update route-map */ + for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) + { + if (ROUTEMAP_NAME (type) && strcmp (ROUTEMAP_NAME (type), name) == 0) + { + /* Keep old route-map. */ + struct route_map *old = ROUTEMAP (type); + + /* Update route-map. */ + ROUTEMAP (type) = route_map_lookup_by_name (ROUTEMAP_NAME (type)); + + /* No update for this distribute type. */ + if (old == NULL && ROUTEMAP (type) == NULL) + continue; + + ospf_distribute_list_update (type); + } + } +} + +void +ospf_route_map_event (route_map_event_t event, char *name) +{ + int type; + + /* If OSPF instatnce does not exist, return right now. */ + if (!ospf_top) + return; + + /* Update route-map. */ + for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) + { + if (ROUTEMAP_NAME (type) && ROUTEMAP (type) && + !strcmp (ROUTEMAP_NAME (type), name)) + { + ospf_distribute_list_update (type); + } + } +} + +/* Delete rip route map rule. */ +int +ospf_route_match_delete (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_delete_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + + return CMD_SUCCESS; +} + +int +ospf_route_match_add (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_add_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + + return CMD_SUCCESS; +} + +int +ospf_route_set_add (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_add_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + + return CMD_SUCCESS; +} + +/* Delete rip route map rule. */ +int +ospf_route_set_delete (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_delete_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + + return CMD_SUCCESS; +} + +/* `match ip netxthop ' */ +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_ip_nexthop (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; + struct external_info *ei = object; + struct prefix_ipv4 p; + + if (type == RMAP_OSPF) + { + p.family = AF_INET; + p.prefix = ei->nexthop; + p.prefixlen = IPV4_MAX_BITLEN; + + alist = access_list_lookup (AFI_IP, (char *) rule); + if (alist == NULL) + return RMAP_NOMATCH; + + return (access_list_apply (alist, &p) == FILTER_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +/* Route map `ip next-hop' match statement. `arg' should be + access-list name. */ +void * +route_match_ip_nexthop_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_ip_nexthop_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for metric matching. */ +struct route_map_rule_cmd route_match_ip_nexthop_cmd = +{ + "ip next-hop", + route_match_ip_nexthop, + route_match_ip_nexthop_compile, + route_match_ip_nexthop_free +}; + +/* `match ip next-hop prefix-list PREFIX_LIST' */ + +route_map_result_t +route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; + struct external_info *ei = object; + struct prefix_ipv4 p; + + if (type == RMAP_OSPF) + { + p.family = AF_INET; + p.prefix = ei->nexthop; + p.prefixlen = IPV4_MAX_BITLEN; + + plist = prefix_list_lookup (AFI_IP, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, &p) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ip_next_hop_prefix_list_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ip_next_hop_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = +{ + "ip next-hop prefix-list", + route_match_ip_next_hop_prefix_list, + route_match_ip_next_hop_prefix_list_compile, + route_match_ip_next_hop_prefix_list_free +}; + +/* `match ip address IP_ACCESS_LIST' */ +/* Match function should return 1 if match is success else return + zero. */ +route_map_result_t +route_match_ip_address (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; + /* struct prefix_ipv4 match; */ + + if (type == RMAP_OSPF) + { + alist = access_list_lookup (AFI_IP, (char *) rule); + if (alist == NULL) + return RMAP_NOMATCH; + + return (access_list_apply (alist, prefix) == FILTER_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +/* Route map `ip address' match statement. `arg' should be + access-list name. */ +void * +route_match_ip_address_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_ip_address_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip address matching. */ +struct route_map_rule_cmd route_match_ip_address_cmd = +{ + "ip address", + route_match_ip_address, + route_match_ip_address_compile, + route_match_ip_address_free +}; + +/* `match ip address prefix-list PREFIX_LIST' */ +route_map_result_t +route_match_ip_address_prefix_list (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; + + if (type == RMAP_OSPF) + { + plist = prefix_list_lookup (AFI_IP, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ip_address_prefix_list_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ip_address_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = +{ + "ip address prefix-list", + route_match_ip_address_prefix_list, + route_match_ip_address_prefix_list_compile, + route_match_ip_address_prefix_list_free +}; + +/* `match interface IFNAME' */ +/* Match function should return 1 if match is success else return + zero. */ +route_map_result_t +route_match_interface (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct interface *ifp; + struct external_info *ei; + + if (type == RMAP_OSPF) + { + ei = object; + ifp = if_lookup_by_name ((char *)rule); + + if (ifp == NULL || ifp->ifindex != ei->ifindex) + return RMAP_NOMATCH; + + return RMAP_MATCH; + } + return RMAP_NOMATCH; +} + +/* Route map `interface' match statement. `arg' should be + interface name. */ +void * +route_match_interface_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `interface' value. */ +void +route_match_interface_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip address matching. */ +struct route_map_rule_cmd route_match_interface_cmd = +{ + "interface", + route_match_interface, + route_match_interface_compile, + route_match_interface_free +}; + +/* `set metric METRIC' */ +/* Set metric to attribute. */ +route_map_result_t +route_set_metric (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_int32_t *metric; + struct external_info *ei; + + if (type == RMAP_OSPF) + { + /* Fetch routemap's rule information. */ + metric = rule; + ei = object; + + /* Set metric out value. */ + ei->route_map_set.metric = *metric; + } + return RMAP_OKAY; +} + +/* set metric compilation. */ +void * +route_set_metric_compile (char *arg) +{ + u_int32_t *metric; + + metric = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); + *metric = atoi (arg); + + if (*metric >= 0) + return metric; + + XFREE (MTYPE_ROUTE_MAP_COMPILED, metric); + return NULL; +} + +/* Free route map's compiled `set metric' value. */ +void +route_set_metric_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set metric rule structure. */ +struct route_map_rule_cmd route_set_metric_cmd = +{ + "metric", + route_set_metric, + route_set_metric_compile, + route_set_metric_free, +}; + +/* `set metric-type TYPE' */ +/* Set metric-type to attribute. */ +route_map_result_t +route_set_metric_type (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_int32_t *metric_type; + struct external_info *ei; + + if (type == RMAP_OSPF) + { + /* Fetch routemap's rule information. */ + metric_type = rule; + ei = object; + + /* Set metric out value. */ + ei->route_map_set.metric_type = *metric_type; + } + return RMAP_OKAY; +} + +/* set metric-type compilation. */ +void * +route_set_metric_type_compile (char *arg) +{ + u_int32_t *metric_type; + + metric_type = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); + if (strcmp (arg, "type-1") == 0) + *metric_type = EXTERNAL_METRIC_TYPE_1; + else if (strcmp (arg, "type-2") == 0) + *metric_type = EXTERNAL_METRIC_TYPE_2; + + if (*metric_type == EXTERNAL_METRIC_TYPE_1 || + *metric_type == EXTERNAL_METRIC_TYPE_2) + return metric_type; + + XFREE (MTYPE_ROUTE_MAP_COMPILED, metric_type); + return NULL; +} + +/* Free route map's compiled `set metric-type' value. */ +void +route_set_metric_type_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set metric rule structure. */ +struct route_map_rule_cmd route_set_metric_type_cmd = +{ + "metric-type", + route_set_metric_type, + route_set_metric_type_compile, + route_set_metric_type_free, +}; + +DEFUN (match_ip_nexthop, + match_ip_nexthop_cmd, + "match ip next-hop (<1-199>|<1300-2699>|WORD)", + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP access-list name\n") +{ + return ospf_route_match_add (vty, vty->index, "ip next-hop", argv[0]); +} + +DEFUN (no_match_ip_nexthop, + no_match_ip_nexthop_cmd, + "no match ip next-hop", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n") +{ + if (argc == 0) + return ospf_route_match_delete (vty, vty->index, "ip next-hop", NULL); + + return ospf_route_match_delete (vty, vty->index, "ip next-hop", argv[0]); +} + +ALIAS (no_match_ip_nexthop, + no_match_ip_nexthop_val_cmd, + "no match ip next-hop (<1-199>|<1300-2699>|WORD)", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP access-list name\n") + +DEFUN (match_ip_next_hop_prefix_list, + match_ip_next_hop_prefix_list_cmd, + "match ip next-hop prefix-list WORD", + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + return ospf_route_match_add (vty, vty->index, "ip next-hop prefix-list", + argv[0]); +} + +DEFUN (no_match_ip_next_hop_prefix_list, + no_match_ip_next_hop_prefix_list_cmd, + "no match ip next-hop prefix-list", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "Match entries of prefix-lists\n") +{ + if (argc == 0) + return ospf_route_match_delete (vty, vty->index, "ip next-hop prefix-list", + NULL); + return ospf_route_match_delete (vty, vty->index, "ip next-hop prefix-list", + argv[0]); +} + +ALIAS (no_match_ip_next_hop_prefix_list, + no_match_ip_next_hop_prefix_list_val_cmd, + "no match ip next-hop prefix-list WORD", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") + +DEFUN (match_ip_address, + match_ip_address_cmd, + "match ip address (<1-199>|<1300-2699>|WORD)", + MATCH_STR + IP_STR + "Match address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP access-list name\n") +{ + return ospf_route_match_add (vty, vty->index, "ip address", argv[0]); +} + +DEFUN (no_match_ip_address, + no_match_ip_address_cmd, + "no match ip address", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n") +{ + if (argc == 0) + return ospf_route_match_delete (vty, vty->index, "ip address", NULL); + + return ospf_route_match_delete (vty, vty->index, "ip address", argv[0]); +} + +ALIAS (no_match_ip_address, + no_match_ip_address_val_cmd, + "no match ip address (<1-199>|<1300-2699>|WORD)", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP access-list name\n") + +DEFUN (match_ip_address_prefix_list, + match_ip_address_prefix_list_cmd, + "match ip address prefix-list WORD", + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + return ospf_route_match_add (vty, vty->index, "ip address prefix-list", + argv[0]); +} + +DEFUN (no_match_ip_address_prefix_list, + no_match_ip_address_prefix_list_cmd, + "no match ip address prefix-list", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n") +{ + if (argc == 0) + return ospf_route_match_delete (vty, vty->index, "ip address prefix-list", + NULL); + return ospf_route_match_delete (vty, vty->index, "ip address prefix-list", + argv[0]); +} + +ALIAS (no_match_ip_address_prefix_list, + no_match_ip_address_prefix_list_val_cmd, + "no match ip address prefix-list WORD", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") + +DEFUN (match_interface, + match_interface_cmd, + "match interface WORD", + MATCH_STR + "Match first hop interface of route\n" + "Interface name\n") +{ + return ospf_route_match_add (vty, vty->index, "interface", argv[0]); +} + +DEFUN (no_match_interface, + no_match_interface_cmd, + "no match interface", + NO_STR + MATCH_STR + "Match first hop interface of route\n") +{ + if (argc == 0) + return ospf_route_match_delete (vty, vty->index, "interface", NULL); + + return ospf_route_match_delete (vty, vty->index, "interface", argv[0]); +} + +ALIAS (no_match_interface, + no_match_interface_val_cmd, + "no match interface WORD", + NO_STR + MATCH_STR + "Match first hop interface of route\n" + "Interface name\n") + +DEFUN (set_metric, + set_metric_cmd, + "set metric <0-4294967295>", + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n") +{ + return ospf_route_set_add (vty, vty->index, "metric", argv[0]); +} + +DEFUN (no_set_metric, + no_set_metric_cmd, + "no set metric", + NO_STR + SET_STR + "Metric value for destination routing protocol\n") +{ + if (argc == 0) + return ospf_route_set_delete (vty, vty->index, "metric", NULL); + + return ospf_route_set_delete (vty, vty->index, "metric", argv[0]); +} + +ALIAS (no_set_metric, + no_set_metric_val_cmd, + "no set metric <0-4294967295>", + NO_STR + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n") + +DEFUN (set_metric_type, + set_metric_type_cmd, + "set metric-type (type-1|type-2)", + SET_STR + "Type of metric for destination routing protocol\n" + "OSPF external type 1 metric\n" + "OSPF external type 2 metric\n") +{ + if (strcmp (argv[0], "1") == 0) + return ospf_route_set_add (vty, vty->index, "metric-type", "type-1"); + if (strcmp (argv[0], "2") == 0) + return ospf_route_set_add (vty, vty->index, "metric-type", "type-2"); + + return ospf_route_set_add (vty, vty->index, "metric-type", argv[0]); +} + +DEFUN (no_set_metric_type, + no_set_metric_type_cmd, + "no set metric-type", + NO_STR + SET_STR + "Type of metric for destination routing protocol\n") +{ + if (argc == 0) + return ospf_route_set_delete (vty, vty->index, "metric-type", NULL); + + return ospf_route_set_delete (vty, vty->index, "metric-type", argv[0]); +} + +ALIAS (no_set_metric_type, + no_set_metric_type_val_cmd, + "no set metric-type (type-1|type-2)", + NO_STR + SET_STR + "Type of metric for destination routing protocol\n" + "OSPF external type 1 metric\n" + "OSPF external type 2 metric\n") + +/* Route-map init */ +void +ospf_route_map_init (void) +{ + route_map_init (); + route_map_init_vty (); + + route_map_add_hook (ospf_route_map_update); + route_map_delete_hook (ospf_route_map_update); + route_map_event_hook (ospf_route_map_event); + + route_map_install_match (&route_match_ip_nexthop_cmd); + route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd); + route_map_install_match (&route_match_ip_address_cmd); + route_map_install_match (&route_match_ip_address_prefix_list_cmd); + route_map_install_match (&route_match_interface_cmd); + + route_map_install_set (&route_set_metric_cmd); + route_map_install_set (&route_set_metric_type_cmd); + + install_element (RMAP_NODE, &match_ip_nexthop_cmd); + install_element (RMAP_NODE, &no_match_ip_nexthop_cmd); + install_element (RMAP_NODE, &no_match_ip_nexthop_val_cmd); + install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd); + install_element (RMAP_NODE, &match_ip_address_cmd); + install_element (RMAP_NODE, &no_match_ip_address_cmd); + install_element (RMAP_NODE, &no_match_ip_address_val_cmd); + install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd); + install_element (RMAP_NODE, &match_interface_cmd); + install_element (RMAP_NODE, &no_match_interface_cmd); + install_element (RMAP_NODE, &no_match_interface_val_cmd); + + install_element (RMAP_NODE, &set_metric_cmd); + install_element (RMAP_NODE, &no_set_metric_cmd); + install_element (RMAP_NODE, &no_set_metric_val_cmd); + install_element (RMAP_NODE, &set_metric_type_cmd); + install_element (RMAP_NODE, &no_set_metric_type_cmd); + install_element (RMAP_NODE, &no_set_metric_type_val_cmd); +} diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c new file mode 100644 index 00000000..6187977e --- /dev/null +++ b/ospfd/ospf_snmp.c @@ -0,0 +1,2443 @@ +/* OSPFv2 SNMP support + * Copyright (C) 2000 IP Infusion Inc. + * + * Written by Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#ifdef HAVE_SNMP +#include +#include +#include + +#include "if.h" +#include "log.h" +#include "prefix.h" +#include "table.h" +#include "command.h" +#include "memory.h" +#include "smux.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_flood.h" + +/* OSPF2-MIB. */ +#define OSPF2MIB 1,3,6,1,2,1,14 + +/* Zebra enterprise OSPF MIB. This variable is used for register + OSPF MIB to SNMP agent under SMUX protocol. */ +#define OSPFDOID 1,3,6,1,4,1,3317,1,2,5 + +/* OSPF MIB General Group values. */ +#define OSPFROUTERID 1 +#define OSPFADMINSTAT 2 +#define OSPFVERSIONNUMBER 3 +#define OSPFAREABDRRTRSTATUS 4 +#define OSPFASBDRRTRSTATUS 5 +#define OSPFEXTERNLSACOUNT 6 +#define OSPFEXTERNLSACKSUMSUM 7 +#define OSPFTOSSUPPORT 8 +#define OSPFORIGINATENEWLSAS 9 +#define OSPFRXNEWLSAS 10 +#define OSPFEXTLSDBLIMIT 11 +#define OSPFMULTICASTEXTENSIONS 12 +#define OSPFEXITOVERFLOWINTERVAL 13 +#define OSPFDEMANDEXTENSIONS 14 + +/* OSPF MIB ospfAreaTable. */ +#define OSPFAREAID 1 +#define OSPFAUTHTYPE 2 +#define OSPFIMPORTASEXTERN 3 +#define OSPFSPFRUNS 4 +#define OSPFAREABDRRTRCOUNT 5 +#define OSPFASBDRRTRCOUNT 6 +#define OSPFAREALSACOUNT 7 +#define OSPFAREALSACKSUMSUM 8 +#define OSPFAREASUMMARY 9 +#define OSPFAREASTATUS 10 + +/* OSPF MIB ospfStubAreaTable. */ +#define OSPFSTUBAREAID 1 +#define OSPFSTUBTOS 2 +#define OSPFSTUBMETRIC 3 +#define OSPFSTUBSTATUS 4 +#define OSPFSTUBMETRICTYPE 5 + +/* OSPF MIB ospfLsdbTable. */ +#define OSPFLSDBAREAID 1 +#define OSPFLSDBTYPE 2 +#define OSPFLSDBLSID 3 +#define OSPFLSDBROUTERID 4 +#define OSPFLSDBSEQUENCE 5 +#define OSPFLSDBAGE 6 +#define OSPFLSDBCHECKSUM 7 +#define OSPFLSDBADVERTISEMENT 8 + +/* OSPF MIB ospfAreaRangeTable. */ +#define OSPFAREARANGEAREAID 1 +#define OSPFAREARANGENET 2 +#define OSPFAREARANGEMASK 3 +#define OSPFAREARANGESTATUS 4 +#define OSPFAREARANGEEFFECT 5 + +/* OSPF MIB ospfHostTable. */ +#define OSPFHOSTIPADDRESS 1 +#define OSPFHOSTTOS 2 +#define OSPFHOSTMETRIC 3 +#define OSPFHOSTSTATUS 4 +#define OSPFHOSTAREAID 5 + +/* OSPF MIB ospfIfTable. */ +#define OSPFIFIPADDRESS 1 +#define OSPFADDRESSLESSIF 2 +#define OSPFIFAREAID 3 +#define OSPFIFTYPE 4 +#define OSPFIFADMINSTAT 5 +#define OSPFIFRTRPRIORITY 6 +#define OSPFIFTRANSITDELAY 7 +#define OSPFIFRETRANSINTERVAL 8 +#define OSPFIFHELLOINTERVAL 9 +#define OSPFIFRTRDEADINTERVAL 10 +#define OSPFIFPOLLINTERVAL 11 +#define OSPFIFSTATE 12 +#define OSPFIFDESIGNATEDROUTER 13 +#define OSPFIFBACKUPDESIGNATEDROUTER 14 +#define OSPFIFEVENTS 15 +#define OSPFIFAUTHKEY 16 +#define OSPFIFSTATUS 17 +#define OSPFIFMULTICASTFORWARDING 18 +#define OSPFIFDEMAND 19 +#define OSPFIFAUTHTYPE 20 + +/* OSPF MIB ospfIfMetricTable. */ +#define OSPFIFMETRICIPADDRESS 1 +#define OSPFIFMETRICADDRESSLESSIF 2 +#define OSPFIFMETRICTOS 3 +#define OSPFIFMETRICVALUE 4 +#define OSPFIFMETRICSTATUS 5 + +/* OSPF MIB ospfVirtIfTable. */ +#define OSPFVIRTIFAREAID 1 +#define OSPFVIRTIFNEIGHBOR 2 +#define OSPFVIRTIFTRANSITDELAY 3 +#define OSPFVIRTIFRETRANSINTERVAL 4 +#define OSPFVIRTIFHELLOINTERVAL 5 +#define OSPFVIRTIFRTRDEADINTERVAL 6 +#define OSPFVIRTIFSTATE 7 +#define OSPFVIRTIFEVENTS 8 +#define OSPFVIRTIFAUTHKEY 9 +#define OSPFVIRTIFSTATUS 10 +#define OSPFVIRTIFAUTHTYPE 11 + +/* OSPF MIB ospfNbrTable. */ +#define OSPFNBRIPADDR 1 +#define OSPFNBRADDRESSLESSINDEX 2 +#define OSPFNBRRTRID 3 +#define OSPFNBROPTIONS 4 +#define OSPFNBRPRIORITY 5 +#define OSPFNBRSTATE 6 +#define OSPFNBREVENTS 7 +#define OSPFNBRLSRETRANSQLEN 8 +#define OSPFNBMANBRSTATUS 9 +#define OSPFNBMANBRPERMANENCE 10 +#define OSPFNBRHELLOSUPPRESSED 11 + +/* OSPF MIB ospfVirtNbrTable. */ +#define OSPFVIRTNBRAREA 1 +#define OSPFVIRTNBRRTRID 2 +#define OSPFVIRTNBRIPADDR 3 +#define OSPFVIRTNBROPTIONS 4 +#define OSPFVIRTNBRSTATE 5 +#define OSPFVIRTNBREVENTS 6 +#define OSPFVIRTNBRLSRETRANSQLEN 7 +#define OSPFVIRTNBRHELLOSUPPRESSED 8 + +/* OSPF MIB ospfExtLsdbTable. */ +#define OSPFEXTLSDBTYPE 1 +#define OSPFEXTLSDBLSID 2 +#define OSPFEXTLSDBROUTERID 3 +#define OSPFEXTLSDBSEQUENCE 4 +#define OSPFEXTLSDBAGE 5 +#define OSPFEXTLSDBCHECKSUM 6 +#define OSPFEXTLSDBADVERTISEMENT 7 + +/* OSPF MIB ospfAreaAggregateTable. */ +#define OSPFAREAAGGREGATEAREAID 1 +#define OSPFAREAAGGREGATELSDBTYPE 2 +#define OSPFAREAAGGREGATENET 3 +#define OSPFAREAAGGREGATEMASK 4 +#define OSPFAREAAGGREGATESTATUS 5 +#define OSPFAREAAGGREGATEEFFECT 6 + +/* SYNTAX Status from OSPF-MIB. */ +#define OSPF_STATUS_ENABLED 1 +#define OSPF_STATUS_DISABLED 2 + +/* SNMP value hack. */ +#define COUNTER ASN_COUNTER +#define INTEGER ASN_INTEGER +#define GAUGE ASN_GAUGE +#define TIMETICKS ASN_TIMETICKS +#define IPADDRESS ASN_IPADDRESS +#define STRING ASN_OCTET_STR + +/* Declare static local variables for convenience. */ +SNMP_LOCAL_VARIABLES + +/* OSPF-MIB instances. */ +oid ospf_oid [] = { OSPF2MIB }; +oid ospfd_oid [] = { OSPFDOID }; + +/* IP address 0.0.0.0. */ +static struct in_addr ospf_empty_addr = {0}; + +/* Hook functions. */ +static u_char *ospfGeneralGroup (); +static u_char *ospfAreaEntry (); +static u_char *ospfStubAreaEntry (); +static u_char *ospfLsdbEntry (); +static u_char *ospfAreaRangeEntry (); +static u_char *ospfHostEntry (); +static u_char *ospfIfEntry (); +static u_char *ospfIfMetricEntry (); +static u_char *ospfVirtIfEntry (); +static u_char *ospfNbrEntry (); +static u_char *ospfVirtNbrEntry (); +static u_char *ospfExtLsdbEntry (); +static u_char *ospfAreaAggregateEntry (); + +struct variable ospf_variables[] = +{ + /* OSPF general variables */ + {OSPFROUTERID, IPADDRESS, RWRITE, ospfGeneralGroup, + 2, {1, 1}}, + {OSPFADMINSTAT, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 2}}, + {OSPFVERSIONNUMBER, INTEGER, RONLY, ospfGeneralGroup, + 2, {1, 3}}, + {OSPFAREABDRRTRSTATUS, INTEGER, RONLY, ospfGeneralGroup, + 2, {1, 4}}, + {OSPFASBDRRTRSTATUS, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 5}}, + {OSPFEXTERNLSACOUNT, GAUGE, RONLY, ospfGeneralGroup, + 2, {1, 6}}, + {OSPFEXTERNLSACKSUMSUM, INTEGER, RONLY, ospfGeneralGroup, + 2, {1, 7}}, + {OSPFTOSSUPPORT, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 8}}, + {OSPFORIGINATENEWLSAS, COUNTER, RONLY, ospfGeneralGroup, + 2, {1, 9}}, + {OSPFRXNEWLSAS, COUNTER, RONLY, ospfGeneralGroup, + 2, {1, 10}}, + {OSPFEXTLSDBLIMIT, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 11}}, + {OSPFMULTICASTEXTENSIONS, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 12}}, + {OSPFEXITOVERFLOWINTERVAL, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 13}}, + {OSPFDEMANDEXTENSIONS, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 14}}, + + /* OSPF area data structure. */ + {OSPFAREAID, IPADDRESS, RONLY, ospfAreaEntry, + 3, {2, 1, 1}}, + {OSPFAUTHTYPE, INTEGER, RWRITE, ospfAreaEntry, + 3, {2, 1, 2}}, + {OSPFIMPORTASEXTERN, INTEGER, RWRITE, ospfAreaEntry, + 3, {2, 1, 3}}, + {OSPFSPFRUNS, COUNTER, RONLY, ospfAreaEntry, + 3, {2, 1, 4}}, + {OSPFAREABDRRTRCOUNT, GAUGE, RONLY, ospfAreaEntry, + 3, {2, 1, 5}}, + {OSPFASBDRRTRCOUNT, GAUGE, RONLY, ospfAreaEntry, + 3, {2, 1, 6}}, + {OSPFAREALSACOUNT, GAUGE, RONLY, ospfAreaEntry, + 3, {2, 1, 7}}, + {OSPFAREALSACKSUMSUM, INTEGER, RONLY, ospfAreaEntry, + 3, {2, 1, 8}}, + {OSPFAREASUMMARY, INTEGER, RWRITE, ospfAreaEntry, + 3, {2, 1, 9}}, + {OSPFAREASTATUS, INTEGER, RWRITE, ospfAreaEntry, + 3, {2, 1, 10}}, + + /* OSPF stub area information. */ + {OSPFSTUBAREAID, IPADDRESS, RONLY, ospfStubAreaEntry, + 3, {3, 1, 1}}, + {OSPFSTUBTOS, INTEGER, RONLY, ospfStubAreaEntry, + 3, {3, 1, 2}}, + {OSPFSTUBMETRIC, INTEGER, RWRITE, ospfStubAreaEntry, + 3, {3, 1, 3}}, + {OSPFSTUBSTATUS, INTEGER, RWRITE, ospfStubAreaEntry, + 3, {3, 1, 4}}, + {OSPFSTUBMETRICTYPE, INTEGER, RWRITE, ospfStubAreaEntry, + 3, {3, 1, 5}}, + + /* OSPF link state database. */ + {OSPFLSDBAREAID, IPADDRESS, RONLY, ospfLsdbEntry, + 3, {4, 1, 1}}, + {OSPFLSDBTYPE, INTEGER, RONLY, ospfLsdbEntry, + 3, {4, 1, 2}}, + {OSPFLSDBLSID, IPADDRESS, RONLY, ospfLsdbEntry, + 3, {4, 1, 3}}, + {OSPFLSDBROUTERID, IPADDRESS, RONLY, ospfLsdbEntry, + 3, {4, 1, 4}}, + {OSPFLSDBSEQUENCE, INTEGER, RONLY, ospfLsdbEntry, + 3, {4, 1, 5}}, + {OSPFLSDBAGE, INTEGER, RONLY, ospfLsdbEntry, + 3, {4, 1, 6}}, + {OSPFLSDBCHECKSUM, INTEGER, RONLY, ospfLsdbEntry, + 3, {4, 1, 7}}, + {OSPFLSDBADVERTISEMENT, STRING, RONLY, ospfLsdbEntry, + 3, {4, 1, 8}}, + + /* Area range table. */ + {OSPFAREARANGEAREAID, IPADDRESS, RONLY, ospfAreaRangeEntry, + 3, {5, 1, 1}}, + {OSPFAREARANGENET, IPADDRESS, RONLY, ospfAreaRangeEntry, + 3, {5, 1, 2}}, + {OSPFAREARANGEMASK, IPADDRESS, RWRITE, ospfAreaRangeEntry, + 3, {5, 1, 3}}, + {OSPFAREARANGESTATUS, INTEGER, RWRITE, ospfAreaRangeEntry, + 3, {5, 1, 4}}, + {OSPFAREARANGEEFFECT, INTEGER, RWRITE, ospfAreaRangeEntry, + 3, {5, 1, 5}}, + + /* OSPF host table. */ + {OSPFHOSTIPADDRESS, IPADDRESS, RONLY, ospfHostEntry, + 3, {6, 1, 1}}, + {OSPFHOSTTOS, INTEGER, RONLY, ospfHostEntry, + 3, {6, 1, 2}}, + {OSPFHOSTMETRIC, INTEGER, RWRITE, ospfHostEntry, + 3, {6, 1, 3}}, + {OSPFHOSTSTATUS, INTEGER, RWRITE, ospfHostEntry, + 3, {6, 1, 4}}, + {OSPFHOSTAREAID, IPADDRESS, RONLY, ospfHostEntry, + 3, {6, 1, 5}}, + + /* OSPF interface table. */ + {OSPFIFIPADDRESS, IPADDRESS, RONLY, ospfIfEntry, + 3, {7, 1, 1}}, + {OSPFADDRESSLESSIF, INTEGER, RONLY, ospfIfEntry, + 3, {7, 1, 2}}, + {OSPFIFAREAID, IPADDRESS, RWRITE, ospfIfEntry, + 3, {7, 1, 3}}, + {OSPFIFTYPE, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 4}}, + {OSPFIFADMINSTAT, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 5}}, + {OSPFIFRTRPRIORITY, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 6}}, + {OSPFIFTRANSITDELAY, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 7}}, + {OSPFIFRETRANSINTERVAL, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 8}}, + {OSPFIFHELLOINTERVAL, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 9}}, + {OSPFIFRTRDEADINTERVAL, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 10}}, + {OSPFIFPOLLINTERVAL, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 11}}, + {OSPFIFSTATE, INTEGER, RONLY, ospfIfEntry, + 3, {7, 1, 12}}, + {OSPFIFDESIGNATEDROUTER, IPADDRESS, RONLY, ospfIfEntry, + 3, {7, 1, 13}}, + {OSPFIFBACKUPDESIGNATEDROUTER, IPADDRESS, RONLY, ospfIfEntry, + 3, {7, 1, 14}}, + {OSPFIFEVENTS, COUNTER, RONLY, ospfIfEntry, + 3, {7, 1, 15}}, + {OSPFIFAUTHKEY, STRING, RWRITE, ospfIfEntry, + 3, {7, 1, 16}}, + {OSPFIFSTATUS, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 17}}, + {OSPFIFMULTICASTFORWARDING, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 18}}, + {OSPFIFDEMAND, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 19}}, + {OSPFIFAUTHTYPE, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 20}}, + + /* OSPF interface metric table. */ + {OSPFIFMETRICIPADDRESS, IPADDRESS, RONLY, ospfIfMetricEntry, + 3, {8, 1, 1}}, + {OSPFIFMETRICADDRESSLESSIF, INTEGER, RONLY, ospfIfMetricEntry, + 3, {8, 1, 2}}, + {OSPFIFMETRICTOS, INTEGER, RONLY, ospfIfMetricEntry, + 3, {8, 1, 3}}, + {OSPFIFMETRICVALUE, INTEGER, RWRITE, ospfIfMetricEntry, + 3, {8, 1, 4}}, + {OSPFIFMETRICSTATUS, INTEGER, RWRITE, ospfIfMetricEntry, + 3, {8, 1, 5}}, + + /* OSPF virtual interface table. */ + {OSPFVIRTIFAREAID, IPADDRESS, RONLY, ospfVirtIfEntry, + 3, {9, 1, 1}}, + {OSPFVIRTIFNEIGHBOR, IPADDRESS, RONLY, ospfVirtIfEntry, + 3, {9, 1, 2}}, + {OSPFVIRTIFTRANSITDELAY, INTEGER, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 3}}, + {OSPFVIRTIFRETRANSINTERVAL, INTEGER, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 4}}, + {OSPFVIRTIFHELLOINTERVAL, INTEGER, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 5}}, + {OSPFVIRTIFRTRDEADINTERVAL, INTEGER, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 6}}, + {OSPFVIRTIFSTATE, INTEGER, RONLY, ospfVirtIfEntry, + 3, {9, 1, 7}}, + {OSPFVIRTIFEVENTS, COUNTER, RONLY, ospfVirtIfEntry, + 3, {9, 1, 8}}, + {OSPFVIRTIFAUTHKEY, STRING, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 9}}, + {OSPFVIRTIFSTATUS, INTEGER, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 10}}, + {OSPFVIRTIFAUTHTYPE, INTEGER, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 11}}, + + /* OSPF neighbor table. */ + {OSPFNBRIPADDR, IPADDRESS, RONLY, ospfNbrEntry, + 3, {10, 1, 1}}, + {OSPFNBRADDRESSLESSINDEX, INTEGER, RONLY, ospfNbrEntry, + 3, {10, 1, 2}}, + {OSPFNBRRTRID, IPADDRESS, RONLY, ospfNbrEntry, + 3, {10, 1, 3}}, + {OSPFNBROPTIONS, INTEGER, RONLY, ospfNbrEntry, + 3, {10, 1, 4}}, + {OSPFNBRPRIORITY, INTEGER, RWRITE, ospfNbrEntry, + 3, {10, 1, 5}}, + {OSPFNBRSTATE, INTEGER, RONLY, ospfNbrEntry, + 3, {10, 1, 6}}, + {OSPFNBREVENTS, COUNTER, RONLY, ospfNbrEntry, + 3, {10, 1, 7}}, + {OSPFNBRLSRETRANSQLEN, GAUGE, RONLY, ospfNbrEntry, + 3, {10, 1, 8}}, + {OSPFNBMANBRSTATUS, INTEGER, RWRITE, ospfNbrEntry, + 3, {10, 1, 9}}, + {OSPFNBMANBRPERMANENCE, INTEGER, RONLY, ospfNbrEntry, + 3, {10, 1, 10}}, + {OSPFNBRHELLOSUPPRESSED, INTEGER, RONLY, ospfNbrEntry, + 3, {10, 1, 11}}, + + /* OSPF virtual neighbor table. */ + {OSPFVIRTNBRAREA, IPADDRESS, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 1}}, + {OSPFVIRTNBRRTRID, IPADDRESS, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 2}}, + {OSPFVIRTNBRIPADDR, IPADDRESS, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 3}}, + {OSPFVIRTNBROPTIONS, INTEGER, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 4}}, + {OSPFVIRTNBRSTATE, INTEGER, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 5}}, + {OSPFVIRTNBREVENTS, COUNTER, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 6}}, + {OSPFVIRTNBRLSRETRANSQLEN, INTEGER, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 7}}, + {OSPFVIRTNBRHELLOSUPPRESSED, INTEGER, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 8}}, + + /* OSPF link state database, external. */ + {OSPFEXTLSDBTYPE, INTEGER, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 1}}, + {OSPFEXTLSDBLSID, IPADDRESS, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 2}}, + {OSPFEXTLSDBROUTERID, IPADDRESS, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 3}}, + {OSPFEXTLSDBSEQUENCE, INTEGER, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 4}}, + {OSPFEXTLSDBAGE, INTEGER, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 5}}, + {OSPFEXTLSDBCHECKSUM, INTEGER, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 6}}, + {OSPFEXTLSDBADVERTISEMENT, STRING, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 7}}, + + /* OSPF area aggregate table. */ + {OSPFAREAAGGREGATEAREAID, IPADDRESS, RONLY, ospfAreaAggregateEntry, + 3, {14, 1, 1}}, + {OSPFAREAAGGREGATELSDBTYPE, INTEGER, RONLY, ospfAreaAggregateEntry, + 3, {14, 1, 2}}, + {OSPFAREAAGGREGATENET, IPADDRESS, RONLY, ospfAreaAggregateEntry, + 3, {14, 1, 3}}, + {OSPFAREAAGGREGATEMASK, IPADDRESS, RONLY, ospfAreaAggregateEntry, + 3, {14, 1, 4}}, + {OSPFAREAAGGREGATESTATUS, INTEGER, RWRITE, ospfAreaAggregateEntry, + 3, {14, 1, 5}}, + {OSPFAREAAGGREGATEEFFECT, INTEGER, RWRITE, ospfAreaAggregateEntry, + 3, {14, 1, 6}} +}; + +/* The administrative status of OSPF. When OSPF is enbled on at least + one interface return 1. */ +int +ospf_admin_stat () +{ + listnode node; + struct ospf_interface *oi; + + if (! ospf_top) + return 0; + + for (node = listhead (ospf_top->oiflist); node; nextnode (node)) + { + oi = getdata (node); + + if (oi && oi->address) + return 1; + } + return 0; +} + +static u_char * +ospfGeneralGroup (struct variable *v, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + /* Check whether the instance identifier is valid */ + if (smux_header_generic (v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFROUTERID: /* 1 */ + /* Router-ID of this OSPF instance. */ + if (ospf_top) + return SNMP_IPADDRESS (ospf_top->router_id); + else + return SNMP_IPADDRESS (ospf_empty_addr); + break; + case OSPFADMINSTAT: /* 2 */ + /* The administrative status of OSPF in the router. */ + if (ospf_admin_stat ()) + return SNMP_INTEGER (OSPF_STATUS_ENABLED); + else + return SNMP_INTEGER (OSPF_STATUS_DISABLED); + break; + case OSPFVERSIONNUMBER: /* 3 */ + /* OSPF version 2. */ + return SNMP_INTEGER (OSPF_VERSION); + break; + case OSPFAREABDRRTRSTATUS: /* 4 */ + /* Area Border router status. */ + if (ospf_top && CHECK_FLAG (ospf_top->flags, OSPF_FLAG_ABR)) + return SNMP_INTEGER (SNMP_TRUE); + else + return SNMP_INTEGER (SNMP_FALSE); + break; + case OSPFASBDRRTRSTATUS: /* 5 */ + /* AS Border router status. */ + if (ospf_top && CHECK_FLAG (ospf_top->flags, OSPF_FLAG_ASBR)) + return SNMP_INTEGER (SNMP_TRUE); + else + return SNMP_INTEGER (SNMP_FALSE); + break; + case OSPFEXTERNLSACOUNT: /* 6 */ + /* External LSA counts. */ + if (ospf_top) + return SNMP_INTEGER (ospf_lsdb_count_all (ospf_top->lsdb)); + else + return SNMP_INTEGER (0); + break; + case OSPFEXTERNLSACKSUMSUM: /* 7 */ + /* External LSA checksum. */ + return SNMP_INTEGER (0); + break; + case OSPFTOSSUPPORT: /* 8 */ + /* TOS is not supported. */ + return SNMP_INTEGER (SNMP_FALSE); + break; + case OSPFORIGINATENEWLSAS: /* 9 */ + /* The number of new link-state advertisements. */ + if (ospf_top) + return SNMP_INTEGER (ospf_top->lsa_originate_count); + else + return SNMP_INTEGER (0); + break; + case OSPFRXNEWLSAS: /* 10 */ + /* The number of link-state advertisements received determined + to be new instantiations. */ + if (ospf_top) + return SNMP_INTEGER (ospf_top->rx_lsa_count); + else + return SNMP_INTEGER (0); + break; + case OSPFEXTLSDBLIMIT: /* 11 */ + /* There is no limit for the number of non-default + AS-external-LSAs. */ + return SNMP_INTEGER (-1); + break; + case OSPFMULTICASTEXTENSIONS: /* 12 */ + /* Multicast Extensions to OSPF is not supported. */ + return SNMP_INTEGER (0); + break; + case OSPFEXITOVERFLOWINTERVAL: /* 13 */ + /* Overflow is not supported. */ + return SNMP_INTEGER (0); + break; + case OSPFDEMANDEXTENSIONS: /* 14 */ + /* Demand routing is not supported. */ + return SNMP_INTEGER (SNMP_FALSE); + break; + default: + return NULL; + } + return NULL; +} + +struct ospf_area * +ospf_area_lookup_next (struct in_addr *area_id, int first) +{ + struct ospf_area *area; + listnode node; + + if (! ospf_top) + return NULL; + + if (first) + { + node = listhead (ospf_top->areas); + if (node) + { + area = getdata (node); + *area_id = area->area_id; + return area; + } + return NULL; + } + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + area = getdata (node); + + if (ntohl (area->area_id.s_addr) > ntohl (area_id->s_addr)) + { + *area_id = area->area_id; + return area; + } + } + return NULL; +} + +struct ospf_area * +ospfAreaLookup (struct variable *v, oid name[], size_t *length, + struct in_addr *addr, int exact) +{ + int len; + struct ospf_area *area; + + if (! ospf_top) + return NULL; + + if (exact) + { + /* Length is insufficient to lookup OSPF area. */ + if (*length - v->namelen != sizeof (struct in_addr)) + return NULL; + + oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); + + area = ospf_area_lookup_by_area_id (*addr); + + return area; + } + else + { + len = *length - v->namelen; + if (len > 4) + len = 4; + + oid2in_addr (name + v->namelen, len, addr); + + area = ospf_area_lookup_next (addr, len == 0 ? 1 : 0); + + if (area == NULL) + return NULL; + + oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr)); + *length = sizeof (struct in_addr) + v->namelen; + + return area; + } + return NULL; +} + +static u_char * +ospfAreaEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct ospf_area *area; + struct in_addr addr; + + memset (&addr, 0, sizeof (struct in_addr)); + + area = ospfAreaLookup (v, name, length, &addr, exact); + if (! area) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFAREAID: /* 1 */ + return SNMP_IPADDRESS (area->area_id); + break; + case OSPFAUTHTYPE: /* 2 */ + return SNMP_INTEGER (area->auth_type); + break; + case OSPFIMPORTASEXTERN: /* 3 */ + return SNMP_INTEGER (area->external_routing + 1); + break; + case OSPFSPFRUNS: /* 4 */ + return SNMP_INTEGER (area->spf_calculation); + break; + case OSPFAREABDRRTRCOUNT: /* 5 */ + return SNMP_INTEGER (area->abr_count); + break; + case OSPFASBDRRTRCOUNT: /* 6 */ + return SNMP_INTEGER (area->asbr_count); + break; + case OSPFAREALSACOUNT: /* 7 */ + return SNMP_INTEGER (area->lsdb->total); + break; + case OSPFAREALSACKSUMSUM: /* 8 */ + return SNMP_INTEGER (0); + break; + case OSPFAREASUMMARY: /* 9 */ +#define OSPF_noAreaSummary 1 +#define OSPF_sendAreaSummary 2 + if (area->no_summary) + return SNMP_INTEGER (OSPF_noAreaSummary); + else + return SNMP_INTEGER (OSPF_sendAreaSummary); + break; + case OSPFAREASTATUS: /* 10 */ + return SNMP_INTEGER (SNMP_VALID); + break; + default: + return NULL; + break; + } + return NULL; +} + +struct ospf_area * +ospf_stub_area_lookup_next (struct in_addr *area_id, int first) +{ + struct ospf_area *area; + listnode node; + + if (! ospf_top) + return NULL; + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + area = getdata (node); + + if (area->external_routing == OSPF_AREA_STUB) + { + if (first) + { + *area_id = area->area_id; + return area; + } + else if (ntohl (area->area_id.s_addr) > ntohl (area_id->s_addr)) + { + *area_id = area->area_id; + return area; + } + } + } + return NULL; +} + +struct ospf_area * +ospfStubAreaLookup (struct variable *v, oid name[], size_t *length, + struct in_addr *addr, int exact) +{ + int len; + struct ospf_area *area; + + if (! ospf_top) + return NULL; + + /* Exact lookup. */ + if (exact) + { + /* ospfStubAreaID + ospfStubTOS. */ + if (*length != v->namelen + sizeof (struct in_addr) + 1) + return NULL; + + /* Check ospfStubTOS is zero. */ + if (name[*length - 1] != 0) + return NULL; + + oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); + + area = ospf_area_lookup_by_area_id (*addr); + + if (area->external_routing == OSPF_AREA_STUB) + return area; + else + return NULL; + } + else + { + len = *length - v->namelen; + if (len > 4) + len = 4; + + oid2in_addr (name + v->namelen, len, addr); + + area = ospf_stub_area_lookup_next (addr, len == 0 ? 1 : 0); + + if (area == NULL) + return NULL; + + oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr)); + /* Set TOS 0. */ + name[v->namelen + sizeof (struct in_addr)] = 0; + *length = v->namelen + sizeof (struct in_addr) + 1; + + return area; + } + return NULL; +} + +static u_char * +ospfStubAreaEntry (struct variable *v, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + struct ospf_area *area; + struct in_addr addr; + + memset (&addr, 0, sizeof (struct in_addr)); + + area = ospfStubAreaLookup (v, name, length, &addr, exact); + if (! area) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFSTUBAREAID: /* 1 */ + /* OSPF stub area id. */ + return SNMP_IPADDRESS (area->area_id); + break; + case OSPFSTUBTOS: /* 2 */ + /* TOS value is not supported. */ + return SNMP_INTEGER (0); + break; + case OSPFSTUBMETRIC: /* 3 */ + /* Default cost to stub area. */ + return SNMP_INTEGER (area->default_cost); + break; + case OSPFSTUBSTATUS: /* 4 */ + /* Status of the stub area. */ + return SNMP_INTEGER (SNMP_VALID); + break; + case OSPFSTUBMETRICTYPE: /* 5 */ + /* OSPF Metric type. */ +#define OSPF_ospfMetric 1 +#define OSPF_comparableCost 2 +#define OSPF_nonComparable 3 + return SNMP_INTEGER (OSPF_ospfMetric); + break; + default: + return NULL; + break; + } + return NULL; +} + +struct ospf_lsa * +lsdb_lookup_next (struct ospf_area *area, u_char *type, int type_next, + struct in_addr *ls_id, int ls_id_next, + struct in_addr *router_id, int router_id_next) +{ + struct ospf_lsa *lsa; + int i; + + if (type_next) + i = OSPF_MIN_LSA; + else + i = *type; + + for (; i < OSPF_MAX_LSA; i++) + { + *type = i; + + lsa = ospf_lsdb_lookup_by_id_next (area->lsdb, *type, *ls_id, *router_id, + ls_id_next); + if (lsa) + return lsa; + + ls_id_next = 1; + } + return NULL; +} + +struct ospf_lsa * +ospfLsdbLookup (struct variable *v, oid *name, size_t *length, + struct in_addr *area_id, u_char *type, + struct in_addr *ls_id, struct in_addr *router_id, int exact) +{ + struct ospf_area *area; + struct ospf_lsa *lsa; + int len; + int type_next; + int ls_id_next; + int router_id_next; + oid *offset; + int offsetlen; + +#define OSPF_LSDB_ENTRY_OFFSET \ + (IN_ADDR_SIZE + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE) + + if (exact) + { + /* Area ID + Type + LS ID + Router ID. */ + if (*length - v->namelen != OSPF_LSDB_ENTRY_OFFSET) + return NULL; + + /* Set OID offset for Area ID. */ + offset = name + v->namelen; + + /* Lookup area first. */ + oid2in_addr (offset, IN_ADDR_SIZE, area_id); + area = ospf_area_lookup_by_area_id (*area_id); + if (! area) + return NULL; + offset += IN_ADDR_SIZE; + + /* Type. */ + *type = *offset; + offset++; + + /* LS ID. */ + oid2in_addr (offset, IN_ADDR_SIZE, ls_id); + offset += IN_ADDR_SIZE; + + /* Router ID. */ + oid2in_addr (offset, IN_ADDR_SIZE, router_id); + + /* Lookup LSDB. */ + return ospf_lsdb_lookup_by_id (area->lsdb, *type, *ls_id, *router_id); + } + else + { + /* Get variable length. */ + offset = name + v->namelen; + offsetlen = *length - v->namelen; + len = offsetlen; + + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (offset, len, area_id); + + /* First we search area. */ + if (len == IN_ADDR_SIZE) + area = ospf_area_lookup_by_area_id (*area_id); + else + area = ospf_area_lookup_next (area_id, len == 0 ? 1 : 0); + + if (area == NULL) + return NULL; + + do + { + /* Next we lookup type. */ + offset += IN_ADDR_SIZE; + offsetlen -= IN_ADDR_SIZE; + len = offsetlen; + + if (len <= 0) + type_next = 1; + else + { + len = 1; + type_next = 0; + *type = *offset; + } + + /* LS ID. */ + offset++; + offsetlen--; + len = offsetlen; + + if (len <= 0) + ls_id_next = 1; + else + { + ls_id_next = 0; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (offset, len, ls_id); + } + + /* Router ID. */ + offset += IN_ADDR_SIZE; + offsetlen -= IN_ADDR_SIZE; + len = offsetlen; + + if (len <= 0) + router_id_next = 1; + else + { + router_id_next = 0; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (offset, len, router_id); + } + + lsa = lsdb_lookup_next (area, type, type_next, ls_id, ls_id_next, + router_id, router_id_next); + + if (lsa) + { + /* Fill in length. */ + *length = v->namelen + OSPF_LSDB_ENTRY_OFFSET; + + /* Fill in value. */ + offset = name + v->namelen; + oid_copy_addr (offset, area_id, IN_ADDR_SIZE); + offset += IN_ADDR_SIZE; + *offset = lsa->data->type; + offset++; + oid_copy_addr (offset, &lsa->data->id, IN_ADDR_SIZE); + offset += IN_ADDR_SIZE; + oid_copy_addr (offset, &lsa->data->adv_router, IN_ADDR_SIZE); + + return lsa; + } + } + while ((area = ospf_area_lookup_next (area_id, 0)) != NULL); + } + return NULL; +} + +static u_char * +ospfLsdbEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct ospf_lsa *lsa; + struct lsa_header *lsah; + struct in_addr area_id; + u_char type; + struct in_addr ls_id; + struct in_addr router_id; + + /* INDEX { ospfLsdbAreaId, ospfLsdbType, + ospfLsdbLsid, ospfLsdbRouterId } */ + + memset (&area_id, 0, sizeof (struct in_addr)); + type = 0; + memset (&ls_id, 0, sizeof (struct in_addr)); + memset (&router_id, 0, sizeof (struct in_addr)); + + /* Check OSPF instance. */ + if (! ospf_top) + return NULL; + + lsa = ospfLsdbLookup (v, name, length, &area_id, &type, &ls_id, &router_id, + exact); + if (! lsa) + return NULL; + + lsah = lsa->data; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFLSDBAREAID: /* 1 */ + return SNMP_IPADDRESS (lsa->area->area_id); + break; + case OSPFLSDBTYPE: /* 2 */ + return SNMP_INTEGER (lsah->type); + break; + case OSPFLSDBLSID: /* 3 */ + return SNMP_IPADDRESS (lsah->id); + break; + case OSPFLSDBROUTERID: /* 4 */ + return SNMP_IPADDRESS (lsah->adv_router); + break; + case OSPFLSDBSEQUENCE: /* 5 */ + return SNMP_INTEGER (lsah->ls_seqnum); + break; + case OSPFLSDBAGE: /* 6 */ + return SNMP_INTEGER (lsah->ls_age); + break; + case OSPFLSDBCHECKSUM: /* 7 */ + return SNMP_INTEGER (lsah->checksum); + break; + case OSPFLSDBADVERTISEMENT: /* 8 */ + *var_len = ntohs (lsah->length); + return (u_char *) lsah; + break; + default: + return NULL; + break; + } + return NULL; +} + +struct ospf_area_range * +ospfAreaRangeLookup (struct variable *v, oid *name, size_t *length, + struct in_addr *area_id, struct in_addr *range_net, + int exact) +{ + oid *offset; + int offsetlen; + int len; + struct ospf_area *area; + struct ospf_area_range *range; + struct prefix_ipv4 p; + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + + if (exact) + { + /* Area ID + Range Network. */ + if (v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE != *length) + return NULL; + + /* Set OID offset for Area ID. */ + offset = name + v->namelen; + + /* Lookup area first. */ + oid2in_addr (offset, IN_ADDR_SIZE, area_id); + + area = ospf_area_lookup_by_area_id (*area_id); + if (! area) + return NULL; + + offset += IN_ADDR_SIZE; + + /* Lookup area range. */ + oid2in_addr (offset, IN_ADDR_SIZE, range_net); + p.prefix = *range_net; + + return ospf_area_range_lookup (area, &p); + } + else + { + /* Set OID offset for Area ID. */ + offset = name + v->namelen; + offsetlen = *length - v->namelen; + + len = offsetlen; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (offset, len, area_id); + + /* First we search area. */ + if (len == IN_ADDR_SIZE) + area = ospf_area_lookup_by_area_id (*area_id); + else + area = ospf_area_lookup_next (area_id, len == 0 ? 1 : 0); + + if (area == NULL) + return NULL; + + do + { + offset += IN_ADDR_SIZE; + offsetlen -= IN_ADDR_SIZE; + len = offsetlen; + + if (len < 0) + len = 0; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (offset, len, range_net); + + range = ospf_area_range_lookup_next (area, range_net, + len == 0 ? 1 : 0); + + if (range) + { + /* Fill in length. */ + *length = v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE; + + /* Fill in value. */ + offset = name + v->namelen; + oid_copy_addr (offset, area_id, IN_ADDR_SIZE); + offset += IN_ADDR_SIZE; + oid_copy_addr (offset, range_net, IN_ADDR_SIZE); + + return range; + } + } + while ((area = ospf_area_lookup_next (area_id, 0)) != NULL); + } + return NULL; +} + +static u_char * +ospfAreaRangeEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct ospf_area_range *range; + struct in_addr area_id; + struct in_addr range_net; + struct in_addr mask; + + /* Check OSPF instance. */ + if (! ospf_top) + return NULL; + + memset (&area_id, 0, IN_ADDR_SIZE); + memset (&range_net, 0, IN_ADDR_SIZE); + + range = ospfAreaRangeLookup (v, name, length, &area_id, &range_net, exact); + if (! range) + return NULL; + + /* Convert prefixlen to network mask format. */ + masklen2ip (range->subst_masklen, &mask); + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFAREARANGEAREAID: /* 1 */ + return SNMP_IPADDRESS (area_id); + break; + case OSPFAREARANGENET: /* 2 */ + return SNMP_IPADDRESS (range_net); + break; + case OSPFAREARANGEMASK: /* 3 */ + return SNMP_IPADDRESS (mask); + break; + case OSPFAREARANGESTATUS: /* 4 */ + return SNMP_INTEGER (SNMP_VALID); + break; + case OSPFAREARANGEEFFECT: /* 5 */ +#define OSPF_advertiseMatching 1 +#define OSPF_doNotAdvertiseMatching 2 + return SNMP_INTEGER (OSPF_advertiseMatching); + break; + default: + return NULL; + break; + } + return NULL; +} + +struct ospf_nbr_nbma * +ospfHostLookup (struct variable *v, oid *name, size_t *length, + struct in_addr *addr, int exact) +{ + int len; + struct ospf_nbr_nbma *nbr_nbma; + + if (! ospf_top) + return NULL; + + if (exact) + { + /* INDEX { ospfHostIpAddress, ospfHostTOS } */ + if (*length != v->namelen + IN_ADDR_SIZE + 1) + return NULL; + + /* Check ospfHostTOS. */ + if (name[*length - 1] != 0) + return NULL; + + oid2in_addr (name + v->namelen, IN_ADDR_SIZE, addr); + + nbr_nbma = ospf_nbr_nbma_lookup (ospf_top, *addr); + + return nbr_nbma; + } + else + { + len = *length - v->namelen; + if (len > 4) + len = 4; + + oid2in_addr (name + v->namelen, len, addr); + + nbr_nbma = ospf_nbr_nbma_lookup_next (addr, len == 0 ? 1 : 0); + + if (nbr_nbma == NULL) + return NULL; + + oid_copy_addr (name + v->namelen, addr, IN_ADDR_SIZE); + + /* Set TOS 0. */ + name[v->namelen + IN_ADDR_SIZE] = 0; + + *length = v->namelen + IN_ADDR_SIZE + 1; + + return nbr_nbma; + } + return NULL; +} + +static u_char * +ospfHostEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct ospf_nbr_nbma *nbr_nbma; + struct ospf_interface *oi; + struct in_addr addr; + + /* Check OSPF instance. */ + if (! ospf_top) + return NULL; + + memset (&addr, 0, sizeof (struct in_addr)); + + nbr_nbma = ospfHostLookup (v, name, length, &addr, exact); + if (nbr_nbma == NULL) + return NULL; + + oi = nbr_nbma->oi; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFHOSTIPADDRESS: /* 1 */ + return SNMP_IPADDRESS (nbr_nbma->addr); + break; + case OSPFHOSTTOS: /* 2 */ + return SNMP_INTEGER (0); + break; + case OSPFHOSTMETRIC: /* 3 */ + if (oi) + return SNMP_INTEGER (oi->output_cost); + else + return SNMP_INTEGER (1); + break; + case OSPFHOSTSTATUS: /* 4 */ + return SNMP_INTEGER (SNMP_VALID); + break; + case OSPFHOSTAREAID: /* 5 */ + if (oi && oi->area) + return SNMP_IPADDRESS (oi->area->area_id); + else + return SNMP_IPADDRESS (ospf_empty_addr); + break; + default: + return NULL; + break; + } + return NULL; +} + +struct list *ospf_snmp_iflist; + +struct ospf_snmp_if +{ + struct in_addr addr; + unsigned int ifindex; + struct interface *ifp; +}; + +struct ospf_snmp_if * +ospf_snmp_if_new () +{ + struct ospf_snmp_if *osif; + + osif = XMALLOC (0, sizeof (struct ospf_snmp_if)); + memset (osif, 0, sizeof (struct ospf_snmp_if)); + return osif; +} + +void +ospf_snmp_if_free (struct ospf_snmp_if *osif) +{ + XFREE (0, osif); +} + +void +ospf_snmp_if_delete (struct interface *ifp) +{ + struct listnode *nn; + struct ospf_snmp_if *osif; + + LIST_LOOP (ospf_snmp_iflist, osif, nn) + { + if (osif->ifp == ifp) + { + list_delete_node (ospf_snmp_iflist, nn); + ospf_snmp_if_free (osif); + return; + } + } +} + +void +ospf_snmp_if_update (struct interface *ifp) +{ + struct listnode *nn; + struct listnode *pn; + struct connected *ifc; + struct prefix *p; + struct ospf_snmp_if *osif; + struct in_addr *addr; + unsigned int ifindex; + + ospf_snmp_if_delete (ifp); + + p = NULL; + addr = NULL; + ifindex = 0; + + /* Lookup first IPv4 address entry. */ + LIST_LOOP (ifp->connected, ifc, nn) + { + if (if_is_pointopoint (ifp)) + p = ifc->destination; + else + p = ifc->address; + + if (p->family == AF_INET) + { + addr = &p->u.prefix4; + break; + } + } + if (! addr) + ifindex = ifp->ifindex; + + /* Add interface to the list. */ + pn = NULL; + LIST_LOOP (ospf_snmp_iflist, osif, nn) + { + if (addr) + { + if (ntohl (osif->addr.s_addr) > ntohl (addr->s_addr)) + break; + } + else + { + /* Unnumbered interface. */ + if (osif->addr.s_addr != 0 || osif->ifindex > ifindex) + break; + } + pn = nn; + } + + osif = ospf_snmp_if_new (); + if (addr) + osif->addr = *addr; + else + osif->ifindex = ifindex; + osif->ifp = ifp; + + listnode_add_after (ospf_snmp_iflist, pn, osif); +} + +struct interface * +ospf_snmp_if_lookup (struct in_addr *ifaddr, unsigned int *ifindex) +{ + struct listnode *nn; + struct ospf_snmp_if *osif; + + LIST_LOOP (ospf_snmp_iflist, osif, nn) + { + if (ifaddr->s_addr) + { + if (IPV4_ADDR_SAME (&osif->addr, ifaddr)) + return osif->ifp; + } + else + { + if (osif->ifindex == *ifindex) + return osif->ifp; + } + } + return NULL; +} + +struct interface * +ospf_snmp_if_lookup_next (struct in_addr *ifaddr, unsigned int *ifindex, + int ifaddr_next, int ifindex_next) +{ + struct ospf_snmp_if *osif; + struct listnode *nn; + + if (ifaddr_next) + { + nn = listhead (ospf_snmp_iflist); + if (nn) + { + osif = getdata (nn); + *ifaddr = osif->addr; + *ifindex = osif->ifindex; + return osif->ifp; + } + return NULL; + } + + LIST_LOOP (ospf_snmp_iflist, osif, nn) + { + if (ifaddr->s_addr) + { + if (ntohl (osif->addr.s_addr) > ntohl (ifaddr->s_addr)) + { + *ifaddr = osif->addr; + *ifindex = osif->ifindex; + return osif->ifp; + } + } + else + { + if (osif->ifindex > *ifindex || osif->addr.s_addr) + { + *ifaddr = osif->addr; + *ifindex = osif->ifindex; + return osif->ifp; + } + } + } + return NULL; +} + +int +ospf_snmp_iftype (struct interface *ifp) +{ +#define ospf_snmp_iftype_broadcast 1 +#define ospf_snmp_iftype_nbma 2 +#define ospf_snmp_iftype_pointToPoint 3 +#define ospf_snmp_iftype_pointToMultipoint 5 + if (if_is_broadcast (ifp)) + return ospf_snmp_iftype_broadcast; + if (if_is_pointopoint (ifp)) + return ospf_snmp_iftype_pointToPoint; + return ospf_snmp_iftype_broadcast; +} + +struct interface * +ospfIfLookup (struct variable *v, oid *name, size_t *length, + struct in_addr *ifaddr, unsigned int *ifindex, int exact) +{ + int len; + int ifaddr_next = 0; + int ifindex_next = 0; + struct interface *ifp; + oid *offset; + + if (exact) + { + if (*length != v->namelen + IN_ADDR_SIZE + 1) + return NULL; + + oid2in_addr (name + v->namelen, IN_ADDR_SIZE, ifaddr); + *ifindex = name[v->namelen + IN_ADDR_SIZE]; + + return ospf_snmp_if_lookup (ifaddr, ifindex); + } + else + { + len = *length - v->namelen; + if (len >= IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + if (len <= 0) + ifaddr_next = 1; + + oid2in_addr (name + v->namelen, len, ifaddr); + + len = *length - v->namelen - IN_ADDR_SIZE; + if (len >= 1) + len = 1; + else + ifindex_next = 1; + + if (len == 1) + *ifindex = name[v->namelen + IN_ADDR_SIZE]; + + ifp = ospf_snmp_if_lookup_next (ifaddr, ifindex, ifaddr_next, + ifindex_next); + if (ifp) + { + *length = v->namelen + IN_ADDR_SIZE + 1; + offset = name + v->namelen; + oid_copy_addr (offset, ifaddr, IN_ADDR_SIZE); + offset += IN_ADDR_SIZE; + *offset = *ifindex; + return ifp; + } + } + return NULL; +} + +static u_char * +ospfIfEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct interface *ifp; + unsigned int ifindex; + struct in_addr ifaddr; + struct ospf_interface *oi; + + ifindex = 0; + memset (&ifaddr, 0, sizeof (struct in_addr)); + + /* Check OSPF instance. */ + if (! ospf_top) + return NULL; + + ifp = ospfIfLookup (v, name, length, &ifaddr, &ifindex, exact); + if (ifp == NULL) + return NULL; + + oi = ospf_if_lookup_by_local_addr (ifp, ifaddr); + if (oi == NULL) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFIFIPADDRESS: /* 1 */ + return SNMP_IPADDRESS (ifaddr); + break; + case OSPFADDRESSLESSIF: /* 2 */ + return SNMP_INTEGER (ifindex); + break; + case OSPFIFAREAID: /* 3 */ + if (oi->area) + return SNMP_IPADDRESS (oi->area->area_id); + else + return SNMP_IPADDRESS (ospf_empty_addr); + break; + case OSPFIFTYPE: /* 4 */ + return SNMP_INTEGER (ospf_snmp_iftype (ifp)); + break; + case OSPFIFADMINSTAT: /* 5 */ + if (oi) + return SNMP_INTEGER (OSPF_STATUS_ENABLED); + else + return SNMP_INTEGER (OSPF_STATUS_DISABLED); + break; + case OSPFIFRTRPRIORITY: /* 6 */ + return SNMP_INTEGER (PRIORITY (oi)); + break; + case OSPFIFTRANSITDELAY: /* 7 */ + return SNMP_INTEGER (OSPF_IF_PARAM (oi, transmit_delay)); + break; + case OSPFIFRETRANSINTERVAL: /* 8 */ + return SNMP_INTEGER (OSPF_IF_PARAM (oi, retransmit_interval)); + break; + case OSPFIFHELLOINTERVAL: /* 9 */ + return SNMP_INTEGER (OSPF_IF_PARAM (oi, v_hello)); + break; + case OSPFIFRTRDEADINTERVAL: /* 10 */ + return SNMP_INTEGER (OSPF_IF_PARAM (oi, v_wait)); + break; + case OSPFIFPOLLINTERVAL: /* 11 */ + return SNMP_INTEGER (OSPF_POLL_INTERVAL_DEFAULT); + break; + case OSPFIFSTATE: /* 12 */ + return SNMP_INTEGER (oi->state); + break; + case OSPFIFDESIGNATEDROUTER: /* 13 */ + return SNMP_IPADDRESS (DR (oi)); + break; + case OSPFIFBACKUPDESIGNATEDROUTER: /* 14 */ + return SNMP_IPADDRESS (BDR (oi)); + break; + case OSPFIFEVENTS: /* 15 */ + return SNMP_INTEGER (oi->state_change); + break; + case OSPFIFAUTHKEY: /* 16 */ + *var_len = 0; + return (u_char *) OSPF_IF_PARAM (oi, auth_simple); + break; + case OSPFIFSTATUS: /* 17 */ + return SNMP_INTEGER (SNMP_VALID); + break; + case OSPFIFMULTICASTFORWARDING: /* 18 */ +#define ospf_snmp_multiforward_blocked 1 +#define ospf_snmp_multiforward_multicast 2 +#define ospf_snmp_multiforward_unicast 3 + return SNMP_INTEGER (ospf_snmp_multiforward_blocked); + break; + case OSPFIFDEMAND: /* 19 */ + return SNMP_INTEGER (SNMP_FALSE); + break; + case OSPFIFAUTHTYPE: /* 20 */ + if (oi->area) + return SNMP_INTEGER (oi->area->auth_type); + else + return SNMP_INTEGER (0); + break; + default: + return NULL; + break; + } + return NULL; +} + +#define OSPF_SNMP_METRIC_VALUE 1 + +struct interface * +ospfIfMetricLookup (struct variable *v, oid *name, size_t *length, + struct in_addr *ifaddr, unsigned int *ifindex, int exact) +{ + int len; + int ifaddr_next = 0; + int ifindex_next = 0; + struct interface *ifp; + oid *offset; + int metric; + + if (exact) + { + if (*length != v->namelen + IN_ADDR_SIZE + 1 + 1) + return NULL; + + oid2in_addr (name + v->namelen, IN_ADDR_SIZE, ifaddr); + *ifindex = name[v->namelen + IN_ADDR_SIZE]; + metric = name[v->namelen + IN_ADDR_SIZE + 1]; + + if (metric != OSPF_SNMP_METRIC_VALUE) + return NULL; + + return ospf_snmp_if_lookup (ifaddr, ifindex); + } + else + { + len = *length - v->namelen; + if (len >= IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + else + ifaddr_next = 1; + + oid2in_addr (name + v->namelen, len, ifaddr); + + len = *length - v->namelen - IN_ADDR_SIZE; + if (len >= 1) + len = 1; + else + ifindex_next = 1; + + if (len == 1) + *ifindex = name[v->namelen + IN_ADDR_SIZE]; + + ifp = ospf_snmp_if_lookup_next (ifaddr, ifindex, ifaddr_next, + ifindex_next); + if (ifp) + { + *length = v->namelen + IN_ADDR_SIZE + 1 + 1; + offset = name + v->namelen; + oid_copy_addr (offset, ifaddr, IN_ADDR_SIZE); + offset += IN_ADDR_SIZE; + *offset = *ifindex; + offset++; + *offset = OSPF_SNMP_METRIC_VALUE; + return ifp; + } + } + return NULL; +} + +static u_char * +ospfIfMetricEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + /* Currently we support metric 1 only. */ + struct interface *ifp; + unsigned int ifindex; + struct in_addr ifaddr; + struct ospf_interface *oi; + + ifindex = 0; + memset (&ifaddr, 0, sizeof (struct in_addr)); + + /* Check OSPF instance. */ + if (! ospf_top) + return NULL; + + ifp = ospfIfMetricLookup (v, name, length, &ifaddr, &ifindex, exact); + if (ifp == NULL) + return NULL; + + oi = ospf_if_lookup_by_local_addr (ifp, ifaddr); + if (oi == NULL) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFIFMETRICIPADDRESS: + return SNMP_IPADDRESS (ifaddr); + break; + case OSPFIFMETRICADDRESSLESSIF: + return SNMP_INTEGER (ifindex); + break; + case OSPFIFMETRICTOS: + return SNMP_INTEGER (0); + break; + case OSPFIFMETRICVALUE: + return SNMP_INTEGER (OSPF_SNMP_METRIC_VALUE); + break; + case OSPFIFMETRICSTATUS: + return SNMP_INTEGER (1); + break; + default: + return NULL; + break; + } + return NULL; +} + +struct route_table *ospf_snmp_vl_table; + +void +ospf_snmp_vl_add (struct ospf_vl_data *vl_data) +{ + struct prefix_ls lp; + struct route_node *rn; + + memset (&lp, 0, sizeof (struct prefix_ls)); + lp.family = 0; + lp.prefixlen = 64; + lp.id = vl_data->vl_area_id; + lp.adv_router = vl_data->vl_peer; + + rn = route_node_get (ospf_snmp_vl_table, (struct prefix *) &lp); + rn->info = vl_data; +} + +void +ospf_snmp_vl_delete (struct ospf_vl_data *vl_data) +{ + struct prefix_ls lp; + struct route_node *rn; + + memset (&lp, 0, sizeof (struct prefix_ls)); + lp.family = 0; + lp.prefixlen = 64; + lp.id = vl_data->vl_area_id; + lp.adv_router = vl_data->vl_peer; + + rn = route_node_lookup (ospf_snmp_vl_table, (struct prefix *) &lp); + if (! rn) + return; + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); +} + +struct ospf_vl_data * +ospf_snmp_vl_lookup (struct in_addr *area_id, struct in_addr *neighbor) +{ + struct prefix_ls lp; + struct route_node *rn; + struct ospf_vl_data *vl_data; + + memset (&lp, 0, sizeof (struct prefix_ls)); + lp.family = 0; + lp.prefixlen = 64; + lp.id = *area_id; + lp.adv_router = *neighbor; + + rn = route_node_lookup (ospf_snmp_vl_table, (struct prefix *) &lp); + if (rn) + { + vl_data = rn->info; + route_unlock_node (rn); + return vl_data; + } + return NULL; +} + +struct ospf_vl_data * +ospf_snmp_vl_lookup_next (struct in_addr *area_id, struct in_addr *neighbor, + int first) +{ + struct prefix_ls lp; + struct route_node *rn; + struct ospf_vl_data *vl_data; + + memset (&lp, 0, sizeof (struct prefix_ls)); + lp.family = 0; + lp.prefixlen = 64; + lp.id = *area_id; + lp.adv_router = *neighbor; + + if (first) + rn = route_top (ospf_snmp_vl_table); + else + { + rn = route_node_get (ospf_snmp_vl_table, (struct prefix *) &lp); + rn = route_next (rn); + } + + for (; rn; rn = route_next (rn)) + if (rn->info) + break; + + if (rn && rn->info) + { + vl_data = rn->info; + *area_id = vl_data->vl_area_id; + *neighbor = vl_data->vl_peer; + route_unlock_node (rn); + return vl_data; + } + return NULL; +} + +struct ospf_vl_data * +ospfVirtIfLookup (struct variable *v, oid *name, size_t *length, + struct in_addr *area_id, struct in_addr *neighbor, int exact) +{ + int first; + int len; + struct ospf_vl_data *vl_data; + + if (exact) + { + if (*length != v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE) + return NULL; + + oid2in_addr (name + v->namelen, IN_ADDR_SIZE, area_id); + oid2in_addr (name + v->namelen + IN_ADDR_SIZE, IN_ADDR_SIZE, neighbor); + + return ospf_snmp_vl_lookup (area_id, neighbor); + } + else + { + first = 0; + + len = *length - v->namelen; + if (len <= 0) + first = 1; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + oid2in_addr (name + v->namelen, len, area_id); + + len = *length - v->namelen - IN_ADDR_SIZE; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + oid2in_addr (name + v->namelen + IN_ADDR_SIZE, len, neighbor); + + vl_data = ospf_snmp_vl_lookup_next (area_id, neighbor, first); + + if (vl_data) + { + *length = v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE; + oid_copy_addr (name + v->namelen, area_id, IN_ADDR_SIZE); + oid_copy_addr (name + v->namelen + IN_ADDR_SIZE, neighbor, + IN_ADDR_SIZE); + return vl_data; + } + } + return NULL; +} + +static u_char * +ospfVirtIfEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct ospf_vl_data *vl_data; + struct ospf_interface *oi; + struct in_addr area_id; + struct in_addr neighbor; + + memset (&area_id, 0, sizeof (struct in_addr)); + memset (&neighbor, 0, sizeof (struct in_addr)); + + vl_data = ospfVirtIfLookup (v, name, length, &area_id, &neighbor, exact); + if (! vl_data) + return NULL; + oi = vl_data->vl_oi; + if (! oi) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFVIRTIFAREAID: + return SNMP_IPADDRESS (area_id); + break; + case OSPFVIRTIFNEIGHBOR: + return SNMP_IPADDRESS (neighbor); + break; + case OSPFVIRTIFTRANSITDELAY: + return SNMP_INTEGER (OSPF_IF_PARAM (oi, transmit_delay)); + break; + case OSPFVIRTIFRETRANSINTERVAL: + return SNMP_INTEGER (OSPF_IF_PARAM (oi, retransmit_interval)); + break; + case OSPFVIRTIFHELLOINTERVAL: + return SNMP_INTEGER (OSPF_IF_PARAM (oi, v_hello)); + break; + case OSPFVIRTIFRTRDEADINTERVAL: + return SNMP_INTEGER (OSPF_IF_PARAM (oi, v_wait)); + break; + case OSPFVIRTIFSTATE: + return SNMP_INTEGER (oi->state); + break; + case OSPFVIRTIFEVENTS: + return SNMP_INTEGER (oi->state_change); + break; + case OSPFVIRTIFAUTHKEY: + *var_len = 0; + return (u_char *) OSPF_IF_PARAM (oi, auth_simple); + break; + case OSPFVIRTIFSTATUS: + return SNMP_INTEGER (SNMP_VALID); + break; + case OSPFVIRTIFAUTHTYPE: + if (oi->area) + return SNMP_INTEGER (oi->area->auth_type); + else + return SNMP_INTEGER (0); + break; + default: + return NULL; + break; + } + return NULL; +} + +struct ospf_neighbor * +ospf_snmp_nbr_lookup (struct in_addr *nbr_addr, unsigned int *ifindex) +{ + struct listnode *nn; + struct ospf_interface *oi; + struct ospf_neighbor *nbr; + struct route_node *rn; + + LIST_LOOP (ospf_top->oiflist, oi, nn) + { + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL + && nbr != oi->nbr_self + && nbr->state != NSM_Down + && nbr->src.s_addr != 0) + { + if (IPV4_ADDR_SAME (&nbr->src, nbr_addr)) + { + route_unlock_node (rn); + return nbr; + } + } + } + return NULL; +} + +struct ospf_neighbor * +ospf_snmp_nbr_lookup_next (struct in_addr *nbr_addr, unsigned int *ifindex, + int first) +{ + struct listnode *nn; + struct ospf_interface *oi; + struct ospf_neighbor *nbr; + struct route_node *rn; + struct ospf_neighbor *min = NULL; + + LIST_LOOP (ospf_top->oiflist, oi, nn) + { + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL + && nbr != oi->nbr_self + && nbr->state != NSM_Down + && nbr->src.s_addr != 0) + { + if (first) + { + if (! min) + min = nbr; + else if (ntohl (nbr->src.s_addr) < ntohl (min->src.s_addr)) + min = nbr; + } + else if (ntohl (nbr->src.s_addr) > ntohl (nbr_addr->s_addr)) + { + if (! min) + min = nbr; + else if (ntohl (nbr->src.s_addr) < ntohl (min->src.s_addr)) + min = nbr; + } + } + } + if (min) + { + *nbr_addr = min->src; + *ifindex = 0; + return min; + } + return NULL; +} + +struct ospf_neighbor * +ospfNbrLookup (struct variable *v, oid *name, size_t *length, + struct in_addr *nbr_addr, unsigned int *ifindex, int exact) +{ + int len; + int first; + struct ospf_neighbor *nbr; + + if (exact) + { + if (*length != v->namelen + IN_ADDR_SIZE + 1) + return NULL; + + oid2in_addr (name + v->namelen, IN_ADDR_SIZE, nbr_addr); + *ifindex = name[v->namelen + IN_ADDR_SIZE]; + + return ospf_snmp_nbr_lookup (nbr_addr, ifindex); + } + else + { + first = 0; + len = *length - v->namelen; + + if (len <= 0) + first = 1; + + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (name + v->namelen, len, nbr_addr); + + len = *length - v->namelen - IN_ADDR_SIZE; + if (len >= 1) + *ifindex = name[v->namelen + IN_ADDR_SIZE]; + + nbr = ospf_snmp_nbr_lookup_next (nbr_addr, ifindex, first); + + if (nbr) + { + *length = v->namelen + IN_ADDR_SIZE + 1; + oid_copy_addr (name + v->namelen, nbr_addr, IN_ADDR_SIZE); + name[v->namelen + IN_ADDR_SIZE] = *ifindex; + return nbr; + } + } + return NULL; +} + +static u_char * +ospfNbrEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct in_addr nbr_addr; + unsigned int ifindex; + struct ospf_neighbor *nbr; + struct ospf_interface *oi; + + memset (&nbr_addr, 0, sizeof (struct in_addr)); + ifindex = 0; + + nbr = ospfNbrLookup (v, name, length, &nbr_addr, &ifindex, exact); + if (! nbr) + return NULL; + oi = nbr->oi; + if (! oi) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFNBRIPADDR: + return SNMP_IPADDRESS (nbr_addr); + break; + case OSPFNBRADDRESSLESSINDEX: + return SNMP_INTEGER (ifindex); + break; + case OSPFNBRRTRID: + return SNMP_IPADDRESS (nbr->router_id); + break; + case OSPFNBROPTIONS: + return SNMP_INTEGER (oi->nbr_self->options); + break; + case OSPFNBRPRIORITY: + return SNMP_INTEGER (nbr->priority); + break; + case OSPFNBRSTATE: + return SNMP_INTEGER (nbr->state); + break; + case OSPFNBREVENTS: + return SNMP_INTEGER (nbr->state_change); + break; + case OSPFNBRLSRETRANSQLEN: + return SNMP_INTEGER (ospf_ls_retransmit_count (nbr)); + break; + case OSPFNBMANBRSTATUS: + return SNMP_INTEGER (SNMP_VALID); + break; + case OSPFNBMANBRPERMANENCE: + return SNMP_INTEGER (2); + break; + case OSPFNBRHELLOSUPPRESSED: + return SNMP_INTEGER (SNMP_FALSE); + break; + default: + return NULL; + break; + } + return NULL; +} + +static u_char * +ospfVirtNbrEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct ospf_vl_data *vl_data; + struct in_addr area_id; + struct in_addr neighbor; + + memset (&area_id, 0, sizeof (struct in_addr)); + memset (&neighbor, 0, sizeof (struct in_addr)); + + /* Check OSPF instance. */ + if (! ospf_top) + return NULL; + + vl_data = ospfVirtIfLookup (v, name, length, &area_id, &neighbor, exact); + if (! vl_data) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFVIRTNBRAREA: + return (u_char *) NULL; + break; + case OSPFVIRTNBRRTRID: + return (u_char *) NULL; + break; + case OSPFVIRTNBRIPADDR: + return (u_char *) NULL; + break; + case OSPFVIRTNBROPTIONS: + return (u_char *) NULL; + break; + case OSPFVIRTNBRSTATE: + return (u_char *) NULL; + break; + case OSPFVIRTNBREVENTS: + return (u_char *) NULL; + break; + case OSPFVIRTNBRLSRETRANSQLEN: + return (u_char *) NULL; + break; + case OSPFVIRTNBRHELLOSUPPRESSED: + return (u_char *) NULL; + break; + default: + return NULL; + break; + } + return NULL; +} + +struct ospf_lsa * +ospfExtLsdbLookup (struct variable *v, oid *name, size_t *length, u_char *type, + struct in_addr *ls_id, struct in_addr *router_id, int exact) +{ + int first; + oid *offset; + int offsetlen; + u_char lsa_type; + int len; + struct ospf_lsa *lsa; + + if (exact) + { + if (*length != v->namelen + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE) + return NULL; + + offset = name + v->namelen; + + /* Make it sure given value match to type. */ + lsa_type = *offset; + offset++; + + if (lsa_type != *type) + return NULL; + + /* LS ID. */ + oid2in_addr (offset, IN_ADDR_SIZE, ls_id); + offset += IN_ADDR_SIZE; + + /* Router ID. */ + oid2in_addr (offset, IN_ADDR_SIZE, router_id); + + return ospf_lsdb_lookup_by_id (ospf_top->lsdb, *type, *ls_id, *router_id); + } + else + { + /* Get variable length. */ + first = 0; + offset = name + v->namelen; + offsetlen = *length - v->namelen; + + /* LSA type value. */ + lsa_type = *offset; + offset++; + offsetlen--; + + if (offsetlen <= 0 || lsa_type < OSPF_AS_EXTERNAL_LSA) + first = 1; + + /* LS ID. */ + len = offsetlen; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (offset, len, ls_id); + + offset += IN_ADDR_SIZE; + offsetlen -= IN_ADDR_SIZE; + + /* Router ID. */ + len = offsetlen; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (offset, len, router_id); + + lsa = ospf_lsdb_lookup_by_id_next (ospf_top->lsdb, *type, *ls_id, + *router_id, first); + + if (lsa) + { + /* Fill in length. */ + *length = v->namelen + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE; + + /* Fill in value. */ + offset = name + v->namelen; + + *offset = OSPF_AS_EXTERNAL_LSA; + offset++; + oid_copy_addr (offset, &lsa->data->id, IN_ADDR_SIZE); + offset += IN_ADDR_SIZE; + oid_copy_addr (offset, &lsa->data->adv_router, IN_ADDR_SIZE); + + return lsa; + } + } + return NULL; +} + +static u_char * +ospfExtLsdbEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct ospf_lsa *lsa; + struct lsa_header *lsah; + u_char type; + struct in_addr ls_id; + struct in_addr router_id; + + type = OSPF_AS_EXTERNAL_LSA; + memset (&ls_id, 0, sizeof (struct in_addr)); + memset (&router_id, 0, sizeof (struct in_addr)); + + /* Check OSPF instance. */ + if (! ospf_top) + return NULL; + + lsa = ospfExtLsdbLookup (v, name, length, &type, &ls_id, &router_id, exact); + if (! lsa) + return NULL; + + lsah = lsa->data; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFEXTLSDBTYPE: + return SNMP_INTEGER (OSPF_AS_EXTERNAL_LSA); + break; + case OSPFEXTLSDBLSID: + return SNMP_IPADDRESS (lsah->id); + break; + case OSPFEXTLSDBROUTERID: + return SNMP_IPADDRESS (lsah->adv_router); + break; + case OSPFEXTLSDBSEQUENCE: + return SNMP_INTEGER (lsah->ls_seqnum); + break; + case OSPFEXTLSDBAGE: + return SNMP_INTEGER (lsah->ls_age); + break; + case OSPFEXTLSDBCHECKSUM: + return SNMP_INTEGER (lsah->checksum); + break; + case OSPFEXTLSDBADVERTISEMENT: + *var_len = ntohs (lsah->length); + return (u_char *) lsah; + break; + default: + return NULL; + break; + } + return NULL; +} + +static u_char * +ospfAreaAggregateEntry (struct variable *v, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFAREAAGGREGATEAREAID: + return (u_char *) NULL; + break; + case OSPFAREAAGGREGATELSDBTYPE: + return (u_char *) NULL; + break; + case OSPFAREAAGGREGATENET: + return (u_char *) NULL; + break; + case OSPFAREAAGGREGATEMASK: + return (u_char *) NULL; + break; + case OSPFAREAAGGREGATESTATUS: + return (u_char *) NULL; + break; + case OSPFAREAAGGREGATEEFFECT: + return (u_char *) NULL; + break; + default: + return NULL; + break; + } + return NULL; +} + +/* Register OSPF2-MIB. */ +void +ospf_snmp_init () +{ + ospf_snmp_iflist = list_new (); + ospf_snmp_vl_table = route_table_init (); + smux_init (ospfd_oid, sizeof (ospfd_oid) / sizeof (oid)); + REGISTER_MIB("mibII/ospf", ospf_variables, variable, ospf_oid); + smux_start (); +} +#endif /* HAVE_SNMP */ diff --git a/ospfd/ospf_snmp.h b/ospfd/ospf_snmp.h new file mode 100644 index 00000000..d82f87b1 --- /dev/null +++ b/ospfd/ospf_snmp.h @@ -0,0 +1,33 @@ +/* OSPFv2 SNMP support + * Copyright (C) 2000 IP Infusion Inc. + * + * Written by Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_SNMP_H +#define _ZEBRA_OSPF_SNMP_H + +void ospf_snmp_if_update (struct interface *); +void ospf_snmp_if_delete (struct interface *); + +void ospf_snmp_vl_add (struct ospf_vl_data *); +void ospf_snmp_vl_delete (struct ospf_vl_data *); + +#endif /* _ZEBRA_OSPF_SNMP_H */ diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c new file mode 100644 index 00000000..d6254717 --- /dev/null +++ b/ospfd/ospf_spf.c @@ -0,0 +1,1088 @@ +/* OSPF SPF calculation. + Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "thread.h" +#include "memory.h" +#include "hash.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "log.h" +#include "sockunion.h" /* for inet_ntop () */ + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ia.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_dump.h" + +#define DEBUG + +struct vertex_nexthop * +vertex_nexthop_new (struct vertex *parent) +{ + struct vertex_nexthop *new; + + new = XCALLOC (MTYPE_OSPF_NEXTHOP, sizeof (struct vertex_nexthop)); + new->parent = parent; + + return new; +} + +void +vertex_nexthop_free (struct vertex_nexthop *nh) +{ + XFREE (MTYPE_OSPF_NEXTHOP, nh); +} + +struct vertex_nexthop * +vertex_nexthop_dup (struct vertex_nexthop *nh) +{ + struct vertex_nexthop *new; + + new = vertex_nexthop_new (nh->parent); + + new->oi = nh->oi; + new->router = nh->router; + + return new; +} + + +struct vertex * +ospf_vertex_new (struct ospf_lsa *lsa) +{ + struct vertex *new; + + new = XMALLOC (MTYPE_OSPF_VERTEX, sizeof (struct vertex)); + memset (new, 0, sizeof (struct vertex)); + + new->flags = 0; + new->type = lsa->data->type; + new->id = lsa->data->id; + new->lsa = lsa->data; + new->distance = 0; + new->child = list_new (); + new->nexthop = list_new (); + + return new; +} + +void +ospf_vertex_free (struct vertex *v) +{ + listnode node; + + list_delete (v->child); + + if (listcount (v->nexthop) > 0) + for (node = listhead (v->nexthop); node; nextnode (node)) + vertex_nexthop_free (node->data); + + list_delete (v->nexthop); + + XFREE (MTYPE_OSPF_VERTEX, v); +} + +void +ospf_vertex_add_parent (struct vertex *v) +{ + struct vertex_nexthop *nh; + listnode node; + + for (node = listhead (v->nexthop); node; nextnode (node)) + { + nh = (struct vertex_nexthop *) getdata (node); + + /* No need to add two links from the same parent. */ + if (listnode_lookup (nh->parent->child, v) == NULL) + listnode_add (nh->parent->child, v); + } +} + +void +ospf_spf_init (struct ospf_area *area) +{ + struct vertex *v; + + /* Create root node. */ + v = ospf_vertex_new (area->router_lsa_self); + + area->spf = v; + + /* Reset ABR and ASBR router counts. */ + area->abr_count = 0; + area->asbr_count = 0; +} + +int +ospf_spf_has_vertex (struct route_table *rv, struct route_table *nv, + struct lsa_header *lsa) +{ + struct prefix p; + struct route_node *rn; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = lsa->id; + + if (lsa->type == OSPF_ROUTER_LSA) + rn = route_node_get (rv, &p); + else + rn = route_node_get (nv, &p); + + if (rn->info != NULL) + { + route_unlock_node (rn); + return 1; + } + return 0; +} + +listnode +ospf_vertex_lookup (list vlist, struct in_addr id, int type) +{ + listnode node; + struct vertex *v; + + for (node = listhead (vlist); node; nextnode (node)) + { + v = (struct vertex *) getdata (node); + if (IPV4_ADDR_SAME (&id, &v->id) && type == v->type) + return node; + } + + return NULL; +} + +int +ospf_lsa_has_link (struct lsa_header *w, struct lsa_header *v) +{ + int i; + int length; + struct router_lsa *rl; + struct network_lsa *nl; + + /* In case of W is Network LSA. */ + if (w->type == OSPF_NETWORK_LSA) + { + if (v->type == OSPF_NETWORK_LSA) + return 0; + + nl = (struct network_lsa *) w; + length = (ntohs (w->length) - OSPF_LSA_HEADER_SIZE - 4) / 4; + + for (i = 0; i < length; i++) + if (IPV4_ADDR_SAME (&nl->routers[i], &v->id)) + return 1; + return 0; + } + + /* In case of W is Router LSA. */ + if (w->type == OSPF_ROUTER_LSA) + { + rl = (struct router_lsa *) w; + + length = ntohs (w->length); + + for (i = 0; + i < ntohs (rl->links) && length >= sizeof (struct router_lsa); + i++, length -= 12) + { + switch (rl->link[i].type) + { + case LSA_LINK_TYPE_POINTOPOINT: + case LSA_LINK_TYPE_VIRTUALLINK: + /* Router LSA ID. */ + if (v->type == OSPF_ROUTER_LSA && + IPV4_ADDR_SAME (&rl->link[i].link_id, &v->id)) + { + return 1; + } + break; + case LSA_LINK_TYPE_TRANSIT: + /* Network LSA ID. */ + if (v->type == OSPF_NETWORK_LSA && + IPV4_ADDR_SAME (&rl->link[i].link_id, &v->id)) + { + return 1; + } + break; + case LSA_LINK_TYPE_STUB: + /* Not take into count? */ + continue; + default: + break; + } + } + } + return 0; +} + +/* Add the nexthop to the list, only if it is unique. + * If it's not unique, free the nexthop entry. + */ +void +ospf_nexthop_add_unique (struct vertex_nexthop *new, list nexthop) +{ + struct vertex_nexthop *nh; + listnode node; + int match; + + match = 0; + for (node = listhead (nexthop); node; nextnode (node)) + { + nh = node->data; + + /* Compare the two entries. */ + /* XXX + * Comparing the parent preserves the shortest path tree + * structure even when the nexthops are identical. + */ + if (nh->oi == new->oi && + IPV4_ADDR_SAME (&nh->router, &new->router) && + nh->parent == new->parent) + { + match = 1; + break; + } + } + + if (!match) + listnode_add (nexthop, new); + else + vertex_nexthop_free (new); +} + +/* Merge entries in list b into list a. */ +void +ospf_nexthop_merge (list a, list b) +{ + struct listnode *n; + + for (n = listhead (b); n; nextnode (n)) + { + ospf_nexthop_add_unique (n->data, a); + } +} + +#define ROUTER_LSA_MIN_SIZE 12 +#define ROUTER_LSA_TOS_SIZE 4 + +struct router_lsa_link * +ospf_get_next_link (struct vertex *v, struct vertex *w, + struct router_lsa_link *prev_link) +{ + u_char *p; + u_char *lim; + struct router_lsa_link *l; + + if (prev_link == NULL) + p = ((u_char *) v->lsa) + 24; + else + { + p = (u_char *)prev_link; + p += (ROUTER_LSA_MIN_SIZE + + (prev_link->m[0].tos_count * ROUTER_LSA_TOS_SIZE)); + } + + lim = ((u_char *) v->lsa) + ntohs (v->lsa->length); + + while (p < lim) + { + l = (struct router_lsa_link *) p; + + p += (ROUTER_LSA_MIN_SIZE + + (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE)); + + if (l->m[0].type == LSA_LINK_TYPE_STUB) + continue; + + /* Defer NH calculation via VLs until summaries from + transit areas area confidered */ + + if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK) + continue; + + if (IPV4_ADDR_SAME (&l->link_id, &w->id)) + return l; + } + + return NULL; +} + +/* Calculate nexthop from root to vertex W. */ +void +ospf_nexthop_calculation (struct ospf_area *area, + struct vertex *v, struct vertex *w) +{ + listnode node; + struct vertex_nexthop *nh, *x; + struct ospf_interface *oi = NULL; + struct router_lsa_link *l = NULL; + + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_nexthop_calculation(): Start"); + + /* W's parent is root. */ + if (v == area->spf) + { + if (w->type == OSPF_VERTEX_ROUTER) + { + while ((l = ospf_get_next_link (v, w, l))) + { + struct router_lsa_link *l2 = NULL; + + if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT) + { + while ((l2 = ospf_get_next_link (w, v, l2))) + { + oi = ospf_if_is_configured (&(l2->link_data)); + + if (oi == NULL) + continue; + + if (! IPV4_ADDR_SAME (&oi->address->u.prefix4, + &l->link_data)) + continue; + + break; + } + + if (oi && l2) + { + nh = vertex_nexthop_new (v); + nh->oi = oi; + nh->router = l2->link_data; + listnode_add (w->nexthop, nh); + } + } + } + } + else + { + while ((l = ospf_get_next_link (v, w, l))) + { + oi = ospf_if_is_configured (&(l->link_data)); + if (oi) + { + nh = vertex_nexthop_new (v); + nh->oi = oi; + nh->router.s_addr = 0; + listnode_add (w->nexthop, nh); + } + } + } + return; + } + /* In case of W's parent is network connected to root. */ + else if (v->type == OSPF_VERTEX_NETWORK) + { + for (node = listhead (v->nexthop); node; nextnode (node)) + { + x = (struct vertex_nexthop *) getdata (node); + if (x->parent == area->spf) + { + while ((l = ospf_get_next_link (w, v, l))) + { + nh = vertex_nexthop_new (v); + nh->oi = x->oi; + nh->router = l->link_data; + listnode_add (w->nexthop, nh); + } + return; + } + } + } + + /* Inherit V's nexthop. */ + for (node = listhead (v->nexthop); node; nextnode (node)) + { + nh = vertex_nexthop_dup (node->data); + nh->parent = v; + ospf_nexthop_add_unique (nh, w->nexthop); + } +} + +void +ospf_install_candidate (list candidate, struct vertex *w) +{ + listnode node; + struct vertex *cw; + + if (list_isempty (candidate)) + { + listnode_add (candidate, w); + return; + } + + /* Install vertex with sorting by distance. */ + for (node = listhead (candidate); node; nextnode (node)) + { + cw = (struct vertex *) getdata (node); + if (cw->distance > w->distance) + { + list_add_node_prev (candidate, node, w); + break; + } + else if (node->next == NULL) + { + list_add_node_next (candidate, node, w); + break; + } + } +} + +/* RFC2328 Section 16.1 (2). */ +void +ospf_spf_next (struct vertex *v, struct ospf_area *area, + list candidate, struct route_table *rv, + struct route_table *nv) +{ + struct ospf_lsa *w_lsa = NULL; + struct vertex *w, *cw; + u_char *p; + u_char *lim; + struct router_lsa_link *l = NULL; + struct in_addr *r; + listnode node; + int type = 0; + + /* If this is a router-LSA, and bit V of the router-LSA (see Section + A.4.2:RFC2328) is set, set Area A's TransitCapability to TRUE. */ + if (v->type == OSPF_VERTEX_ROUTER) + { + if (IS_ROUTER_LSA_VIRTUAL ((struct router_lsa *) v->lsa)) + area->transit = OSPF_TRANSIT_TRUE; + } + + p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4; + lim = ((u_char *) v->lsa) + ntohs (v->lsa->length); + + while (p < lim) + { + /* In case of V is Router-LSA. */ + if (v->lsa->type == OSPF_ROUTER_LSA) + { + l = (struct router_lsa_link *) p; + + p += (ROUTER_LSA_MIN_SIZE + + (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE)); + + /* (a) If this is a link to a stub network, examine the next + link in V's LSA. Links to stub networks will be + considered in the second stage of the shortest path + calculation. */ + if ((type = l->m[0].type) == LSA_LINK_TYPE_STUB) + continue; + + /* (b) Otherwise, W is a transit vertex (router or transit + network). Look up the vertex W's LSA (router-LSA or + network-LSA) in Area A's link state database. */ + switch (type) + { + case LSA_LINK_TYPE_POINTOPOINT: + case LSA_LINK_TYPE_VIRTUALLINK: + if (type == LSA_LINK_TYPE_VIRTUALLINK) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("looking up LSA through VL: %s", + inet_ntoa (l->link_id)); + } + + w_lsa = ospf_lsa_lookup (area, OSPF_ROUTER_LSA, l->link_id, + l->link_id); + if (w_lsa) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info("found the LSA"); + } + break; + case LSA_LINK_TYPE_TRANSIT: + if (IS_DEBUG_OSPF_EVENT) + + zlog_info ("Looking up Network LSA, ID: %s", + inet_ntoa(l->link_id)); + w_lsa = ospf_lsa_lookup_by_id (area, OSPF_NETWORK_LSA, + l->link_id); + if (w_lsa) + if (IS_DEBUG_OSPF_EVENT) + zlog_info("found the LSA"); + break; + default: + zlog_warn ("Invalid LSA link type %d", type); + continue; + } + } + else + { + /* In case of V is Network-LSA. */ + r = (struct in_addr *) p ; + p += sizeof (struct in_addr); + + /* Lookup the vertex W's LSA. */ + w_lsa = ospf_lsa_lookup_by_id (area, OSPF_ROUTER_LSA, *r); + } + + /* (b cont.) If the LSA does not exist, or its LS age is equal + to MaxAge, or it does not have a link back to vertex V, + examine the next link in V's LSA.[23] */ + if (w_lsa == NULL) + continue; + + if (IS_LSA_MAXAGE (w_lsa)) + continue; + + if (! ospf_lsa_has_link (w_lsa->data, v->lsa)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("The LSA doesn't have a link back"); + continue; + } + + /* (c) If vertex W is already on the shortest-path tree, examine + the next link in the LSA. */ + if (ospf_spf_has_vertex (rv, nv, w_lsa->data)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("The LSA is already in SPF"); + continue; + } + + /* (d) Calculate the link state cost D of the resulting path + from the root to vertex W. D is equal to the sum of the link + state cost of the (already calculated) shortest path to + vertex V and the advertised cost of the link between vertices + V and W. If D is: */ + + /* prepare vertex W. */ + w = ospf_vertex_new (w_lsa); + + /* calculate link cost D. */ + if (v->lsa->type == OSPF_ROUTER_LSA) + w->distance = v->distance + ntohs (l->m[0].metric); + else + w->distance = v->distance; + + /* Is there already vertex W in candidate list? */ + node = ospf_vertex_lookup (candidate, w->id, w->type); + if (node == NULL) + { + /* Calculate nexthop to W. */ + ospf_nexthop_calculation (area, v, w); + + ospf_install_candidate (candidate, w); + } + else + { + cw = (struct vertex *) getdata (node); + + /* if D is greater than. */ + if (cw->distance < w->distance) + { + ospf_vertex_free (w); + continue; + } + /* equal to. */ + else if (cw->distance == w->distance) + { + /* Calculate nexthop to W. */ + ospf_nexthop_calculation (area, v, w); + ospf_nexthop_merge (cw->nexthop, w->nexthop); + list_delete_all_node (w->nexthop); + ospf_vertex_free (w); + } + /* less than. */ + else + { + /* Calculate nexthop. */ + ospf_nexthop_calculation (area, v, w); + + /* Remove old vertex from candidate list. */ + ospf_vertex_free (cw); + listnode_delete (candidate, cw); + + /* Install new to candidate. */ + ospf_install_candidate (candidate, w); + } + } + } +} + +/* Add vertex V to SPF tree. */ +void +ospf_spf_register (struct vertex *v, struct route_table *rv, + struct route_table *nv) +{ + struct prefix p; + struct route_node *rn; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = v->id; + + if (v->type == OSPF_VERTEX_ROUTER) + rn = route_node_get (rv, &p); + else + rn = route_node_get (nv, &p); + + rn->info = v; +} + +void +ospf_spf_route_free (struct route_table *table) +{ + struct route_node *rn; + struct vertex *v; + + for (rn = route_top (table); rn; rn = route_next (rn)) + { + if ((v = rn->info)) + { + ospf_vertex_free (v); + rn->info = NULL; + } + + route_unlock_node (rn); + } + + route_table_finish (table); +} + +void +ospf_spf_dump (struct vertex *v, int i) +{ + listnode cnode; + listnode nnode; + struct vertex_nexthop *nexthop; + + if (v->type == OSPF_VERTEX_ROUTER) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("SPF Result: %d [R] %s", i, inet_ntoa (v->lsa->id)); + } + else + { + struct network_lsa *lsa = (struct network_lsa *) v->lsa; + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("SPF Result: %d [N] %s/%d", i, inet_ntoa (v->lsa->id), + ip_masklen (lsa->mask)); + + for (nnode = listhead (v->nexthop); nnode; nextnode (nnode)) + { + nexthop = getdata (nnode); + if (IS_DEBUG_OSPF_EVENT) + zlog_info (" nexthop %s", inet_ntoa (nexthop->router)); + } + } + + i++; + + for (cnode = listhead (v->child); cnode; nextnode (cnode)) + { + v = getdata (cnode); + ospf_spf_dump (v, i); + } +} + +/* Second stage of SPF calculation. */ +void +ospf_spf_process_stubs (struct ospf_area *area, struct vertex * v, + struct route_table *rt) +{ + listnode cnode; + struct vertex *child; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_process_stub():processing stubs for area %s", + inet_ntoa (area->area_id)); + if (v->type == OSPF_VERTEX_ROUTER) + { + u_char *p; + u_char *lim; + struct router_lsa_link *l; + struct router_lsa *rlsa; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_process_stub():processing router LSA, id: %s", + inet_ntoa (v->lsa->id)); + rlsa = (struct router_lsa *) v->lsa; + + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_process_stub(): we have %d links to process", + ntohs (rlsa->links)); + p = ((u_char *) v->lsa) + 24; + lim = ((u_char *) v->lsa) + ntohs (v->lsa->length); + + while (p < lim) + { + l = (struct router_lsa_link *) p; + + p += (ROUTER_LSA_MIN_SIZE + + (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE)); + + if (l->m[0].type == LSA_LINK_TYPE_STUB) + ospf_intra_add_stub (rt, l, v, area); + } + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("children of V:"); + for (cnode = listhead (v->child); cnode; nextnode (cnode)) + { + child = getdata (cnode); + if (IS_DEBUG_OSPF_EVENT) + zlog_info (" child : %s", inet_ntoa (child->id)); + } + + for (cnode = listhead (v->child); cnode; nextnode (cnode)) + { + child = getdata (cnode); + + if (CHECK_FLAG (child->flags, OSPF_VERTEX_PROCESSED)) + continue; + + ospf_spf_process_stubs (area, child, rt); + + SET_FLAG (child->flags, OSPF_VERTEX_PROCESSED); + } +} + +void +ospf_rtrs_free (struct route_table *rtrs) +{ + struct route_node *rn; + list or_list; + listnode node; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Route: Router Routing Table free"); + + for (rn = route_top (rtrs); rn; rn = route_next (rn)) + if ((or_list = rn->info) != NULL) + { + for (node = listhead (or_list); node; nextnode (node)) + ospf_route_free (node->data); + + list_delete (or_list); + + /* Unlock the node. */ + rn->info = NULL; + route_unlock_node (rn); + } + route_table_finish (rtrs); +} + +void +ospf_rtrs_print (struct route_table *rtrs) +{ + struct route_node *rn; + list or_list; + listnode ln; + listnode pnode; + struct ospf_route *or; + struct ospf_path *path; + char buf1[BUFSIZ]; + char buf2[BUFSIZ]; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_rtrs_print() start"); + + for (rn = route_top (rtrs); rn; rn = route_next (rn)) + if ((or_list = rn->info) != NULL) + for (ln = listhead (or_list); ln; nextnode (ln)) + { + or = getdata (ln); + + switch (or->path_type) + { + case OSPF_PATH_INTRA_AREA: + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("%s [%d] area: %s", + inet_ntop (AF_INET, &or->id, buf1, BUFSIZ), or->cost, + inet_ntop (AF_INET, &or->u.std.area_id, + buf2, BUFSIZ)); + break; + case OSPF_PATH_INTER_AREA: + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("%s IA [%d] area: %s", + inet_ntop (AF_INET, &or->id, buf1, BUFSIZ), or->cost, + inet_ntop (AF_INET, &or->u.std.area_id, + buf2, BUFSIZ)); + break; + default: + break; + } + + for (pnode = listhead (or->path); pnode; nextnode (pnode)) + { + path = getdata (pnode); + if (path->nexthop.s_addr == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info (" directly attached to %s\r\n", + IF_NAME (path->oi)); + } + else + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info (" via %s, %s\r\n", + inet_ntoa (path->nexthop), IF_NAME (path->oi)); + } + } + } + + zlog_info ("ospf_rtrs_print() end"); +} + +/* Calculating the shortest-path tree for an area. */ +void +ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table, + struct route_table *new_rtrs) +{ + list candidate; + listnode node; + struct vertex *v; + struct route_table *rv; + struct route_table *nv; + + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("ospf_spf_calculate: Start"); + zlog_info ("ospf_spf_calculate: running Dijkstra for area %s", + inet_ntoa (area->area_id)); + } + + /* Check router-lsa-self. If self-router-lsa is not yet allocated, + return this area's calculation. */ + if (! area->router_lsa_self) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_spf_calculate: " + "Skip area %s's calculation due to empty router_lsa_self", + inet_ntoa (area->area_id)); + return; + } + + /* RFC2328 16.1. (1). */ + /* Initialize the algorithm's data structures. */ + rv = route_table_init (); + nv = route_table_init (); + + /* Clear the list of candidate vertices. */ + candidate = list_new (); + + /* Initialize the shortest-path tree to only the root (which is the + router doing the calculation). */ + ospf_spf_init (area); + v = area->spf; + ospf_spf_register (v, rv, nv); + + /* Set Area A's TransitCapability to FALSE. */ + area->transit = OSPF_TRANSIT_FALSE; + area->shortcut_capability = 1; + + for (;;) + { + /* RFC2328 16.1. (2). */ + ospf_spf_next (v, area, candidate, rv, nv); + + /* RFC2328 16.1. (3). */ + /* If at this step the candidate list is empty, the shortest- + path tree (of transit vertices) has been completely built and + this stage of the procedure terminates. */ + if (listcount (candidate) == 0) + break; + + /* Otherwise, choose the vertex belonging to the candidate list + that is closest to the root, and add it to the shortest-path + tree (removing it from the candidate list in the + process). */ + node = listhead (candidate); + v = getdata (node); + ospf_vertex_add_parent (v); + + /* Reveve from the candidate list. */ + listnode_delete (candidate, v); + + /* Add to SPF tree. */ + ospf_spf_register (v, rv, nv); + + /* Note that when there is a choice of vertices closest to the + root, network vertices must be chosen before router vertices + in order to necessarily find all equal-cost paths. */ + /* We don't do this at this moment, we should add the treatment + above codes. -- kunihiro. */ + + /* RFC2328 16.1. (4). */ + if (v->type == OSPF_VERTEX_ROUTER) + ospf_intra_add_router (new_rtrs, v, area); + else + ospf_intra_add_transit (new_table, v, area); + + /* RFC2328 16.1. (5). */ + /* Iterate the algorithm by returning to Step 2. */ + } + + if (IS_DEBUG_OSPF_EVENT) + { + ospf_spf_dump (area->spf, 0); + ospf_route_table_dump (new_table); + } + + /* Second stage of SPF calculation procedure's */ + ospf_spf_process_stubs (area, area->spf, new_table); + + /* Free all vertices which allocated for SPF calculation */ + ospf_spf_route_free (rv); + ospf_spf_route_free (nv); + + /* Free candidate list */ + list_free (candidate); + + /* Increment SPF Calculation Counter. */ + area->spf_calculation++; + + ospf_top->ts_spf = time (NULL); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_spf_calculate: Stop"); +} + +/* Timer for SPF calculation. */ +int +ospf_spf_calculate_timer (struct thread *t) +{ + struct route_table *new_table, *new_rtrs; + struct ospf *ospf; + /* struct ospf_area *area; */ + listnode node; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("SPF: Timer (SPF calculation expire)"); + + ospf = THREAD_ARG (t); + ospf->t_spf_calc = NULL; + + /* Allocate new table tree. */ + new_table = route_table_init (); + new_rtrs = route_table_init (); + + ospf_vl_unapprove (); + + /* Calculate SPF for each area. */ + for (node = listhead (ospf->areas); node; node = nextnode (node)) + ospf_spf_calculate (node->data, new_table, new_rtrs); + + ospf_vl_shut_unapproved (); + + ospf_ia_routing (new_table, new_rtrs); + + ospf_prune_unreachable_networks (new_table); + ospf_prune_unreachable_routers (new_rtrs); + + /* AS-external-LSA calculation should not be performed here. */ + + /* If new Router Route is installed, + then schedule re-calculate External routes. */ + if (1) + ospf_ase_calculate_schedule (); + + ospf_ase_calculate_timer_add (); + + /* Update routing table. */ + ospf_route_install (new_table); + + /* Update ABR/ASBR routing table */ + if (ospf_top->old_rtrs) + { + /* old_rtrs's node holds linked list of ospf_route. --kunihiro. */ + /* ospf_route_delete (ospf_top->old_rtrs); */ + ospf_rtrs_free (ospf_top->old_rtrs); + } + + ospf_top->old_rtrs = ospf_top->new_rtrs; + ospf_top->new_rtrs = new_rtrs; + + if (OSPF_IS_ABR) + ospf_abr_task (new_table, new_rtrs); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("SPF: calculation complete"); + + return 0; +} + +/* Add schedule for SPF calculation. To avoid frequenst SPF calc, we + set timer for SPF calc. */ +void +ospf_spf_calculate_schedule () +{ + time_t ht, delay; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("SPF: calculation timer scheduled"); + + /* OSPF instance does not exist. */ + if (!ospf_top) + return; + + /* SPF calculation timer is already scheduled. */ + if (ospf_top->t_spf_calc) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("SPF: calculation timer is already scheduled: %p", + ospf_top->t_spf_calc); + return; + } + + ht = time (NULL) - ospf_top->ts_spf; + + /* Get SPF calculation delay time. */ + if (ht < ospf_top->spf_holdtime) + { + if (ospf_top->spf_holdtime - ht < ospf_top->spf_delay) + delay = ospf_top->spf_delay; + else + delay = ospf_top->spf_holdtime - ht; + } + else + delay = ospf_top->spf_delay; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("SPF: calculation timer delay = %ld", delay); + ospf_top->t_spf_calc = + thread_add_timer (master, ospf_spf_calculate_timer, ospf_top, delay); +} + diff --git a/ospfd/ospf_spf.h b/ospfd/ospf_spf.h new file mode 100644 index 00000000..7fe682ee --- /dev/null +++ b/ospfd/ospf_spf.h @@ -0,0 +1,50 @@ +/* + * OSPF calculation. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#define OSPF_VERTEX_ROUTER 1 +#define OSPF_VERTEX_NETWORK 2 + +#define OSPF_VERTEX_PROCESSED 0x01 + + +struct vertex +{ + u_char flags; + u_char type; + struct in_addr id; + struct lsa_header *lsa; + u_int32_t distance; + list child; + list nexthop; +}; + +struct vertex_nexthop +{ + struct ospf_interface *oi; + struct in_addr router; + struct vertex *parent; +}; + +void ospf_spf_calculate_schedule (); +void ospf_rtrs_free (struct route_table *); + +/* void ospf_spf_calculate_timer_add (); */ diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c new file mode 100644 index 00000000..aedac32a --- /dev/null +++ b/ospfd/ospf_te.c @@ -0,0 +1,1921 @@ +/* + * This is an implementation of draft-katz-yeung-ospf-traffic-06.txt + * Copyright (C) 2001 KDD R&D Laboratories, Inc. + * http://www.kddlabs.co.jp/ + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/***** MTYPE definition is not reflected to "memory.h" yet. *****/ +#define MTYPE_OSPF_MPLS_TE_LINKPARAMS 0 + +#include + +#ifdef HAVE_OSPF_TE +#ifndef HAVE_OPAQUE_LSA +#error "Wrong configure option" +#endif /* HAVE_OPAQUE_LSA */ + +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "memory.h" +#include "command.h" +#include "vty.h" +#include "stream.h" +#include "log.h" +#include "thread.h" +#include "hash.h" +#include "sockunion.h" /* for inet_aton() */ + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_te.h" + +/* Following structure are internal use only. */ +struct ospf_mpls_te +{ + enum { disabled, enabled } status; + + /* List elements are zebra-interfaces (ifp), not ospf-interfaces (oi). */ + list iflist; + + /* Store Router-TLV in network byte order. */ + struct te_tlv_router_addr router_addr; +}; + +struct mpls_te_link +{ + /* + * According to MPLS-TE (draft) specification, 24-bit Opaque-ID field + * is subdivided into 8-bit "unused" field and 16-bit "instance" field. + * In this implementation, each Link-TLV has its own instance. + */ + u_int32_t instance; + + /* Reference pointer to a Zebra-interface. */ + struct interface *ifp; + + /* Area info in which this MPLS-TE link belongs to. */ + struct ospf_area *area; + + /* Flags to manage this link parameters. */ + u_int32_t flags; +#define LPFLG_LOOKUP_DONE 0x1 +#define LPFLG_LSA_ENGAGED 0x2 +#define LPFLG_LSA_FORCED_REFRESH 0x4 + + /* Store Link-TLV in network byte order. */ + struct te_tlv_link link_header; + struct te_link_subtlv_link_type link_type; + struct te_link_subtlv_link_id link_id; + struct te_link_subtlv_lclif_ipaddr *lclif_ipaddr; + struct te_link_subtlv_rmtif_ipaddr *rmtif_ipaddr; + struct te_link_subtlv_te_metric te_metric; + struct te_link_subtlv_max_bw max_bw; + struct te_link_subtlv_max_rsv_bw max_rsv_bw; + struct te_link_subtlv_unrsv_bw unrsv_bw; + struct te_link_subtlv_rsc_clsclr rsc_clsclr; +}; + +/* + * Global variable to manage Opaque-LSA/MPLS-TE on this node. + * Note that all parameter values are stored in network byte order. + */ +static struct ospf_mpls_te OspfMplsTE; + +enum oifstate { + OI_ANY, OI_DOWN, OI_UP +}; + +enum sched_opcode { + REORIGINATE_PER_AREA, REFRESH_THIS_LSA, FLUSH_THIS_LSA +}; + +/*------------------------------------------------------------------------* + * Followings are initialize/terminate functions for MPLS-TE handling. + *------------------------------------------------------------------------*/ + +static int ospf_mpls_te_new_if (struct interface *ifp); +static int ospf_mpls_te_del_if (struct interface *ifp); +static void ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_status); +static void ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_status); +static void ospf_mpls_te_config_write_router (struct vty *vty); +static void ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp); +static void ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa); +static int ospf_mpls_te_lsa_originate (void *arg); +static void ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa); +static void ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, enum sched_opcode); + +static void del_mpls_te_link (void *val); +static void ospf_mpls_te_register_vty (void); + +int +ospf_mpls_te_init (void) +{ + int rc; + + rc = ospf_register_opaque_functab ( + OSPF_OPAQUE_AREA_LSA, + OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, + ospf_mpls_te_new_if, + ospf_mpls_te_del_if, + ospf_mpls_te_ism_change, + ospf_mpls_te_nsm_change, + ospf_mpls_te_config_write_router, + ospf_mpls_te_config_write_if, + NULL,/* ospf_mpls_te_config_write_debug */ + ospf_mpls_te_show_info, + ospf_mpls_te_lsa_originate, + ospf_mpls_te_lsa_refresh, + NULL,/* ospf_mpls_te_new_lsa_hook */ + NULL /* ospf_mpls_te_del_lsa_hook */); + if (rc != 0) + { + zlog_warn ("ospf_mpls_te_init: Failed to register functions"); + goto out; + } + + memset (&OspfMplsTE, 0, sizeof (struct ospf_mpls_te)); + OspfMplsTE.status = disabled; + OspfMplsTE.iflist = list_new (); + OspfMplsTE.iflist->del = del_mpls_te_link; + + ospf_mpls_te_register_vty (); + +out: + return rc; +} + +void +ospf_mpls_te_term (void) +{ + list_delete (OspfMplsTE.iflist); + + OspfMplsTE.iflist = NULL; + OspfMplsTE.status = disabled; + + ospf_delete_opaque_functab (OSPF_OPAQUE_AREA_LSA, + OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); + return; +} + +/*------------------------------------------------------------------------* + * Followings are control functions for MPLS-TE parameters management. + *------------------------------------------------------------------------*/ + +static void +del_mpls_te_link (void *val) +{ + XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, val); + return; +} + +static u_int32_t +get_mpls_te_instance_value () +{ + static u_int32_t seqno = 0; + + if (LEGAL_TE_INSTANCE_RANGE (seqno + 1)) + seqno += 1; + else + seqno = 1; /* Avoid zero. */ + + return seqno; +} + +static struct ospf_interface * +lookup_oi_by_ifp (struct interface *ifp, + struct ospf_area *area, enum oifstate oifstate) +{ + struct ospf_interface *oi = NULL; + struct route_node *rn; + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + if ((oi = rn->info) == NULL) + continue; + + switch (oifstate) + { + case OI_ANY: + break; + case OI_DOWN: + if (ospf_if_is_enable (oi)) + continue; + break; + case OI_UP: + if (! ospf_if_is_enable (oi)) + continue; + break; + default: + zlog_warn ("lookup_oi_by_ifp: Unknown oifstate: %x", oifstate); + goto out; + } + + if (area == NULL || oi->area == area) + return oi; + } +out: + return NULL; +} + +static struct mpls_te_link * +lookup_linkparams_by_ifp (struct interface *ifp) +{ + listnode node; + struct mpls_te_link *lp; + + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + if ((lp = getdata (node)) != NULL) + if (lp->ifp == ifp) + return lp; + + return NULL; +} + +static struct mpls_te_link * +lookup_linkparams_by_instance (struct ospf_lsa *lsa) +{ + listnode node; + struct mpls_te_link *lp; + int key = GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)); + + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + if ((lp = getdata (node)) != NULL) + if (lp->instance == key) + return lp; + + zlog_warn ("lookup_linkparams_by_instance: Entry not found: key(%x)", key); + return NULL; +} + +static void +ospf_mpls_te_foreach_area ( + void (*func)(struct mpls_te_link *lp, enum sched_opcode), + enum sched_opcode sched_opcode) +{ + listnode node, node2; + struct mpls_te_link *lp; + struct ospf_area *area; + + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + { + if ((lp = getdata (node)) == NULL) + continue; + if ((area = lp->area) == NULL) + continue; + if (lp->flags & LPFLG_LOOKUP_DONE) + continue; + + if (func != NULL) + (* func)(lp, sched_opcode); + + for (node2 = nextnode (node); node2; nextnode (node2)) + if ((lp = getdata (node2)) != NULL) + if (lp->area != NULL) + if (IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id)) + lp->flags |= LPFLG_LOOKUP_DONE; + } + + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + if ((lp = getdata (node)) != NULL) + if (lp->area != NULL) + lp->flags &= ~LPFLG_LOOKUP_DONE; + + return; +} + +static void +set_mpls_te_router_addr (struct in_addr ipv4) +{ + OspfMplsTE.router_addr.header.type = htons (TE_TLV_ROUTER_ADDR); + OspfMplsTE.router_addr.header.length = htons (sizeof (ipv4)); + OspfMplsTE.router_addr.value = ipv4; + return; +} + +static void +set_linkparams_link_header (struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh; + u_int16_t length = 0; + + /* TE_LINK_SUBTLV_LINK_TYPE */ + if (ntohs (lp->link_type.header.type) != 0) + length += TLV_SIZE (&lp->link_type.header); + + /* TE_LINK_SUBTLV_LINK_ID */ + if (ntohs (lp->link_id.header.type) != 0) + length += TLV_SIZE (&lp->link_id.header); + + /* TE_LINK_SUBTLV_LCLIF_IPADDR */ + if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL + && ntohs (tlvh->type) != 0) + length += TLV_SIZE (tlvh); + + /* TE_LINK_SUBTLV_RMTIF_IPADDR */ + if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL + && ntohs (tlvh->type) != 0) + length += TLV_SIZE (tlvh); + + /* TE_LINK_SUBTLV_TE_METRIC */ + if (ntohs (lp->te_metric.header.type) != 0) + length += TLV_SIZE (&lp->te_metric.header); + + /* TE_LINK_SUBTLV_MAX_BW */ + if (ntohs (lp->max_bw.header.type) != 0) + length += TLV_SIZE (&lp->max_bw.header); + + /* TE_LINK_SUBTLV_MAX_RSV_BW */ + if (ntohs (lp->max_rsv_bw.header.type) != 0) + length += TLV_SIZE (&lp->max_rsv_bw.header); + + /* TE_LINK_SUBTLV_UNRSV_BW */ + if (ntohs (lp->unrsv_bw.header.type) != 0) + length += TLV_SIZE (&lp->unrsv_bw.header); + + /* TE_LINK_SUBTLV_RSC_CLSCLR */ + if (ntohs (lp->rsc_clsclr.header.type) != 0) + length += TLV_SIZE (&lp->rsc_clsclr.header); + + lp->link_header.header.type = htons (TE_TLV_LINK); + lp->link_header.header.length = htons (length); + + return; +} + +static void +set_linkparams_link_type (struct ospf_interface *oi, struct mpls_te_link *lp) +{ + lp->link_type.header.type = htons (TE_LINK_SUBTLV_LINK_TYPE); + lp->link_type.header.length = htons (sizeof (lp->link_type.link_type.value)); + + switch (oi->type) + { + case OSPF_IFTYPE_POINTOPOINT: + lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_PTP; + break; + case OSPF_IFTYPE_BROADCAST: + case OSPF_IFTYPE_NBMA: + lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_MA; + break; + default: + /* Not supported yet. *//* XXX */ + lp->link_type.header.type = htons (0); + break; + } + return; +} + +static void +set_linkparams_link_id (struct ospf_interface *oi, struct mpls_te_link *lp) +{ + struct ospf_neighbor *nbr; + int done = 0; + + lp->link_id.header.type = htons (TE_LINK_SUBTLV_LINK_ID); + lp->link_id.header.length = htons (sizeof (lp->link_id.value)); + + /* + * The Link ID is identical to the contents of the Link ID field + * in the Router LSA for these link types. + */ + switch (oi->type) + { + case OSPF_IFTYPE_POINTOPOINT: + /* Take the router ID of the neighbor. */ + if (((nbr = ospf_nbr_lookup_ptop (oi->nbrs, oi->area->top->router_id))) + && (nbr->state == NSM_Full)) + { + lp->link_id.value = nbr->router_id; + done = 1; + } + break; + case OSPF_IFTYPE_BROADCAST: + case OSPF_IFTYPE_NBMA: + /* Take the interface address of the designated router. */ + if ((nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &DR (oi))) == NULL) + break; + + if (nbr->state == NSM_Full + || (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi)) + && ospf_nbr_count (oi->nbrs, NSM_Full) > 0)) + { + lp->link_id.value = DR (oi); + done = 1; + } + break; + default: + /* Not supported yet. *//* XXX */ + lp->link_id.header.type = htons (0); + break; + } + + if (! done) + { + struct in_addr mask; + masklen2ip (oi->address->prefixlen, &mask); + lp->link_id.value.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; + } + return; +} + +static void +set_linkparams_te_metric (struct mpls_te_link *lp, u_int32_t te_metric) +{ + lp->te_metric.header.type = htons (TE_LINK_SUBTLV_TE_METRIC); + lp->te_metric.header.length = htons (sizeof (lp->te_metric.value)); + lp->te_metric.value = htonl (te_metric); + return; +} + +static void +set_linkparams_max_bw (struct mpls_te_link *lp, float *fp) +{ + lp->max_bw.header.type = htons (TE_LINK_SUBTLV_MAX_BW); + lp->max_bw.header.length = htons (sizeof (lp->max_bw.value)); + htonf (fp, &lp->max_bw.value); + return; +} + +static void +set_linkparams_max_rsv_bw (struct mpls_te_link *lp, float *fp) +{ + lp->max_rsv_bw.header.type = htons (TE_LINK_SUBTLV_MAX_RSV_BW); + lp->max_rsv_bw.header.length = htons (sizeof (lp->max_rsv_bw.value)); + htonf (fp, &lp->max_rsv_bw.value); + return; +} + +static void +set_linkparams_unrsv_bw (struct mpls_te_link *lp, int priority, float *fp) +{ + /* Note that TLV-length field is the size of array. */ + lp->unrsv_bw.header.type = htons (TE_LINK_SUBTLV_UNRSV_BW); + lp->unrsv_bw.header.length = htons (sizeof (lp->unrsv_bw.value)); + htonf (fp, &lp->unrsv_bw.value [priority]); + return; +} + +static void +set_linkparams_rsc_clsclr (struct mpls_te_link *lp, u_int32_t classcolor) +{ + lp->rsc_clsclr.header.type = htons (TE_LINK_SUBTLV_RSC_CLSCLR); + lp->rsc_clsclr.header.length = htons (sizeof (lp->rsc_clsclr.value)); + lp->rsc_clsclr.value = htonl (classcolor); + return; +} + +static void +initialize_linkparams (struct mpls_te_link *lp) +{ + struct interface *ifp = lp->ifp; + struct ospf_interface *oi; + float fval; + int i; + + if ((oi = lookup_oi_by_ifp (ifp, NULL, OI_ANY)) == NULL) + return; + + /* + * Try to set initial values those can be derived from + * zebra-interface information. + */ + set_linkparams_link_type (oi, lp); + + /* + * Linux and *BSD kernel holds bandwidth parameter as an "int" type. + * We may have to reconsider, if "ifp->bandwidth" type changes to float. + */ + fval = (float)((ifp->bandwidth ? ifp->bandwidth + : OSPF_DEFAULT_BANDWIDTH) * 1000 / 8); + + set_linkparams_max_bw (lp, &fval); + set_linkparams_max_rsv_bw (lp, &fval); + + for (i = 0; i < 8; i++) + set_linkparams_unrsv_bw (lp, i, &fval); + + return; +} + +static int +is_mandated_params_set (struct mpls_te_link *lp) +{ + int rc = 0; + + if (ntohs (OspfMplsTE.router_addr.header.type) == 0) + goto out; + + if (ntohs (lp->link_type.header.type) == 0) + goto out; + + if (ntohs (lp->link_id.header.type) == 0) + goto out; + + rc = 1; +out: + return rc; +} + +/*------------------------------------------------------------------------* + * Followings are callback functions against generic Opaque-LSAs handling. + *------------------------------------------------------------------------*/ + +static int +ospf_mpls_te_new_if (struct interface *ifp) +{ + struct mpls_te_link *new; + int rc = -1; + + if (lookup_linkparams_by_ifp (ifp) != NULL) + { + zlog_warn ("ospf_mpls_te_new_if: ifp(%p) already in use?", ifp); + rc = 0; /* Do nothing here. */ + goto out; + } + + if ((new = XMALLOC (MTYPE_OSPF_MPLS_TE_LINKPARAMS, + sizeof (struct mpls_te_link))) == NULL) + { + zlog_warn ("ospf_mpls_te_new_if: XMALLOC: %s", strerror (errno)); + goto out; + } + memset (new, 0, sizeof (struct mpls_te_link)); + + new->area = NULL; + new->flags = 0; + new->instance = get_mpls_te_instance_value (); + new->ifp = ifp; + + initialize_linkparams (new); + + listnode_add (OspfMplsTE.iflist, new); + + /* Schedule Opaque-LSA refresh. *//* XXX */ + + rc = 0; +out: + return rc; +} + +static int +ospf_mpls_te_del_if (struct interface *ifp) +{ + struct mpls_te_link *lp; + int rc = -1; + + if ((lp = lookup_linkparams_by_ifp (ifp)) != NULL) + { + list iflist = OspfMplsTE.iflist; + + /* Dequeue listnode entry from the list. */ + listnode_delete (iflist, lp); + + /* Avoid misjudgement in the next lookup. */ + if (listcount (iflist) == 0) + iflist->head = iflist->tail = NULL; + + XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, lp); + } + + /* Schedule Opaque-LSA refresh. *//* XXX */ + + rc = 0; +/*out:*/ + return rc; +} + +static void +ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_state) +{ + struct te_link_subtlv_link_type old_type; + struct te_link_subtlv_link_id old_id; + struct mpls_te_link *lp; + + if ((lp = lookup_linkparams_by_ifp (oi->ifp)) == NULL) + { + zlog_warn ("ospf_mpls_te_ism_change: Cannot get linkparams from OI(%s)?", IF_NAME (oi)); + goto out; + } + if (oi->area == NULL || oi->area->top == NULL) + { + zlog_warn ("ospf_mpls_te_ism_change: Cannot refer to OSPF from OI(%s)?", +IF_NAME (oi)); + goto out; + } +#ifdef notyet + if ((lp->area != NULL + && ! IPV4_ADDR_SAME (&lp->area->area_id, &oi->area->area_id)) + || (lp->area != NULL && oi->area == NULL)) + { + /* How should we consider this case? */ + zlog_warn ("MPLS-TE: Area for OI(%s) has changed to [%s], flush previous LSAs", IF_NAME (oi), oi->area ? inet_ntoa (oi->area->area_id) : "N/A"); + ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); + } +#endif + /* Keep Area information in conbination with linkparams. */ + lp->area = oi->area; + + switch (oi->state) + { + case ISM_PointToPoint: + case ISM_DROther: + case ISM_Backup: + case ISM_DR: + old_type = lp->link_type; + old_id = lp->link_id; + + set_linkparams_link_type (oi, lp); + set_linkparams_link_id (oi, lp); + + if ((ntohs (old_type.header.type) != ntohs (lp->link_type.header.type) + || old_type.link_type.value != lp->link_type.link_type.value) + || (ntohs (old_id.header.type) != ntohs (lp->link_id.header.type) + || ntohl (old_id.value.s_addr) != ntohl (lp->link_id.value.s_addr))) + { + if (lp->flags & LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + else + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); + } + break; + default: + lp->link_type.header.type = htons (0); + lp->link_id.header.type = htons (0); + + if (lp->flags & LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); + break; + } + +out: + return; +} + +static void +ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_state) +{ + /* So far, nothing to do here. */ + return; +} + +/*------------------------------------------------------------------------* + * Followings are OSPF protocol processing functions for MPLS-TE. + *------------------------------------------------------------------------*/ + +static void +build_tlv_header (struct stream *s, struct te_tlv_header *tlvh) +{ + stream_put (s, tlvh, sizeof (struct te_tlv_header)); + return; +} + +static void +build_router_tlv (struct stream *s) +{ + struct te_tlv_header *tlvh = &OspfMplsTE.router_addr.header; + if (ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_subtlv_link_type (struct stream *s, struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh = &lp->link_type.header; + if (ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_subtlv_link_id (struct stream *s, struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh = &lp->link_id.header; + if (ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_subtlv_lclif_ipaddr (struct stream *s, struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->lclif_ipaddr; + if (tlvh != NULL && ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_subtlv_rmtif_ipaddr (struct stream *s, struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr; + if (tlvh != NULL && ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_subtlv_te_metric (struct stream *s, struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh = &lp->te_metric.header; + if (ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_subtlv_max_bw (struct stream *s, struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh = &lp->max_bw.header; + if (ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_subtlv_max_rsv_bw (struct stream *s, struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh = &lp->max_rsv_bw.header; + if (ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_subtlv_unrsv_bw (struct stream *s, struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh = &lp->unrsv_bw.header; + if (ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_subtlv_rsc_clsclr (struct stream *s, struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh = &lp->rsc_clsclr.header; + if (ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_tlv (struct stream *s, struct mpls_te_link *lp) +{ + set_linkparams_link_header (lp); + build_tlv_header (s, &lp->link_header.header); + + build_link_subtlv_link_type (s, lp); + build_link_subtlv_link_id (s, lp); + build_link_subtlv_lclif_ipaddr (s, lp); + build_link_subtlv_rmtif_ipaddr (s, lp); + build_link_subtlv_te_metric (s, lp); + build_link_subtlv_max_bw (s, lp); + build_link_subtlv_max_rsv_bw (s, lp); + build_link_subtlv_unrsv_bw (s, lp); + build_link_subtlv_rsc_clsclr (s, lp); + return; +} + +static void +ospf_mpls_te_lsa_body_set (struct stream *s, struct mpls_te_link *lp) +{ + /* + * The router address TLV is type 1, and ... + * It must appear in exactly one + * Traffic Engineering LSA originated by a router. + */ + build_router_tlv (s); + + /* + * Only one Link TLV shall be carried in each LSA, allowing for fine + * granularity changes in topology. + */ + build_link_tlv (s, lp); + return; +} + +/* Create new opaque-LSA. */ +static struct ospf_lsa * +ospf_mpls_te_lsa_new (struct ospf_area *area, struct mpls_te_link *lp) +{ + struct stream *s; + struct lsa_header *lsah; + struct ospf_lsa *new = NULL; + u_char options, lsa_type; + struct in_addr lsa_id; + u_int32_t tmp; + u_int16_t length; + + /* Create a stream for LSA. */ + if ((s = stream_new (OSPF_MAX_LSA_SIZE)) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_new: stream_new() ?"); + goto out; + } + lsah = (struct lsa_header *) STREAM_DATA (s); + + options = LSA_OPTIONS_GET (area); +#ifdef HAVE_NSSA + options |= LSA_NSSA_GET (area); +#endif /* HAVE_NSSA */ + options |= OSPF_OPTION_O; /* Don't forget this :-) */ + + lsa_type = OSPF_OPAQUE_AREA_LSA; + tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); + lsa_id.s_addr = htonl (tmp); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type%d:%s]: Create an Opaque-LSA/MPLS-TE instance", lsa_type, inet_ntoa (lsa_id)); + + /* Set opaque-LSA header fields. */ + lsa_header_set (s, options, lsa_type, lsa_id); + + /* Set opaque-LSA body fields. */ + ospf_mpls_te_lsa_body_set (s, lp); + + /* Set length. */ + length = stream_get_endp (s); + lsah->length = htons (length); + + /* Now, create an OSPF LSA instance. */ + if ((new = ospf_lsa_new ()) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_new: ospf_lsa_new() ?"); + stream_free (s); + goto out; + } + if ((new->data = ospf_lsa_data_new (length)) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_new: ospf_lsa_data_new() ?"); + ospf_lsa_free (new); + new = NULL; + stream_free (s); + goto out; + } + + new->area = area; + SET_FLAG (new->flags, OSPF_LSA_SELF); + memcpy (new->data, lsah, length); + stream_free (s); + +out: + return new; +} + +static int +ospf_mpls_te_lsa_originate1 (struct ospf_area *area, struct mpls_te_link *lp) +{ + struct ospf_lsa *new; + int rc = -1; + + /* Create new Opaque-LSA/MPLS-TE instance. */ + if ((new = ospf_mpls_te_lsa_new (area, lp)) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_originate1: ospf_mpls_te_lsa_new() ?"); + goto out; + } + + /* Install this LSA into LSDB. */ + if (ospf_lsa_install (NULL/*oi*/, new) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_originate1: ospf_lsa_install() ?"); + ospf_lsa_free (new); + goto out; + } + + /* Now this linkparameter entry has associated LSA. */ + lp->flags |= LPFLG_LSA_ENGAGED; + + /* Update new LSA origination count. */ + area->top->lsa_originate_count++; + + /* Flood new LSA through area. */ + ospf_flood_through_area (area, NULL/*nbr*/, new); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + char area_id[INET_ADDRSTRLEN]; + strcpy (area_id, inet_ntoa (area->area_id)); + zlog_info ("LSA[Type%d:%s]: Originate Opaque-LSA/MPLS-TE: Area(%s), Link(%s)", new->data->type, inet_ntoa (new->data->id), area_id, lp->ifp->name); + ospf_lsa_header_dump (new->data); + } + + rc = 0; +out: + return rc; +} + +static int +ospf_mpls_te_lsa_originate (void *arg) +{ + struct ospf_area *area = (struct ospf_area *) arg; + listnode node; + struct mpls_te_link *lp; + int rc = -1; + + if (OspfMplsTE.status == disabled) + { + zlog_info ("ospf_mpls_te_lsa_originate: MPLS-TE is disabled now."); + rc = 0; /* This is not an error case. */ + goto out; + } + + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + { + if ((lp = getdata (node)) == NULL) + continue; + if (lp->area == NULL) + continue; + if (! IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id)) + continue; + + if (lp->flags & LPFLG_LSA_ENGAGED) + { + if (lp->flags & LPFLG_LSA_FORCED_REFRESH) + { + lp->flags &= ~LPFLG_LSA_FORCED_REFRESH; + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + } + continue; + } + if (! is_mandated_params_set (lp)) + { + zlog_warn ("ospf_mpls_te_lsa_originate: Link(%s) lacks some mandated MPLS-TE parameters.", lp->ifp ? lp->ifp->name : "?"); + continue; + } + + /* Ok, let's try to originate an LSA for this area and Link. */ + if (ospf_mpls_te_lsa_originate1 (area, lp) != 0) + goto out; + } + + rc = 0; +out: + return rc; +} + +static void +ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa) +{ + struct mpls_te_link *lp; + struct ospf_area *area = lsa->area; + struct ospf_lsa *new = NULL; + + if (OspfMplsTE.status == disabled) + { + /* + * This LSA must have flushed before due to MPLS-TE status change. + * It seems a slip among routers in the routing domain. + */ + zlog_info ("ospf_mpls_te_lsa_refresh: MPLS-TE is disabled now."); + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ + } + + /* At first, resolve lsa/lp relationship. */ + if ((lp = lookup_linkparams_by_instance (lsa)) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_refresh: Invalid parameter?"); + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ + } + + /* If the lsa's age reached to MaxAge, start flushing procedure. */ + if (IS_LSA_MAXAGE (lsa)) + { + lp->flags &= ~LPFLG_LSA_ENGAGED; + ospf_opaque_lsa_flush_schedule (lsa); + goto out; + } + + /* Create new Opaque-LSA/MPLS-TE instance. */ + if ((new = ospf_mpls_te_lsa_new (area, lp)) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_mpls_te_lsa_new() ?"); + goto out; + } + new->data->ls_seqnum = lsa_seqnum_increment (lsa); + + /* Install this LSA into LSDB. */ + /* Given "lsa" will be freed in the next function. */ + if (ospf_lsa_install (NULL/*oi*/, new) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_lsa_install() ?"); + ospf_lsa_free (new); + goto out; + } + + /* Flood updated LSA through area. */ + ospf_flood_through_area (area, NULL/*nbr*/, new); + + /* Debug logging. */ + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: Refresh Opaque-LSA/MPLS-TE", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_header_dump (new->data); + } + +out: + return; +} + +static void +ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, + enum sched_opcode opcode) +{ + struct ospf_lsa lsa; + struct lsa_header lsah; + u_int32_t tmp; + + memset (&lsa, 0, sizeof (lsa)); + memset (&lsah, 0, sizeof (lsah)); + + lsa.area = lp->area; + lsa.data = &lsah; + lsah.type = OSPF_OPAQUE_AREA_LSA; + tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); + lsah.id.s_addr = htonl (tmp); + + switch (opcode) + { + case REORIGINATE_PER_AREA: + ospf_opaque_lsa_reoriginate_schedule ((void *) lp->area, + OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); + break; + case REFRESH_THIS_LSA: + ospf_opaque_lsa_refresh_schedule (&lsa); + break; + case FLUSH_THIS_LSA: + lp->flags &= ~LPFLG_LSA_ENGAGED; + ospf_opaque_lsa_flush_schedule (&lsa); + break; + default: + zlog_warn ("ospf_mpls_te_lsa_schedule: Unknown opcode (%u)", opcode); + break; + } + + return; +} + +/*------------------------------------------------------------------------* + * Followings are vty session control functions. + *------------------------------------------------------------------------*/ + +static u_int16_t +show_vty_router_addr (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_tlv_router_addr *top = (struct te_tlv_router_addr *) tlvh; + + if (vty != NULL) + vty_out (vty, " Router-Address: %s%s", inet_ntoa (top->value), VTY_NEWLINE); + else + zlog_info (" Router-Address: %s", inet_ntoa (top->value)); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_header (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_tlv_link *top = (struct te_tlv_link *) tlvh; + + if (vty != NULL) + vty_out (vty, " Link: %u octets of data%s", ntohs (top->header.length), VTY_NEWLINE); + else + zlog_info (" Link: %u octets of data", ntohs (top->header.length)); + + return TLV_HDR_SIZE; /* Here is special, not "TLV_SIZE". */ +} + +static u_int16_t +show_vty_link_subtlv_link_type (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_link_type *top; + const char *cp = "Unknown"; + + top = (struct te_link_subtlv_link_type *) tlvh; + switch (top->link_type.value) + { + case LINK_TYPE_SUBTLV_VALUE_PTP: + cp = "Point-to-point"; + break; + case LINK_TYPE_SUBTLV_VALUE_MA: + cp = "Multiaccess"; + break; + default: + break; + } + + if (vty != NULL) + vty_out (vty, " Link-Type: %s (%u)%s", cp, top->link_type.value, VTY_NEWLINE); + else + zlog_info (" Link-Type: %s (%u)", cp, top->link_type.value); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_link_id (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_link_id *top; + + top = (struct te_link_subtlv_link_id *) tlvh; + if (vty != NULL) + vty_out (vty, " Link-ID: %s%s", inet_ntoa (top->value), VTY_NEWLINE); + else + zlog_info (" Link-ID: %s", inet_ntoa (top->value)); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_lclif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_lclif_ipaddr *top; + int i, n; + + top = (struct te_link_subtlv_lclif_ipaddr *) tlvh; + n = ntohs (tlvh->length) / sizeof (top->value[0]); + + if (vty != NULL) + vty_out (vty, " Local Interface IP Address(es): %d%s", n, VTY_NEWLINE); + else + zlog_info (" Local Interface IP Address(es): %d", n); + + for (i = 0; i < n; i++) + { + if (vty != NULL) + vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE); + else + zlog_info (" #%d: %s", i, inet_ntoa (top->value[i])); + } + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_rmtif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_rmtif_ipaddr *top; + int i, n; + + top = (struct te_link_subtlv_rmtif_ipaddr *) tlvh; + n = ntohs (tlvh->length) / sizeof (top->value[0]); + if (vty != NULL) + vty_out (vty, " Remote Interface IP Address(es): %d%s", n, VTY_NEWLINE); + else + zlog_info (" Remote Interface IP Address(es): %d", n); + + for (i = 0; i < n; i++) + { + if (vty != NULL) + vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE); + else + zlog_info (" #%d: %s", i, inet_ntoa (top->value[i])); + } + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_te_metric (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_te_metric *top; + + top = (struct te_link_subtlv_te_metric *) tlvh; + if (vty != NULL) + vty_out (vty, " Traffic Engineering Metric: %u%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE); + else + zlog_info (" Traffic Engineering Metric: %u", (u_int32_t) ntohl (top->value)); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_max_bw (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_max_bw *top; + float fval; + + top = (struct te_link_subtlv_max_bw *) tlvh; + ntohf (&top->value, &fval); + + if (vty != NULL) + vty_out (vty, " Maximum Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); + else + zlog_info (" Maximum Bandwidth: %g (Bytes/sec)", fval); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_max_rsv_bw (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_max_rsv_bw *top; + float fval; + + top = (struct te_link_subtlv_max_rsv_bw *) tlvh; + ntohf (&top->value, &fval); + + if (vty != NULL) + vty_out (vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); + else + zlog_info (" Maximum Reservable Bandwidth: %g (Bytes/sec)", fval); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_unrsv_bw (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_unrsv_bw *top; + float fval; + int i; + + top = (struct te_link_subtlv_unrsv_bw *) tlvh; + for (i = 0; i < 8; i++) + { + ntohf (&top->value[i], &fval); + if (vty != NULL) + vty_out (vty, " Unreserved Bandwidth (pri %d): %g (Bytes/sec)%s", i, fval, VTY_NEWLINE); + else + zlog_info (" Unreserved Bandwidth (pri %d): %g (Bytes/sec)", i, fval); + } + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_rsc_clsclr (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_rsc_clsclr *top; + + top = (struct te_link_subtlv_rsc_clsclr *) tlvh; + if (vty != NULL) + vty_out (vty, " Resource class/color: 0x%x%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE); + else + zlog_info (" Resource Class/Color: 0x%x", (u_int32_t) ntohl (top->value)); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_unknown_tlv (struct vty *vty, struct te_tlv_header *tlvh) +{ + if (vty != NULL) + vty_out (vty, " Unknown TLV: [type(0x%x), length(0x%x)]%s", ntohs (tlvh->type), ntohs (tlvh->length), VTY_NEWLINE); + else + zlog_info (" Unknown TLV: [type(0x%x), length(0x%x)]", ntohs (tlvh->type), ntohs (tlvh->length)); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +ospf_mpls_te_show_link_subtlv (struct vty *vty, struct te_tlv_header *tlvh0, + u_int16_t subtotal, u_int16_t total) +{ + struct te_tlv_header *tlvh, *next; + u_int16_t sum = subtotal; + + for (tlvh = tlvh0; sum < total; tlvh = (next ? next : TLV_HDR_NEXT (tlvh))) + { + next = NULL; + switch (ntohs (tlvh->type)) + { + case TE_LINK_SUBTLV_LINK_TYPE: + sum += show_vty_link_subtlv_link_type (vty, tlvh); + break; + case TE_LINK_SUBTLV_LINK_ID: + sum += show_vty_link_subtlv_link_id (vty, tlvh); + break; + case TE_LINK_SUBTLV_LCLIF_IPADDR: + sum += show_vty_link_subtlv_lclif_ipaddr (vty, tlvh); + break; + case TE_LINK_SUBTLV_RMTIF_IPADDR: + sum += show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh); + break; + case TE_LINK_SUBTLV_TE_METRIC: + sum += show_vty_link_subtlv_te_metric (vty, tlvh); + break; + case TE_LINK_SUBTLV_MAX_BW: + sum += show_vty_link_subtlv_max_bw (vty, tlvh); + break; + case TE_LINK_SUBTLV_MAX_RSV_BW: + sum += show_vty_link_subtlv_max_rsv_bw (vty, tlvh); + break; + case TE_LINK_SUBTLV_UNRSV_BW: + sum += show_vty_link_subtlv_unrsv_bw (vty, tlvh); + break; + case TE_LINK_SUBTLV_RSC_CLSCLR: + sum += show_vty_link_subtlv_rsc_clsclr (vty, tlvh); + break; + default: + sum += show_vty_unknown_tlv (vty, tlvh); + break; + } + } + return sum; +} + +static void +ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa) +{ + struct lsa_header *lsah = (struct lsa_header *) lsa->data; + struct te_tlv_header *tlvh, *next; + u_int16_t sum, total; + u_int16_t (* subfunc)(struct vty *vty, struct te_tlv_header *tlvh, + u_int16_t subtotal, u_int16_t total) = NULL; + + sum = 0; + total = ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE; + + for (tlvh = TLV_HDR_TOP (lsah); sum < total; + tlvh = (next ? next : TLV_HDR_NEXT (tlvh))) + { + if (subfunc != NULL) + { + sum = (* subfunc)(vty, tlvh, sum, total); + next = (struct te_tlv_header *)((char *) tlvh + sum); + subfunc = NULL; + continue; + } + + next = NULL; + switch (ntohs (tlvh->type)) + { + case TE_TLV_ROUTER_ADDR: + sum += show_vty_router_addr (vty, tlvh); + break; + case TE_TLV_LINK: + sum += show_vty_link_header (vty, tlvh); + subfunc = ospf_mpls_te_show_link_subtlv; + next = tlvh + 1; + break; + default: + sum += show_vty_unknown_tlv (vty, tlvh); + break; + } + } + return; +} + +static void +ospf_mpls_te_config_write_router (struct vty *vty) +{ + if (OspfMplsTE.status == enabled) + { + vty_out (vty, " mpls-te%s", VTY_NEWLINE); + vty_out (vty, " mpls-te router-address %s%s", + inet_ntoa (OspfMplsTE.router_addr.value), VTY_NEWLINE); + } + return; +} + +static void +ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp) +{ + struct mpls_te_link *lp; + + if ((OspfMplsTE.status == enabled) + && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0) + && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)) + { + float fval; + int i; + + vty_out (vty, " mpls-te link metric %u%s", + (u_int32_t) ntohl (lp->te_metric.value), VTY_NEWLINE); + + ntohf (&lp->max_bw.value, &fval); + if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) + vty_out (vty, " mpls-te link max-bw %g%s", fval, VTY_NEWLINE); + + ntohf (&lp->max_rsv_bw.value, &fval); + if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) + vty_out (vty, " mpls-te link max-rsv-bw %g%s", fval, VTY_NEWLINE); + + for (i = 0; i < 8; i++) + { + ntohf (&lp->unrsv_bw.value[i], &fval); + if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) + vty_out (vty, " mpls-te link unrsv-bw %d %g%s", + i, fval, VTY_NEWLINE); + } + + vty_out (vty, " mpls-te link rsc-clsclr 0x%x%s", + (u_int32_t) ntohl (lp->rsc_clsclr.value), VTY_NEWLINE); + } + return; +} + +/*------------------------------------------------------------------------* + * Followings are vty command functions. + *------------------------------------------------------------------------*/ + +DEFUN (mpls_te, + mpls_te_cmd, + "mpls-te", + "Configure MPLS-TE parameters\n" + "Enable the MPLS-TE functionality\n") +{ + listnode node; + struct mpls_te_link *lp; + + if (OspfMplsTE.status == enabled) + return CMD_SUCCESS; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("MPLS-TE: OFF -> ON"); + + OspfMplsTE.status = enabled; + + /* + * Following code is intended to handle two cases; + * + * 1) MPLS-TE was disabled at startup time, but now become enabled. + * 2) MPLS-TE was once enabled then disabled, and now enabled again. + */ + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + if ((lp = getdata (node)) != NULL) + initialize_linkparams (lp); + + ospf_mpls_te_foreach_area (ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA); + + return CMD_SUCCESS; +} + +ALIAS (mpls_te, + mpls_te_on_cmd, + "mpls-te on", + "Configure MPLS-TE parameters\n" + "Enable the MPLS-TE functionality\n") + +DEFUN (no_mpls_te, + no_mpls_te_cmd, + "no mpls-te", + NO_STR + "Configure MPLS-TE parameters\n" + "Disable the MPLS-TE functionality\n") +{ + listnode node; + struct mpls_te_link *lp; + + if (OspfMplsTE.status == disabled) + return CMD_SUCCESS; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("MPLS-TE: ON -> OFF"); + + OspfMplsTE.status = disabled; + + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + if ((lp = getdata (node)) != NULL) + if (lp->area != NULL) + if (lp->flags & LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); + + return CMD_SUCCESS; +} + +DEFUN (mpls_te_router_addr, + mpls_te_router_addr_cmd, + "mpls-te router-address A.B.C.D", + "MPLS-TE specific commands\n" + "Stable IP address of the advertising router\n" + "MPLS-TE router address in IPv4 address format\n") +{ + struct te_tlv_router_addr *ra = &OspfMplsTE.router_addr; + struct in_addr value; + + if (! inet_aton (argv[0], &value)) + { + vty_out (vty, "Please specify Router-Addr by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (ntohs (ra->header.type) == 0 + || ntohl (ra->value.s_addr) != ntohl (value.s_addr)) + { + listnode node; + struct mpls_te_link *lp; + int need_to_reoriginate = 0; + + set_mpls_te_router_addr (value); + + if (OspfMplsTE.status == disabled) + goto out; + + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + { + if ((lp = getdata (node)) == NULL) + continue; + if (lp->area == NULL) + continue; + + if ((lp->flags & LPFLG_LSA_ENGAGED) == 0) + { + need_to_reoriginate = 1; + break; + } + } + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + { + if ((lp = getdata (node)) == NULL) + continue; + if (lp->area == NULL) + continue; + + if (need_to_reoriginate) + lp->flags |= LPFLG_LSA_FORCED_REFRESH; + else + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + } + + if (need_to_reoriginate) + ospf_mpls_te_foreach_area ( + ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA); + } +out: + return CMD_SUCCESS; +} + +DEFUN (mpls_te_link_metric, + mpls_te_link_metric_cmd, + "mpls-te link metric <0-4294967295>", + "MPLS-TE specific commands\n" + "Configure MPLS-TE link parameters\n" + "Link metric for MPLS-TE purpose\n" + "Metric\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct mpls_te_link *lp; + u_int32_t value; + + if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) + { + vty_out (vty, "mpls_te_link_metric: Something wrong!%s", VTY_NEWLINE); + return CMD_WARNING; + } + + value = strtoul (argv[0], NULL, 10); + + if (ntohs (lp->te_metric.header.type) == 0 + || ntohl (lp->te_metric.value) != value) + { + set_linkparams_te_metric (lp, value); + + if (OspfMplsTE.status == enabled) + if (lp->area != NULL) + { + if (lp->flags & LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + else + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); + } + } + return CMD_SUCCESS; +} + +DEFUN (mpls_te_link_maxbw, + mpls_te_link_maxbw_cmd, + "mpls-te link max-bw BANDWIDTH", + "MPLS-TE specific commands\n" + "Configure MPLS-TE link parameters\n" + "Maximum bandwidth that can be used\n" + "Bytes/second (IEEE floating point format)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct mpls_te_link *lp; + float f1, f2; + + if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) + { + vty_out (vty, "mpls_te_link_maxbw: Something wrong!%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ntohf (&lp->max_bw.value, &f1); + if (sscanf (argv[0], "%g", &f2) != 1) + { + vty_out (vty, "mpls_te_link_maxbw: fscanf: %s%s", strerror (errno), VTY_NEWLINE); + return CMD_WARNING; + } + + if (ntohs (lp->max_bw.header.type) == 0 + || f1 != f2) + { + set_linkparams_max_bw (lp, &f2); + + if (OspfMplsTE.status == enabled) + if (lp->area != NULL) + { + if (lp->flags & LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + else + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); + } + } + return CMD_SUCCESS; +} + +DEFUN (mpls_te_link_max_rsv_bw, + mpls_te_link_max_rsv_bw_cmd, + "mpls-te link max-rsv-bw BANDWIDTH", + "MPLS-TE specific commands\n" + "Configure MPLS-TE link parameters\n" + "Maximum bandwidth that may be reserved\n" + "Bytes/second (IEEE floating point format)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct mpls_te_link *lp; + float f1, f2; + + if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) + { + vty_out (vty, "mpls_te_link_max_rsv_bw: Something wrong!%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ntohf (&lp->max_rsv_bw.value, &f1); + if (sscanf (argv[0], "%g", &f2) != 1) + { + vty_out (vty, "mpls_te_link_max_rsv_bw: fscanf: %s%s", strerror (errno), VTY_NEWLINE); + return CMD_WARNING; + } + + if (ntohs (lp->max_rsv_bw.header.type) == 0 + || f1 != f2) + { + set_linkparams_max_rsv_bw (lp, &f2); + + if (OspfMplsTE.status == enabled) + if (lp->area != NULL) + { + if (lp->flags & LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + else + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); + } + } + return CMD_SUCCESS; +} + +DEFUN (mpls_te_link_unrsv_bw, + mpls_te_link_unrsv_bw_cmd, + "mpls-te link unrsv-bw <0-7> BANDWIDTH", + "MPLS-TE specific commands\n" + "Configure MPLS-TE link parameters\n" + "Unreserved bandwidth at each priority level\n" + "Priority\n" + "Bytes/second (IEEE floating point format)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct mpls_te_link *lp; + int priority; + float f1, f2; + + if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) + { + vty_out (vty, "mpls_te_link_unrsv_bw: Something wrong!%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* We don't have to consider about range check here. */ + if (sscanf (argv[0], "%d", &priority) != 1) + { + vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", strerror (errno), VTY_NEWLINE); + return CMD_WARNING; + } + + ntohf (&lp->unrsv_bw.value [priority], &f1); + if (sscanf (argv[1], "%g", &f2) != 1) + { + vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", strerror (errno), VTY_NEWLINE); + return CMD_WARNING; + } + + if (ntohs (lp->unrsv_bw.header.type) == 0 + || f1 != f2) + { + set_linkparams_unrsv_bw (lp, priority, &f2); + + if (OspfMplsTE.status == enabled) + if (lp->area != NULL) + { + if (lp->flags & LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + else + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); + } + } + return CMD_SUCCESS; +} + +DEFUN (mpls_te_link_rsc_clsclr, + mpls_te_link_rsc_clsclr_cmd, + "mpls-te link rsc-clsclr BITPATTERN", + "MPLS-TE specific commands\n" + "Configure MPLS-TE link parameters\n" + "Administrative group membership\n" + "32-bit Hexadecimal value (ex. 0xa1)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct mpls_te_link *lp; + unsigned long value; + + if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) + { + vty_out (vty, "mpls_te_link_rsc_clsclr: Something wrong!%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (sscanf (argv[0], "0x%lx", &value) != 1) + { + vty_out (vty, "mpls_te_link_rsc_clsclr: fscanf: %s%s", strerror (errno), VTY_NEWLINE); + return CMD_WARNING; + } + + if (ntohs (lp->rsc_clsclr.header.type) == 0 + || ntohl (lp->rsc_clsclr.value) != value) + { + set_linkparams_rsc_clsclr (lp, value); + + if (OspfMplsTE.status == enabled) + if (lp->area != NULL) + { + if (lp->flags & LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + else + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); + } + } + return CMD_SUCCESS; +} + +DEFUN (show_mpls_te_router, + show_mpls_te_router_cmd, + "show mpls-te router", + SHOW_STR + "MPLS-TE information\n" + "Router information\n") +{ + if (OspfMplsTE.status == enabled) + { + vty_out (vty, "--- MPLS-TE router parameters ---%s", + VTY_NEWLINE); + + if (ntohs (OspfMplsTE.router_addr.header.type) != 0) + show_vty_router_addr (vty, &OspfMplsTE.router_addr.header); + else if (vty != NULL) + vty_out (vty, " N/A%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +static void +show_mpls_te_link_sub (struct vty *vty, struct interface *ifp) +{ + struct mpls_te_link *lp; + struct te_tlv_header *tlvh; + + if ((OspfMplsTE.status == enabled) + && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0) + && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)) + { + vty_out (vty, "-- MPLS-TE link parameters for %s --%s", + ifp->name, VTY_NEWLINE); + + show_vty_link_subtlv_link_type (vty, &lp->link_type.header); + show_vty_link_subtlv_link_id (vty, &lp->link_id.header); + + if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL) + show_vty_link_subtlv_lclif_ipaddr (vty, tlvh); + if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL) + show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh); + + show_vty_link_subtlv_te_metric (vty, &lp->te_metric.header); + + show_vty_link_subtlv_max_bw (vty, &lp->max_bw.header); + show_vty_link_subtlv_max_rsv_bw (vty, &lp->max_rsv_bw.header); + show_vty_link_subtlv_unrsv_bw (vty, &lp->unrsv_bw.header); + show_vty_link_subtlv_rsc_clsclr (vty, &lp->rsc_clsclr.header); + } + else + { + vty_out (vty, " %s: MPLS-TE is disabled on this interface%s", + ifp->name, VTY_NEWLINE); + } + + return; +} + +DEFUN (show_mpls_te_link, + show_mpls_te_link_cmd, + "show mpls-te interface [INTERFACE]", + SHOW_STR + "MPLS-TE information\n" + "Interface information\n" + "Interface name\n") +{ + struct interface *ifp; + listnode node; + + /* Show All Interfaces. */ + if (argc == 0) + for (node = listhead (iflist); node; nextnode (node)) + show_mpls_te_link_sub (vty, node->data); + /* Interface name is specified. */ + else + { + if ((ifp = if_lookup_by_name (argv[0])) == NULL) + vty_out (vty, "No such interface name%s", VTY_NEWLINE); + else + show_mpls_te_link_sub (vty, ifp); + } + + return CMD_SUCCESS; +} + +static void +ospf_mpls_te_register_vty (void) +{ + install_element (VIEW_NODE, &show_mpls_te_router_cmd); + install_element (VIEW_NODE, &show_mpls_te_link_cmd); + install_element (ENABLE_NODE, &show_mpls_te_router_cmd); + install_element (ENABLE_NODE, &show_mpls_te_link_cmd); + + install_element (OSPF_NODE, &mpls_te_cmd); + install_element (OSPF_NODE, &no_mpls_te_cmd); + install_element (OSPF_NODE, &mpls_te_on_cmd); + install_element (OSPF_NODE, &mpls_te_router_addr_cmd); + + install_element (INTERFACE_NODE, &mpls_te_link_metric_cmd); + install_element (INTERFACE_NODE, &mpls_te_link_maxbw_cmd); + install_element (INTERFACE_NODE, &mpls_te_link_max_rsv_bw_cmd); + install_element (INTERFACE_NODE, &mpls_te_link_unrsv_bw_cmd); + install_element (INTERFACE_NODE, &mpls_te_link_rsc_clsclr_cmd); + + return; +} + +#endif /* HAVE_OSPF_TE */ diff --git a/ospfd/ospf_te.h b/ospfd/ospf_te.h new file mode 100644 index 00000000..8a7a98c7 --- /dev/null +++ b/ospfd/ospf_te.h @@ -0,0 +1,193 @@ +/* + * This is an implementation of draft-katz-yeung-ospf-traffic-06.txt + * Copyright (C) 2001 KDD R&D Laboratories, Inc. + * http://www.kddlabs.co.jp/ + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_MPLS_TE_H +#define _ZEBRA_OSPF_MPLS_TE_H + +/* + * Opaque LSA's link state ID for Traffic Engineering is + * structured as follows. + * + * 24 16 8 0 + * +--------+--------+--------+--------+ + * | 1 | MBZ |........|........| + * +--------+--------+--------+--------+ + * |<-Type->||<-- Instance --->| + * + * + * Type: IANA has assigned '1' for Traffic Engineering. + * MBZ: Reserved, must be set to zero. + * Instance: User may select an arbitrary 16-bit value. + * + */ + +#define LEGAL_TE_INSTANCE_RANGE(i) (0 <= (i) && (i) <= 0xffff) + +/* + * 24 16 8 0 + * +--------+--------+--------+--------+ --- + * | LS age |Options | 10 | A + * +--------+--------+--------+--------+ | + * | 1 | 0 | Instance | | + * +--------+--------+--------+--------+ | + * | Advertising router | | Standard (Opaque) LSA header; + * +--------+--------+--------+--------+ | Only type-10 is used. + * | LS sequence number | | + * +--------+--------+--------+--------+ | + * | LS checksum | Length | V + * +--------+--------+--------+--------+ --- + * | Type | Length | A + * +--------+--------+--------+--------+ | TLV part for TE; Values might be + * | Values ... | V structured as a set of sub-TLVs. + * +--------+--------+--------+--------+ --- + */ + +/* + * Following section defines TLV (tag, length, value) structures, + * used for Traffic Engineering. + */ +struct te_tlv_header +{ + u_int16_t type; /* TE_TLV_XXX (see below) */ + u_int16_t length; /* Value portion only, in octets */ +}; + +#define TLV_HDR_SIZE \ + sizeof (struct te_tlv_header) + +#define TLV_BODY_SIZE(tlvh) \ + ROUNDUP (ntohs ((tlvh)->length), sizeof (u_int32_t)) + +#define TLV_SIZE(tlvh) \ + (TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh)) + +#define TLV_HDR_TOP(lsah) \ + (struct te_tlv_header *)((char *)(lsah) + OSPF_LSA_HEADER_SIZE) + +#define TLV_HDR_NEXT(tlvh) \ + (struct te_tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh)) + +/* + * Following section defines TLV body parts. + */ +/* Router Address TLV *//* Mandatory */ +#define TE_TLV_ROUTER_ADDR 1 +struct te_tlv_router_addr +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + struct in_addr value; +}; + +/* Link TLV */ +#define TE_TLV_LINK 2 +struct te_tlv_link +{ + struct te_tlv_header header; + /* A set of link-sub-TLVs will follow. */ +}; + +/* Link Type Sub-TLV *//* Mandatory */ +#define TE_LINK_SUBTLV_LINK_TYPE 1 +struct te_link_subtlv_link_type +{ + struct te_tlv_header header; /* Value length is 1 octet. */ + struct { +#define LINK_TYPE_SUBTLV_VALUE_PTP 1 +#define LINK_TYPE_SUBTLV_VALUE_MA 2 + u_char value; + u_char padding[3]; + } link_type; +}; + +/* Link Sub-TLV: Link ID *//* Mandatory */ +#define TE_LINK_SUBTLV_LINK_ID 2 +struct te_link_subtlv_link_id +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + struct in_addr value; /* Same as router-lsa's link-id. */ +}; + +/* Link Sub-TLV: Local Interface IP Address *//* Optional */ +#define TE_LINK_SUBTLV_LCLIF_IPADDR 3 +struct te_link_subtlv_lclif_ipaddr +{ + struct te_tlv_header header; /* Value length is 4 x N octets. */ + struct in_addr value[1]; /* Local IP address(es). */ +}; + +/* Link Sub-TLV: Remote Interface IP Address *//* Optional */ +#define TE_LINK_SUBTLV_RMTIF_IPADDR 4 +struct te_link_subtlv_rmtif_ipaddr +{ + struct te_tlv_header header; /* Value length is 4 x N octets. */ + struct in_addr value[1]; /* Neighbor's IP address(es). */ +}; + +/* Link Sub-TLV: Traffic Engineering Metric *//* Optional */ +#define TE_LINK_SUBTLV_TE_METRIC 5 +struct te_link_subtlv_te_metric +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + u_int32_t value; /* Link metric for TE purpose. */ +}; + +/* Link Sub-TLV: Maximum Bandwidth *//* Optional */ +#define TE_LINK_SUBTLV_MAX_BW 6 +struct te_link_subtlv_max_bw +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + float value; /* bytes/sec */ +}; + +/* Link Sub-TLV: Maximum Reservable Bandwidth *//* Optional */ +#define TE_LINK_SUBTLV_MAX_RSV_BW 7 +struct te_link_subtlv_max_rsv_bw +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + float value; /* bytes/sec */ +}; + +/* Link Sub-TLV: Unreserved Bandwidth *//* Optional */ +#define TE_LINK_SUBTLV_UNRSV_BW 8 +struct te_link_subtlv_unrsv_bw +{ + struct te_tlv_header header; /* Value length is 32 octets. */ + float value[8]; /* One for each priority level. */ +}; + +/* Link Sub-TLV: Resource Class/Color *//* Optional */ +#define TE_LINK_SUBTLV_RSC_CLSCLR 9 +struct te_link_subtlv_rsc_clsclr +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + u_int32_t value; /* Admin. group membership. */ +}; + +/* Here are "non-official" architechtual constants. */ +#define MPLS_TE_MINIMUM_BANDWIDTH 1.0 /* Reasonable? *//* XXX */ + +/* Prototypes. */ +extern int ospf_mpls_te_init (void); +extern void ospf_mpls_te_term (void); + +#endif /* _ZEBRA_OSPF_MPLS_TE_H */ diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c new file mode 100644 index 00000000..73215fa5 --- /dev/null +++ b/ospfd/ospf_vty.c @@ -0,0 +1,7571 @@ +/* OSPF VTY interface. + * Copyright (C) 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "memory.h" +#include "thread.h" +#include "prefix.h" +#include "table.h" +#include "vty.h" +#include "command.h" +#include "plist.h" +#include "log.h" +#include "zclient.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_zebra.h" +/*#include "ospfd/ospf_routemap.h" */ +#include "ospfd/ospf_vty.h" +#include "ospfd/ospf_dump.h" + + +static char *ospf_network_type_str[] = +{ + "Null", + "POINTOPOINT", + "BROADCAST", + "NBMA", + "POINTOMULTIPOINT", + "VIRTUALLINK", + "LOOPBACK" +}; + + +/* Utility functions. */ +int +ospf_str2area_id (char *str, struct in_addr *area_id, int *format) +{ + char *endptr = NULL; + unsigned long ret; + + /* match "A.B.C.D". */ + if (strchr (str, '.') != NULL) + { + ret = inet_aton (str, area_id); + if (!ret) + return -1; + *format = OSPF_AREA_ID_FORMAT_ADDRESS; + } + /* match "<0-4294967295>". */ + else + { + ret = strtoul (str, &endptr, 10); + if (*endptr != '\0' || (ret == ULONG_MAX && errno == ERANGE)) + return -1; + + area_id->s_addr = htonl (ret); + *format = OSPF_AREA_ID_FORMAT_DECIMAL; + } + + return 0; +} + + +int +str2distribute_source (char *str, int *source) +{ + /* Sanity check. */ + if (str == NULL) + return 0; + + if (strncmp (str, "k", 1) == 0) + *source = ZEBRA_ROUTE_KERNEL; + else if (strncmp (str, "c", 1) == 0) + *source = ZEBRA_ROUTE_CONNECT; + else if (strncmp (str, "s", 1) == 0) + *source = ZEBRA_ROUTE_STATIC; + else if (strncmp (str, "r", 1) == 0) + *source = ZEBRA_ROUTE_RIP; + else if (strncmp (str, "b", 1) == 0) + *source = ZEBRA_ROUTE_BGP; + else + return 0; + + return 1; +} + +int +str2metric (char *str, int *metric) +{ + /* Sanity check. */ + if (str == NULL) + return 0; + + *metric = strtol (str, NULL, 10); + if (*metric < 0 && *metric > 16777214) + { + /* vty_out (vty, "OSPF metric value is invalid%s", VTY_NEWLINE); */ + return 0; + } + + return 1; +} + +int +str2metric_type (char *str, int *metric_type) +{ + /* Sanity check. */ + if (str == NULL) + return 0; + + if (strncmp (str, "1", 1) == 0) + *metric_type = EXTERNAL_METRIC_TYPE_1; + else if (strncmp (str, "2", 1) == 0) + *metric_type = EXTERNAL_METRIC_TYPE_2; + else + return 0; + + return 1; +} + +int +ospf_oi_count (struct interface *ifp) +{ + struct route_node *rn; + int i = 0; + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + if (rn->info) + i++; + + return i; +} + + +DEFUN (router_ospf, + router_ospf_cmd, + "router ospf", + "Enable a routing process\n" + "Start OSPF configuration\n") +{ + vty->node = OSPF_NODE; + vty->index = ospf_get (); + + return CMD_SUCCESS; +} + +DEFUN (no_router_ospf, + no_router_ospf_cmd, + "no router ospf", + NO_STR + "Enable a routing process\n" + "Start OSPF configuration\n") +{ + if (ospf_top == NULL) + { + vty_out (vty, "There isn't active ospf instance.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ospf_finish (ospf_top); + + return CMD_SUCCESS; +} + +DEFUN (ospf_router_id, + ospf_router_id_cmd, + "ospf router-id A.B.C.D", + "OSPF specific commands\n" + "router-id for the OSPF process\n" + "OSPF router-id in IP address format\n") +{ + int ret; + struct in_addr router_id; + + ret = inet_aton (argv[0], &router_id); + if (!ret) + { + vty_out (vty, "Please specify Router ID by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* ospf_top->router_id = router_id; */ + ospf_top->router_id_static = router_id; + + if (ospf_top->t_router_id_update == NULL) + ospf_top->t_router_id_update = + thread_add_timer (master, ospf_router_id_update_timer, NULL, + OSPF_ROUTER_ID_UPDATE_DELAY); + + return CMD_SUCCESS; +} + +ALIAS (ospf_router_id, + router_id_cmd, + "router-id A.B.C.D", + "router-id for the OSPF process\n" + "OSPF router-id in IP address format\n") + +DEFUN (no_ospf_router_id, + no_ospf_router_id_cmd, + "no ospf router-id", + NO_STR + "OSPF specific commands\n" + "router-id for the OSPF process\n") +{ + ospf_top->router_id_static.s_addr = 0; + + ospf_router_id_update (); + + return CMD_SUCCESS; +} + +ALIAS (no_ospf_router_id, + no_router_id_cmd, + "no router-id", + NO_STR + "router-id for the OSPF process\n") + +DEFUN (passive_interface, + passive_interface_addr_cmd, + "passive-interface IFNAME A.B.C.D", + "Suppress routing updates on an interface\n" + "Interface's name\n") +{ + struct interface *ifp; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = if_lookup_by_name (argv[0]); + + if (ifp == NULL) + { + vty_out (vty, "Please specify an existing interface%s", VTY_NEWLINE); + return CMD_WARNING; + } + + params = IF_DEF_PARAMS (ifp); + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + SET_IF_PARAM (params, passive_interface); + params->passive_interface = OSPF_IF_PASSIVE; + + return CMD_SUCCESS; +} + +ALIAS (passive_interface, + passive_interface_cmd, + "passive-interface IFNAME", + "Suppress routing updates on an interface\n" + "Interface's name\n") + +DEFUN (no_passive_interface, + no_passive_interface_addr_cmd, + "no passive-interface IFNAME A.B.C.D", + NO_STR + "Allow routing updates on an interface\n" + "Interface's name\n") +{ + struct interface *ifp; + struct in_addr addr; + struct ospf_if_params *params; + int ret; + + ifp = if_lookup_by_name (argv[0]); + + if (ifp == NULL) + { + vty_out (vty, "Please specify an existing interface%s", VTY_NEWLINE); + return CMD_WARNING; + } + + params = IF_DEF_PARAMS (ifp); + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + UNSET_IF_PARAM (params, passive_interface); + params->passive_interface = OSPF_IF_ACTIVE; + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + return CMD_SUCCESS; +} + +ALIAS (no_passive_interface, + no_passive_interface_cmd, + "no passive-interface IFNAME", + NO_STR + "Allow routing updates on an interface\n" + "Interface's name\n") + +DEFUN (network_area, + network_area_cmd, + "network A.B.C.D/M area (A.B.C.D|<0-4294967295>)", + "Enable routing on an IP network\n" + "OSPF network prefix\n" + "Set the OSPF area ID\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n") +{ + struct ospf *ospf= vty->index; + struct prefix_ipv4 p; + struct in_addr area_id; + int ret, format; + + /* Get network prefix and Area ID. */ + VTY_GET_IPV4_PREFIX ("network prefix", p, argv[0]); + VTY_GET_OSPF_AREA_ID (area_id, format, argv[1]); + + ret = ospf_network_set (ospf, &p, area_id); + if (ret == 0) + { + vty_out (vty, "There is already same network statement.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (no_network_area, + no_network_area_cmd, + "no network A.B.C.D/M area (A.B.C.D|<0-4294967295>)", + NO_STR + "Enable routing on an IP network\n" + "OSPF network prefix\n" + "Set the OSPF area ID\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n") +{ + struct ospf *ospf = (struct ospf *) vty->index; + struct prefix_ipv4 p; + struct in_addr area_id; + int ret, format; + + /* Get network prefix and Area ID. */ + VTY_GET_IPV4_PREFIX ("network prefix", p, argv[0]); + VTY_GET_OSPF_AREA_ID (area_id, format, argv[1]); + + ret = ospf_network_unset (ospf, &p, area_id); + if (ret == 0) + { + vty_out (vty, "Can't find specified network area configuration.%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + + +DEFUN (area_range, + area_range_cmd, + "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n") +{ + struct ospf *ospf = vty->index; + struct prefix_ipv4 p; + struct in_addr area_id; + int format; + u_int32_t cost; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + VTY_GET_IPV4_PREFIX ("area range", p, argv[1]); + + ospf_area_range_set (ospf, area_id, &p, OSPF_AREA_RANGE_ADVERTISE); + if (argc > 2) + { + VTY_GET_UINT32 ("range cost", cost, argv[2]); + ospf_area_range_cost_set (ospf, area_id, &p, cost); + } + + return CMD_SUCCESS; +} + +ALIAS (area_range, + area_range_advertise_cmd, + "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "OSPF area range for route advertise (default)\n" + "Area range prefix\n" + "Advertise this range (default)\n") + +ALIAS (area_range, + area_range_cost_cmd, + "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M cost <0-16777215>", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "User specified metric for this range\n" + "Advertised metric for this range\n") + +ALIAS (area_range, + area_range_advertise_cost_cmd, + "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise cost <0-16777215>", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "Advertise this range (default)\n" + "User specified metric for this range\n" + "Advertised metric for this range\n") + +DEFUN (area_range_not_advertise, + area_range_not_advertise_cmd, + "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M not-advertise", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "DoNotAdvertise this range\n") +{ + struct ospf *ospf = vty->index; + struct prefix_ipv4 p; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + VTY_GET_IPV4_PREFIX ("area range", p, argv[1]); + + ospf_area_range_set (ospf, area_id, &p, 0); + + return CMD_SUCCESS; +} + +DEFUN (no_area_range, + no_area_range_cmd, + "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n") +{ + struct ospf *ospf = vty->index; + struct prefix_ipv4 p; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + VTY_GET_IPV4_PREFIX ("area range", p, argv[1]); + + ospf_area_range_unset (ospf, area_id, &p); + + return CMD_SUCCESS; +} + +ALIAS (no_area_range, + no_area_range_advertise_cmd, + "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M (advertise|not-advertise)", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "Advertise this range (default)\n" + "DoNotAdvertise this range\n") + +ALIAS (no_area_range, + no_area_range_cost_cmd, + "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M cost <0-16777215>", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "User specified metric for this range\n" + "Advertised metric for this range\n") + +ALIAS (no_area_range, + no_area_range_advertise_cost_cmd, + "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise cost <0-16777215>", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "Advertise this range (default)\n" + "User specified metric for this range\n" + "Advertised metric for this range\n") + +DEFUN (area_range_substitute, + area_range_substitute_cmd, + "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M substitute A.B.C.D/M", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "Announce area range as another prefix\n" + "Network prefix to be announced instead of range\n") +{ + struct ospf *ospf = vty->index; + struct prefix_ipv4 p, s; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + VTY_GET_IPV4_PREFIX ("area range", p, argv[1]); + VTY_GET_IPV4_PREFIX ("substituted network prefix", s, argv[2]); + + ospf_area_range_substitute_set (ospf, area_id, &p, &s); + + return CMD_SUCCESS; +} + +DEFUN (no_area_range_substitute, + no_area_range_substitute_cmd, + "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M substitute A.B.C.D/M", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "Announce area range as another prefix\n" + "Network prefix to be announced instead of range\n") +{ + struct ospf *ospf = vty->index; + struct prefix_ipv4 p, s; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + VTY_GET_IPV4_PREFIX ("area range", p, argv[1]); + VTY_GET_IPV4_PREFIX ("substituted network prefix", s, argv[2]); + + ospf_area_range_substitute_unset (ospf, area_id, &p); + + return CMD_SUCCESS; +} + + +/* Command Handler Logic in VLink stuff is delicate!! + + ALTER AT YOUR OWN RISK!!!! + + Various dummy values are used to represent 'NoChange' state for + VLink configuration NOT being changed by a VLink command, and + special syntax is used within the command strings so that the + typed in command verbs can be seen in the configuration command + bacckend handler. This is to drastically reduce the verbeage + required to coe up with a reasonably compatible Cisco VLink command + + - Matthew Grant + Wed, 21 Feb 2001 15:13:52 +1300 + */ + + +/* Configuration data for virtual links + */ +struct ospf_vl_config_data { + struct vty *vty; /* vty stuff */ + struct in_addr area_id; /* area ID from command line */ + int format; /* command line area ID format */ + struct in_addr vl_peer; /* command line vl_peer */ + int auth_type; /* Authehntication type, if given */ + char *auth_key; /* simple password if present */ + int crypto_key_id; /* Cryptographic key ID */ + char *md5_key; /* MD5 authentication key */ + int hello_interval; /* Obvious what these are... */ + int retransmit_interval; + int transmit_delay; + int dead_interval; +}; + +void +ospf_vl_config_data_init (struct ospf_vl_config_data *vl_config, + struct vty *vty) +{ + memset (vl_config, 0, sizeof (struct ospf_vl_config_data)); + vl_config->auth_type = OSPF_AUTH_CMD_NOTSEEN; + vl_config->vty = vty; +} + +struct ospf_vl_data * +ospf_find_vl_data (struct ospf_vl_config_data *vl_config) +{ + struct ospf_area *area; + struct ospf_vl_data *vl_data; + struct vty *vty; + struct in_addr area_id; + + vty = vl_config->vty; + area_id = vl_config->area_id; + + if (area_id.s_addr == OSPF_AREA_BACKBONE) + { + vty_out (vty, + "Configuring VLs over the backbone is not allowed%s", + VTY_NEWLINE); + return NULL; + } + area = ospf_area_get (area_id, vl_config->format); + + if (area->external_routing != OSPF_AREA_DEFAULT) + { + if (vl_config->format == OSPF_AREA_ID_FORMAT_ADDRESS) + vty_out (vty, "Area %s is %s%s", + inet_ntoa (area_id), +#ifdef HAVE_NSSA + area->external_routing == OSPF_AREA_NSSA?"nssa":"stub", +#else + "stub", +#endif /* HAVE_NSSA */ + VTY_NEWLINE); + else + vty_out (vty, "Area %ld is %s%s", + (u_long)ntohl (area_id.s_addr), +#ifdef HAVE_NSSA + area->external_routing == OSPF_AREA_NSSA?"nssa":"stub", +#else + "stub", +#endif /* HAVE_NSSA */ + VTY_NEWLINE); + return NULL; + } + + if ((vl_data = ospf_vl_lookup (area, vl_config->vl_peer)) == NULL) + { + vl_data = ospf_vl_data_new (area, vl_config->vl_peer); + if (vl_data->vl_oi == NULL) + { + vl_data->vl_oi = ospf_vl_new (vl_data); + ospf_vl_add (vl_data); + ospf_spf_calculate_schedule (); + } + } + return vl_data; +} + + +int +ospf_vl_set_security (struct ospf_vl_data *vl_data, + struct ospf_vl_config_data *vl_config) +{ + struct crypt_key *ck; + struct vty *vty; + struct interface *ifp = vl_data->vl_oi->ifp; + + vty = vl_config->vty; + + if (vl_config->auth_type != OSPF_AUTH_CMD_NOTSEEN) + { + SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_type); + IF_DEF_PARAMS (ifp)->auth_type = vl_config->auth_type; + } + + if (vl_config->auth_key) + { + memset(IF_DEF_PARAMS (ifp)->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE+1); + strncpy (IF_DEF_PARAMS (ifp)->auth_simple, vl_config->auth_key, + OSPF_AUTH_SIMPLE_SIZE); + } + else if (vl_config->md5_key) + { + if (ospf_crypt_key_lookup (IF_DEF_PARAMS (ifp)->auth_crypt, vl_config->crypto_key_id) + != NULL) + { + vty_out (vty, "OSPF: Key %d already exists%s", + vl_config->crypto_key_id, VTY_NEWLINE); + return CMD_WARNING; + } + ck = ospf_crypt_key_new (); + ck->key_id = vl_config->crypto_key_id; + memset(ck->auth_key, 0, OSPF_AUTH_MD5_SIZE+1); + strncpy (ck->auth_key, vl_config->md5_key, OSPF_AUTH_MD5_SIZE); + + ospf_crypt_key_add (IF_DEF_PARAMS (ifp)->auth_crypt, ck); + } + else if (vl_config->crypto_key_id != 0) + { + /* Delete a key */ + + if (ospf_crypt_key_lookup (IF_DEF_PARAMS (ifp)->auth_crypt, + vl_config->crypto_key_id) == NULL) + { + vty_out (vty, "OSPF: Key %d does not exist%s", + vl_config->crypto_key_id, VTY_NEWLINE); + return CMD_WARNING; + } + + ospf_crypt_key_delete (IF_DEF_PARAMS (ifp)->auth_crypt, vl_config->crypto_key_id); + + } + + return CMD_SUCCESS; +} + + + +int +ospf_vl_set_timers (struct ospf_vl_data *vl_data, + struct ospf_vl_config_data *vl_config) +{ + struct interface *ifp = ifp = vl_data->vl_oi->ifp; + /* Virtual Link data initialised to defaults, so only set + if a value given */ + if (vl_config->hello_interval) + { + SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_hello); + IF_DEF_PARAMS (ifp)->v_hello = vl_config->hello_interval; + } + + if (vl_config->dead_interval) + { + SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_wait); + IF_DEF_PARAMS (ifp)->v_wait = vl_config->dead_interval; + } + + if (vl_config->retransmit_interval) + { + SET_IF_PARAM (IF_DEF_PARAMS (ifp), retransmit_interval); + IF_DEF_PARAMS (ifp)->retransmit_interval = vl_config->retransmit_interval; + } + + if (vl_config->transmit_delay) + { + SET_IF_PARAM (IF_DEF_PARAMS (ifp), transmit_delay); + IF_DEF_PARAMS (ifp)->transmit_delay = vl_config->transmit_delay; + } + + return CMD_SUCCESS; +} + + + +/* The business end of all of the above */ +int +ospf_vl_set (struct ospf_vl_config_data *vl_config) +{ + struct ospf_vl_data *vl_data; + int ret; + + vl_data = ospf_find_vl_data (vl_config); + if (!vl_data) + return CMD_WARNING; + + /* Process this one first as it can have a fatal result, which can + only logically occur if the virtual link exists already + Thus a command error does not result in a change to the + running configuration such as unexpectedly altered timer + values etc.*/ + ret = ospf_vl_set_security (vl_data, vl_config); + if (ret != CMD_SUCCESS) + return ret; + + /* Set any time based parameters, these area already range checked */ + + ret = ospf_vl_set_timers (vl_data, vl_config); + if (ret != CMD_SUCCESS) + return ret; + + return CMD_SUCCESS; + +} + +/* This stuff exists to make specifying all the alias commands A LOT simpler + */ +#define VLINK_HELPSTR_IPADDR \ + "OSPF area parameters\n" \ + "OSPF area ID in IP address format\n" \ + "OSPF area ID as a decimal value\n" \ + "Configure a virtual link\n" \ + "Router ID of the remote ABR\n" + +#define VLINK_HELPSTR_AUTHTYPE_SIMPLE \ + "Enable authentication on this virtual link\n" \ + "dummy string \n" + +#define VLINK_HELPSTR_AUTHTYPE_ALL \ + VLINK_HELPSTR_AUTHTYPE_SIMPLE \ + "Use null authentication\n" \ + "Use message-digest authentication\n" + +#define VLINK_HELPSTR_TIME_PARAM_NOSECS \ + "Time between HELLO packets\n" \ + "Time between retransmitting lost link state advertisements\n" \ + "Link state transmit delay\n" \ + "Interval after which a neighbor is declared dead\n" + +#define VLINK_HELPSTR_TIME_PARAM \ + VLINK_HELPSTR_TIME_PARAM_NOSECS \ + "Seconds\n" + +#define VLINK_HELPSTR_AUTH_SIMPLE \ + "Authentication password (key)\n" \ + "The OSPF password (key)" + +#define VLINK_HELPSTR_AUTH_MD5 \ + "Message digest authentication password (key)\n" \ + "dummy string \n" \ + "Key ID\n" \ + "Use MD5 algorithm\n" \ + "The OSPF password (key)" + +DEFUN (area_vlink, + area_vlink_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D", + VLINK_HELPSTR_IPADDR) +{ + struct ospf_vl_config_data vl_config; + char auth_key[OSPF_AUTH_SIMPLE_SIZE+1]; + char md5_key[OSPF_AUTH_MD5_SIZE+1]; + int i; + int ret; + + ospf_vl_config_data_init(&vl_config, vty); + + /* Read off first 2 parameters and check them */ + ret = ospf_str2area_id (argv[0], &vl_config.area_id, &vl_config.format); + if (ret < 0) + { + vty_out (vty, "OSPF area ID is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = inet_aton (argv[1], &vl_config.vl_peer); + if (! ret) + { + vty_out (vty, "Please specify valid Router ID as a.b.c.d%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc <=2) + { + /* Thats all folks! - BUGS B. strikes again!!!*/ + + return ospf_vl_set (&vl_config); + } + + /* Deal with other parameters */ + for (i=2; i < argc; i++) + { + + /* vty_out (vty, "argv[%d] - %s%s", i, argv[i], VTY_NEWLINE); */ + + switch (argv[i][0]) + { + + case 'a': + if (i > 2 || strncmp (argv[i], "authentication-", 15) == 0) + { + /* authentication-key - this option can occur anywhere on + command line. At start of command line + must check for authentication option. */ + memset (auth_key, 0, OSPF_AUTH_SIMPLE_SIZE + 1); + strncpy (auth_key, argv[i+1], OSPF_AUTH_SIMPLE_SIZE); + vl_config.auth_key = auth_key; + i++; + } + else if (strncmp (argv[i], "authentication", 14) == 0) + { + /* authentication - this option can only occur at start + of command line */ + vl_config.auth_type = OSPF_AUTH_SIMPLE; + if ((i+1) < argc) + { + if (strncmp (argv[i+1], "n", 1) == 0) + { + /* "authentication null" */ + vl_config.auth_type = OSPF_AUTH_NULL; + i++; + } + else if (strncmp (argv[i+1], "m", 1) == 0 + && strcmp (argv[i+1], "message-digest-") != 0) + { + /* "authentication message-digest" */ + vl_config.auth_type = OSPF_AUTH_CRYPTOGRAPHIC; + i++; + } + } + } + break; + + case 'm': + /* message-digest-key */ + i++; + vl_config.crypto_key_id = strtol (argv[i], NULL, 10); + if (vl_config.crypto_key_id < 0) + return CMD_WARNING; + i++; + memset(md5_key, 0, OSPF_AUTH_MD5_SIZE+1); + strncpy (md5_key, argv[i], OSPF_AUTH_MD5_SIZE); + vl_config.md5_key = md5_key; + break; + + case 'h': + /* Hello interval */ + i++; + vl_config.hello_interval = strtol (argv[i], NULL, 10); + if (vl_config.hello_interval < 0) + return CMD_WARNING; + break; + + case 'r': + /* Retransmit Interval */ + i++; + vl_config.retransmit_interval = strtol (argv[i], NULL, 10); + if (vl_config.retransmit_interval < 0) + return CMD_WARNING; + break; + + case 't': + /* Transmit Delay */ + i++; + vl_config.transmit_delay = strtol (argv[i], NULL, 10); + if (vl_config.transmit_delay < 0) + return CMD_WARNING; + break; + + case 'd': + /* Dead Interval */ + i++; + vl_config.dead_interval = strtol (argv[i], NULL, 10); + if (vl_config.dead_interval < 0) + return CMD_WARNING; + break; + } + } + + + /* Action configuration */ + + return ospf_vl_set (&vl_config); + +} + +DEFUN (no_area_vlink, + no_area_vlink_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D", + NO_STR + VLINK_HELPSTR_IPADDR) +{ + struct ospf_area *area; + struct ospf_vl_config_data vl_config; + struct ospf_vl_data *vl_data = NULL; + char auth_key[OSPF_AUTH_SIMPLE_SIZE+1]; + int i; + int ret, format; + + ospf_vl_config_data_init(&vl_config, vty); + + ret = ospf_str2area_id (argv[0], &vl_config.area_id, &format); + if (ret < 0) + { + vty_out (vty, "OSPF area ID is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + area = ospf_area_lookup_by_area_id (vl_config.area_id); + if (!area) + { + vty_out (vty, "Area does not exist%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = inet_aton (argv[1], &vl_config.vl_peer); + if (! ret) + { + vty_out (vty, "Please specify valid Router ID as a.b.c.d%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc <=2) + { + /* Basic VLink no command */ + /* Thats all folks! - BUGS B. strikes again!!!*/ + if ((vl_data = ospf_vl_lookup (area, vl_config.vl_peer))) + ospf_vl_delete (vl_data); + + ospf_area_check_free (vl_config.area_id); + + return CMD_SUCCESS; + } + + /* If we are down here, we are reseting parameters */ + + /* Deal with other parameters */ + for (i=2; i < argc; i++) + { + + /* vty_out (vty, "argv[%d] - %s%s", i, argv[i], VTY_NEWLINE); */ + + switch (argv[i][0]) + { + + case 'a': + if (i > 2 || strncmp (argv[i], "authentication-", 15) == 0) + { + /* authentication-key - this option can occur anywhere on + command line. At start of command line + must check for authentication option. */ + memset (auth_key, 0, OSPF_AUTH_SIMPLE_SIZE + 1); + vl_config.auth_key = auth_key; + } + else if (strncmp (argv[i], "authentication", 14) == 0) + { + /* authentication - this option can only occur at start + of command line */ + vl_config.auth_type = OSPF_AUTH_NOTSET; + } + break; + + case 'm': + /* message-digest-key */ + /* Delete one key */ + i++; + vl_config.crypto_key_id = strtol (argv[i], NULL, 10); + if (vl_config.crypto_key_id < 0) + return CMD_WARNING; + vl_config.md5_key = NULL; + break; + + case 'h': + /* Hello interval */ + vl_config.hello_interval = OSPF_HELLO_INTERVAL_DEFAULT; + break; + + case 'r': + /* Retransmit Interval */ + vl_config.retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; + break; + + case 't': + /* Transmit Delay */ + vl_config.transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT; + break; + + case 'd': + /* Dead Interval */ + i++; + vl_config.dead_interval = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT; + break; + } + } + + + /* Action configuration */ + + return ospf_vl_set (&vl_config); +} + +ALIAS (area_vlink, + area_vlink_param1_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_TIME_PARAM) + +ALIAS (no_area_vlink, + no_area_vlink_param1_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", + NO_STR + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_TIME_PARAM) + +ALIAS (area_vlink, + area_vlink_param2_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM) + +ALIAS (no_area_vlink, + no_area_vlink_param2_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", + NO_STR + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM) + +ALIAS (area_vlink, + area_vlink_param3_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM) + +ALIAS (no_area_vlink, + no_area_vlink_param3_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", + NO_STR + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM) + +ALIAS (area_vlink, + area_vlink_param4_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM) + +ALIAS (no_area_vlink, + no_area_vlink_param4_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", + NO_STR + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM) + +ALIAS (area_vlink, + area_vlink_authtype_args_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) (message-digest|null)", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTHTYPE_ALL) + +ALIAS (area_vlink, + area_vlink_authtype_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|)", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTHTYPE_SIMPLE) + +ALIAS (no_area_vlink, + no_area_vlink_authtype_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|)", + NO_STR + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTHTYPE_SIMPLE) + +ALIAS (area_vlink, + area_vlink_md5_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(message-digest-key|) <1-255> md5 KEY", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTH_MD5) + +ALIAS (no_area_vlink, + no_area_vlink_md5_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(message-digest-key|) <1-255>", + NO_STR + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTH_MD5) + +ALIAS (area_vlink, + area_vlink_authkey_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication-key|) AUTH_KEY", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTH_SIMPLE) + +ALIAS (no_area_vlink, + no_area_vlink_authkey_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication-key|)", + NO_STR + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTH_SIMPLE) + +ALIAS (area_vlink, + area_vlink_authtype_args_authkey_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) (message-digest|null) " + "(authentication-key|) AUTH_KEY", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTHTYPE_ALL + VLINK_HELPSTR_AUTH_SIMPLE) + +ALIAS (area_vlink, + area_vlink_authtype_authkey_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) " + "(authentication-key|) AUTH_KEY", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTHTYPE_SIMPLE + VLINK_HELPSTR_AUTH_SIMPLE) + +ALIAS (no_area_vlink, + no_area_vlink_authtype_authkey_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) " + "(authentication-key|)", + NO_STR + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTHTYPE_SIMPLE + VLINK_HELPSTR_AUTH_SIMPLE) + +ALIAS (area_vlink, + area_vlink_authtype_args_md5_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) (message-digest|null) " + "(message-digest-key|) <1-255> md5 KEY", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTHTYPE_ALL + VLINK_HELPSTR_AUTH_MD5) + +ALIAS (area_vlink, + area_vlink_authtype_md5_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) " + "(message-digest-key|) <1-255> md5 KEY", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTHTYPE_SIMPLE + VLINK_HELPSTR_AUTH_MD5) + +ALIAS (no_area_vlink, + no_area_vlink_authtype_md5_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) " + "(message-digest-key|)", + NO_STR + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTHTYPE_SIMPLE + VLINK_HELPSTR_AUTH_MD5) + + +DEFUN (area_shortcut, + area_shortcut_cmd, + "area (A.B.C.D|<0-4294967295>) shortcut (default|enable|disable)", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure the area's shortcutting mode\n" + "Set default shortcutting behavior\n" + "Enable shortcutting through the area\n" + "Disable shortcutting through the area\n") +{ + struct ospf_area *area; + struct in_addr area_id; + int mode; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("shortcut", area_id, format, argv[0]); + + area = ospf_area_get (area_id, format); + + if (strncmp (argv[1], "de", 2) == 0) + mode = OSPF_SHORTCUT_DEFAULT; + else if (strncmp (argv[1], "di", 2) == 0) + mode = OSPF_SHORTCUT_DISABLE; + else if (strncmp (argv[1], "e", 1) == 0) + mode = OSPF_SHORTCUT_ENABLE; + else + return CMD_WARNING; + + ospf_area_shortcut_set (area, mode); + + if (ospf_top->abr_type != OSPF_ABR_SHORTCUT) + vty_out (vty, "Shortcut area setting will take effect " + "only when the router is configured as Shortcut ABR%s", + VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN (no_area_shortcut, + no_area_shortcut_cmd, + "no area (A.B.C.D|<0-4294967295>) shortcut (enable|disable)", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Deconfigure the area's shortcutting mode\n" + "Deconfigure enabled shortcutting through the area\n" + "Deconfigure disabled shortcutting through the area\n") +{ + struct ospf_area *area; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("shortcut", area_id, format, argv[0]); + + area = ospf_area_lookup_by_area_id (area_id); + if (!area) + return CMD_SUCCESS; + + ospf_area_shortcut_unset (area); + + return CMD_SUCCESS; +} + + +DEFUN (area_stub, + area_stub_cmd, + "area (A.B.C.D|<0-4294967295>) stub", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as stub\n") +{ + struct ospf *ospf = vty->index; + struct in_addr area_id; + int ret, format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("stub", area_id, format, argv[0]); + + ret = ospf_area_stub_set (ospf, area_id); + if (ret == 0) + { + vty_out (vty, "First deconfigure all virtual link through this area%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ospf_area_no_summary_unset (ospf, area_id); + + return CMD_SUCCESS; +} + +DEFUN (area_stub_no_summary, + area_stub_no_summary_cmd, + "area (A.B.C.D|<0-4294967295>) stub no-summary", + "OSPF stub parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as stub\n" + "Do not inject inter-area routes into stub\n") +{ + struct ospf *ospf = vty->index; + struct in_addr area_id; + int ret, format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("stub", area_id, format, argv[0]); + + ret = ospf_area_stub_set (ospf, area_id); + if (ret == 0) + { + vty_out (vty, "%% Area cannot be nssa as it contains a virtual link%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ospf_area_no_summary_set (ospf, area_id); + + return CMD_SUCCESS; +} + +DEFUN (no_area_stub, + no_area_stub_cmd, + "no area (A.B.C.D|<0-4294967295>) stub", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as stub\n") +{ + struct ospf *ospf = vty->index; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("stub", area_id, format, argv[0]); + + ospf_area_stub_unset (ospf, area_id); + ospf_area_no_summary_unset (ospf, area_id); + + return CMD_SUCCESS; +} + +DEFUN (no_area_stub_no_summary, + no_area_stub_no_summary_cmd, + "no area (A.B.C.D|<0-4294967295>) stub no-summary", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as stub\n" + "Do not inject inter-area routes into area\n") +{ + struct ospf *ospf = vty->index; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("stub", area_id, format, argv[0]); + ospf_area_no_summary_unset (ospf, area_id); + + return CMD_SUCCESS; +} + +#ifdef HAVE_NSSA +DEFUN (area_nssa, + area_nssa_cmd, + "area (A.B.C.D|<0-4294967295>) nssa", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as nssa\n") +{ + struct ospf *ospf = vty->index; + struct in_addr area_id; + int ret, format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("NSSA", area_id, format, argv[0]); + + ret = ospf_area_nssa_set (ospf, area_id); + if (ret == 0) + { + vty_out (vty, "%% Area cannot be nssa as it contains a virtual link%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc > 1) + { + if (strncmp (argv[1], "translate-c", 11) == 0) + ospf_area_nssa_translator_role_set (ospf, area_id, + OSPF_NSSA_ROLE_CANDIDATE); + else if (strncmp (argv[1], "translate-n", 11) == 0) + ospf_area_nssa_translator_role_set (ospf, area_id, + OSPF_NSSA_ROLE_NEVER); + else if (strncmp (argv[1], "translate-a", 11) == 0) + ospf_area_nssa_translator_role_set (ospf, area_id, + OSPF_NSSA_ROLE_ALWAYS); + } + + if (argc > 2) + ospf_area_no_summary_set (ospf, area_id); + + return CMD_SUCCESS; +} + +ALIAS (area_nssa, + area_nssa_translate_no_summary_cmd, + "area (A.B.C.D|<0-4294967295>) nssa (translate-candidate|translate-never|translate-always) (no-summary|)", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as nssa\n" + "Configure NSSA-ABR for translate election (default)\n" + "Configure NSSA-ABR to never translate\n" + "Configure NSSA-ABR to always translate\n" + "Do not inject inter-area routes into nssa\n" + "dummy\n") + +ALIAS (area_nssa, + area_nssa_translate_cmd, + "area (A.B.C.D|<0-4294967295>) nssa (translate-candidate|translate-never|translate-always)", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as nssa\n" + "Configure NSSA-ABR for translate election (default)\n" + "Configure NSSA-ABR to never translate\n" + "Configure NSSA-ABR to always translate\n") + +DEFUN (area_nssa_no_summary, + area_nssa_no_summary_cmd, + "area (A.B.C.D|<0-4294967295>) nssa no-summary", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as nssa\n" + "Do not inject inter-area routes into nssa\n") +{ + struct ospf *ospf = vty->index; + struct in_addr area_id; + int ret, format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("NSSA", area_id, format, argv[0]); + + ret = ospf_area_nssa_set (ospf, area_id); + if (ret == 0) + { + vty_out (vty, "%% Area cannot be nssa as it contains a virtual link%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ospf_area_no_summary_set (ospf, area_id); + + return CMD_SUCCESS; +} + +DEFUN (no_area_nssa, + no_area_nssa_cmd, + "no area (A.B.C.D|<0-4294967295>) nssa", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as nssa\n") +{ + struct ospf *ospf = vty->index; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("NSSA", area_id, format, argv[0]); + + ospf_area_nssa_unset (ospf, area_id); + ospf_area_no_summary_unset (ospf, area_id); + + return CMD_SUCCESS; +} + +DEFUN (no_area_nssa_no_summary, + no_area_nssa_no_summary_cmd, + "no area (A.B.C.D|<0-4294967295>) nssa no-summary", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as nssa\n" + "Do not inject inter-area routes into nssa\n") +{ + struct ospf *ospf = vty->index; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("NSSA", area_id, format, argv[0]); + ospf_area_no_summary_unset (ospf, area_id); + + return CMD_SUCCESS; +} + +#endif /* HAVE_NSSA */ + +DEFUN (area_default_cost, + area_default_cost_cmd, + "area (A.B.C.D|<0-4294967295>) default-cost <0-16777215>", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Set the summary-default cost of a NSSA or stub area\n" + "Stub's advertised default summary cost\n") +{ + struct ospf_area *area; + struct in_addr area_id; + u_int32_t cost; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("default-cost", area_id, format, argv[0]); + VTY_GET_INTEGER_RANGE ("stub default cost", cost, argv[1], 0, 16777215); + + area = ospf_area_get (area_id, format); + + if (area->external_routing == OSPF_AREA_DEFAULT) + { + vty_out (vty, "The area is neither stub, nor NSSA%s", VTY_NEWLINE); + return CMD_WARNING; + } + + area->default_cost = cost; + + return CMD_SUCCESS; +} + +DEFUN (no_area_default_cost, + no_area_default_cost_cmd, + "no area (A.B.C.D|<0-4294967295>) default-cost <0-16777215>", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Set the summary-default cost of a NSSA or stub area\n" + "Stub's advertised default summary cost\n") +{ + struct ospf_area *area; + struct in_addr area_id; + u_int32_t cost; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("default-cost", area_id, format, argv[0]); + VTY_GET_INTEGER_RANGE ("stub default cost", cost, argv[1], 0, 16777215); + + area = ospf_area_lookup_by_area_id (area_id); + if (area == NULL) + return CMD_SUCCESS; + + if (area->external_routing == OSPF_AREA_DEFAULT) + { + vty_out (vty, "The area is neither stub, nor NSSA%s", VTY_NEWLINE); + return CMD_WARNING; + } + + area->default_cost = 1; + + ospf_area_check_free (area_id); + + return CMD_SUCCESS; +} + +DEFUN (area_export_list, + area_export_list_cmd, + "area (A.B.C.D|<0-4294967295>) export-list NAME", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Set the filter for networks announced to other areas\n" + "Name of the access-list\n") +{ + struct ospf_area *area; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("export-list", area_id, format, argv[0]); + + area = ospf_area_get (area_id, format); + ospf_area_export_list_set (area, argv[1]); + + return CMD_SUCCESS; +} + +DEFUN (no_area_export_list, + no_area_export_list_cmd, + "no area (A.B.C.D|<0-4294967295>) export-list NAME", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Unset the filter for networks announced to other areas\n" + "Name of the access-list\n") +{ + struct ospf_area *area; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("export-list", area_id, format, argv[0]); + + area = ospf_area_lookup_by_area_id (area_id); + if (area == NULL) + return CMD_SUCCESS; + + ospf_area_export_list_unset (area); + + return CMD_SUCCESS; +} + + +DEFUN (area_import_list, + area_import_list_cmd, + "area (A.B.C.D|<0-4294967295>) import-list NAME", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Set the filter for networks from other areas announced to the specified one\n" + "Name of the access-list\n") +{ + struct ospf_area *area; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("import-list", area_id, format, argv[0]); + + area = ospf_area_get (area_id, format); + ospf_area_import_list_set (area, argv[1]); + + return CMD_SUCCESS; +} + +DEFUN (no_area_import_list, + no_area_import_list_cmd, + "no area (A.B.C.D|<0-4294967295>) import-list NAME", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Unset the filter for networks announced to other areas\n" + "Name of the access-list\n") +{ + struct ospf_area *area; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("import-list", area_id, format, argv[0]); + area = ospf_area_lookup_by_area_id (area_id); + if (area == NULL) + return CMD_SUCCESS; + + ospf_area_import_list_unset (area); + + return CMD_SUCCESS; +} + +DEFUN (area_filter_list, + area_filter_list_cmd, + "area (A.B.C.D|<0-4294967295>) filter-list prefix WORD (in|out)", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Filter networks between OSPF areas\n" + "Filter prefixes between OSPF areas\n" + "Name of an IP prefix-list\n" + "Filter networks sent to this area\n" + "Filter networks sent from this area\n") +{ + struct ospf_area *area; + struct in_addr area_id; + struct prefix_list *plist; + int format; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + + area = ospf_area_get (area_id, format); + plist = prefix_list_lookup (AFI_IP, argv[1]); + if (strncmp (argv[2], "in", 2) == 0) + { + PREFIX_LIST_IN (area) = plist; + if (PREFIX_NAME_IN (area)) + free (PREFIX_NAME_IN (area)); + + PREFIX_NAME_IN (area) = strdup (argv[1]); + ospf_schedule_abr_task (); + } + else + { + PREFIX_LIST_OUT (area) = plist; + if (PREFIX_NAME_OUT (area)) + free (PREFIX_NAME_OUT (area)); + + PREFIX_NAME_OUT (area) = strdup (argv[1]); + ospf_schedule_abr_task (); + } + + return CMD_SUCCESS; +} + +DEFUN (no_area_filter_list, + no_area_filter_list_cmd, + "no area (A.B.C.D|<0-4294967295>) filter-list prefix WORD (in|out)", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Filter networks between OSPF areas\n" + "Filter prefixes between OSPF areas\n" + "Name of an IP prefix-list\n" + "Filter networks sent to this area\n" + "Filter networks sent from this area\n") +{ + struct ospf_area *area; + struct in_addr area_id; + struct prefix_list *plist; + int format; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + + area = ospf_area_lookup_by_area_id (area_id); + plist = prefix_list_lookup (AFI_IP, argv[1]); + if (strncmp (argv[2], "in", 2) == 0) + { + if (PREFIX_NAME_IN (area)) + if (strcmp (PREFIX_NAME_IN (area), argv[1]) != 0) + return CMD_SUCCESS; + + PREFIX_LIST_IN (area) = NULL; + if (PREFIX_NAME_IN (area)) + free (PREFIX_NAME_IN (area)); + + PREFIX_NAME_IN (area) = NULL; + + ospf_schedule_abr_task (); + } + else + { + if (PREFIX_NAME_OUT (area)) + if (strcmp (PREFIX_NAME_OUT (area), argv[1]) != 0) + return CMD_SUCCESS; + + PREFIX_LIST_OUT (area) = NULL; + if (PREFIX_NAME_OUT (area)) + free (PREFIX_NAME_OUT (area)); + + PREFIX_NAME_OUT (area) = NULL; + + ospf_schedule_abr_task (); + } + + return CMD_SUCCESS; +} + + +DEFUN (area_authentication_message_digest, + area_authentication_message_digest_cmd, + "area (A.B.C.D|<0-4294967295>) authentication message-digest", + "OSPF area parameters\n" + "Enable authentication\n" + "Use message-digest authentication\n") +{ + struct ospf_area *area; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + + area = ospf_area_get (area_id, format); + area->auth_type = OSPF_AUTH_CRYPTOGRAPHIC; + + return CMD_SUCCESS; +} + +DEFUN (area_authentication, + area_authentication_cmd, + "area (A.B.C.D|<0-4294967295>) authentication", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Enable authentication\n") +{ + struct ospf_area *area; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + + area = ospf_area_get (area_id, format); + area->auth_type = OSPF_AUTH_SIMPLE; + + return CMD_SUCCESS; +} + +DEFUN (no_area_authentication, + no_area_authentication_cmd, + "no area (A.B.C.D|<0-4294967295>) authentication", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Enable authentication\n") +{ + struct ospf_area *area; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + + area = ospf_area_lookup_by_area_id (area_id); + if (area == NULL) + return CMD_SUCCESS; + + area->auth_type = OSPF_AUTH_NULL; + + ospf_area_check_free (area_id); + + return CMD_SUCCESS; +} + + +DEFUN (ospf_abr_type, + ospf_abr_type_cmd, + "ospf abr-type (cisco|ibm|shortcut|standard)", + "OSPF specific commands\n" + "Set OSPF ABR type\n" + "Alternative ABR, cisco implementation\n" + "Alternative ABR, IBM implementation\n" + "Shortcut ABR\n" + "Standard behavior (RFC2328)\n") +{ + u_char abr_type = OSPF_ABR_UNKNOWN; + + if (strncmp (argv[0], "c", 1) == 0) + abr_type = OSPF_ABR_CISCO; + else if (strncmp (argv[0], "i", 1) == 0) + abr_type = OSPF_ABR_IBM; + else if (strncmp (argv[0], "sh", 2) == 0) + abr_type = OSPF_ABR_SHORTCUT; + else if (strncmp (argv[0], "st", 2) == 0) + abr_type = OSPF_ABR_STAND; + else + return CMD_WARNING; + + /* If ABR type value is changed, schedule ABR task. */ + if (ospf_top->abr_type != abr_type) + { + ospf_top->abr_type = abr_type; + ospf_schedule_abr_task (); + } + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_abr_type, + no_ospf_abr_type_cmd, + "no ospf abr-type (cisco|ibm|shortcut)", + NO_STR + "OSPF specific commands\n" + "Set OSPF ABR type\n" + "Alternative ABR, cisco implementation\n" + "Alternative ABR, IBM implementation\n" + "Shortcut ABR\n") +{ + u_char abr_type = OSPF_ABR_UNKNOWN; + + if (strncmp (argv[0], "c", 1) == 0) + abr_type = OSPF_ABR_CISCO; + else if (strncmp (argv[0], "i", 1) == 0) + abr_type = OSPF_ABR_IBM; + else if (strncmp (argv[0], "s", 1) == 0) + abr_type = OSPF_ABR_SHORTCUT; + else + return CMD_WARNING; + + /* If ABR type value is changed, schedule ABR task. */ + if (ospf_top->abr_type == abr_type) + { + ospf_top->abr_type = OSPF_ABR_STAND; + ospf_schedule_abr_task (); + } + + return CMD_SUCCESS; +} + +DEFUN (ospf_compatible_rfc1583, + ospf_compatible_rfc1583_cmd, + "compatible rfc1583", + "OSPF compatibility list\n" + "compatible with RFC 1583\n") +{ + struct ospf *ospf = vty->index; + + if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) + { + SET_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE); + ospf_spf_calculate_schedule (); + } + return CMD_SUCCESS; +} + +DEFUN (no_ospf_compatible_rfc1583, + no_ospf_compatible_rfc1583_cmd, + "no compatible rfc1583", + NO_STR + "OSPF compatibility list\n" + "compatible with RFC 1583\n") +{ + struct ospf *ospf = vty->index; + + if (CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) + { + UNSET_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE); + ospf_spf_calculate_schedule (); + } + return CMD_SUCCESS; +} + +ALIAS (ospf_compatible_rfc1583, + ospf_rfc1583_flag_cmd, + "ospf rfc1583compatibility", + "OSPF specific commands\n" + "Enable the RFC1583Compatibility flag\n") + +ALIAS (no_ospf_compatible_rfc1583, + no_ospf_rfc1583_flag_cmd, + "no ospf rfc1583compatibility", + NO_STR + "OSPF specific commands\n" + "Disable the RFC1583Compatibility flag\n") + +DEFUN (timers_spf, + timers_spf_cmd, + "timers spf <0-4294967295> <0-4294967295>", + "Adjust routing timers\n" + "OSPF SPF timers\n" + "Delay between receiving a change to SPF calculation\n" + "Hold time between consecutive SPF calculations\n") +{ + struct ospf *ospf = vty->index; + u_int32_t delay, hold; + + VTY_GET_UINT32 ("SPF delay timer", delay, argv[0]); + VTY_GET_UINT32 ("SPF hold timer", hold, argv[1]); + + ospf_timers_spf_set (ospf, delay, hold); + + return CMD_SUCCESS; +} + +DEFUN (no_timers_spf, + no_timers_spf_cmd, + "no timers spf", + NO_STR + "Adjust routing timers\n" + "OSPF SPF timers\n") +{ + ospf_top->spf_delay = OSPF_SPF_DELAY_DEFAULT; + ospf_top->spf_holdtime = OSPF_SPF_HOLDTIME_DEFAULT; + + return CMD_SUCCESS; +} + + +DEFUN (neighbor, + neighbor_cmd, + "neighbor A.B.C.D", + NEIGHBOR_STR + "Neighbor IP address\n") +{ + struct ospf *ospf = vty->index; + struct in_addr nbr_addr; + int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; + int interval = OSPF_POLL_INTERVAL_DEFAULT; + + VTY_GET_IPV4_ADDRESS ("neighbor address", nbr_addr, argv[0]); + + if (argc > 1) + VTY_GET_INTEGER_RANGE ("neighbor priority", priority, argv[1], 0, 255); + + if (argc > 2) + VTY_GET_INTEGER_RANGE ("poll interval", interval, argv[2], 1, 65535); + + ospf_nbr_nbma_set (ospf, nbr_addr); + if (argc > 1) + ospf_nbr_nbma_priority_set (ospf, nbr_addr, priority); + if (argc > 2) + ospf_nbr_nbma_poll_interval_set (ospf, nbr_addr, priority); + + return CMD_SUCCESS; +} + +ALIAS (neighbor, + neighbor_priority_poll_interval_cmd, + "neighbor A.B.C.D priority <0-255> poll-interval <1-65535>", + NEIGHBOR_STR + "Neighbor IP address\n" + "Neighbor Priority\n" + "Priority\n" + "Dead Neighbor Polling interval\n" + "Seconds\n") + +ALIAS (neighbor, + neighbor_priority_cmd, + "neighbor A.B.C.D priority <0-255>", + NEIGHBOR_STR + "Neighbor IP address\n" + "Neighbor Priority\n" + "Seconds\n") + +DEFUN (neighbor_poll_interval, + neighbor_poll_interval_cmd, + "neighbor A.B.C.D poll-interval <1-65535>", + NEIGHBOR_STR + "Neighbor IP address\n" + "Dead Neighbor Polling interval\n" + "Seconds\n") +{ + struct ospf *ospf = vty->index; + struct in_addr nbr_addr; + int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; + int interval = OSPF_POLL_INTERVAL_DEFAULT; + + VTY_GET_IPV4_ADDRESS ("neighbor address", nbr_addr, argv[0]); + + if (argc > 1) + VTY_GET_INTEGER_RANGE ("poll interval", interval, argv[1], 1, 65535); + + if (argc > 2) + VTY_GET_INTEGER_RANGE ("neighbor priority", priority, argv[2], 0, 255); + + ospf_nbr_nbma_set (ospf, nbr_addr); + if (argc > 1) + ospf_nbr_nbma_poll_interval_set (ospf, nbr_addr, interval); + if (argc > 2) + ospf_nbr_nbma_priority_set (ospf, nbr_addr, priority); + + return CMD_SUCCESS; +} + +ALIAS (neighbor_poll_interval, + neighbor_poll_interval_priority_cmd, + "neighbor A.B.C.D poll-interval <1-65535> priority <0-255>", + NEIGHBOR_STR + "Neighbor address\n" + "OSPF dead-router polling interval\n" + "Seconds\n" + "OSPF priority of non-broadcast neighbor\n" + "Priority\n") + +DEFUN (no_neighbor, + no_neighbor_cmd, + "no neighbor A.B.C.D", + NO_STR + NEIGHBOR_STR + "Neighbor IP address\n") +{ + struct ospf *ospf = vty->index; + struct in_addr nbr_addr; + int ret; + + VTY_GET_IPV4_ADDRESS ("neighbor address", nbr_addr, argv[0]); + + ret = ospf_nbr_nbma_unset (ospf, nbr_addr); + + return CMD_SUCCESS; +} + +ALIAS (no_neighbor, + no_neighbor_priority_cmd, + "no neighbor A.B.C.D priority <0-255>", + NO_STR + NEIGHBOR_STR + "Neighbor IP address\n" + "Neighbor Priority\n" + "Priority\n") + +ALIAS (no_neighbor, + no_neighbor_poll_interval_cmd, + "no neighbor A.B.C.D poll-interval <1-65535>", + NO_STR + NEIGHBOR_STR + "Neighbor IP address\n" + "Dead Neighbor Polling interval\n" + "Seconds\n") + +ALIAS (no_neighbor, + no_neighbor_priority_pollinterval_cmd, + "no neighbor A.B.C.D priority <0-255> poll-interval <1-65535>", + NO_STR + NEIGHBOR_STR + "Neighbor IP address\n" + "Neighbor Priority\n" + "Priority\n" + "Dead Neighbor Polling interval\n" + "Seconds\n") + + +DEFUN (refresh_timer, refresh_timer_cmd, + "refresh timer <10-1800>", + "Adjust refresh parameters\n" + "Set refresh timer\n" + "Timer value in seconds\n") +{ + struct ospf *ospf = vty->index; + int interval; + + VTY_GET_INTEGER_RANGE ("refresh timer", interval, argv[0], 10, 1800); + interval = (interval / 10) * 10; + + ospf_timers_refresh_set (ospf, interval); + + return CMD_SUCCESS; +} + +DEFUN (no_refresh_timer, no_refresh_timer_val_cmd, + "no refresh timer <10-1800>", + "Adjust refresh parameters\n" + "Unset refresh timer\n" + "Timer value in seconds\n") +{ + struct ospf *ospf = vty->index; + int interval; + + if (argc == 1) + { + VTY_GET_INTEGER_RANGE ("refresh timer", interval, argv[0], 10, 1800); + + if (ospf->lsa_refresh_interval != interval || + interval == OSPF_LSA_REFRESH_INTERVAL_DEFAULT) + return CMD_SUCCESS; + } + + ospf_timers_refresh_unset (ospf); + + return CMD_SUCCESS; +} + +ALIAS (no_refresh_timer, + no_refresh_timer_cmd, + "no refresh timer", + "Adjust refresh parameters\n" + "Unset refresh timer\n") + +DEFUN (auto_cost_reference_bandwidth, + auto_cost_reference_bandwidth_cmd, + "auto-cost reference-bandwidth <1-4294967>", + "Calculate OSPF interface cost according to bandwidth\n" + "Use reference bandwidth method to assign OSPF cost\n" + "The reference bandwidth in terms of Mbits per second\n") +{ + u_int32_t refbw; + listnode node; + + refbw = strtol (argv[0], NULL, 10); + if (refbw < 1 || refbw > 4294967) + { + vty_out (vty, "reference-bandwidth value is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* If reference bandwidth is changed. */ + if ((refbw * 1000) == ospf_top->ref_bandwidth) + return CMD_SUCCESS; + + ospf_top->ref_bandwidth = refbw * 1000; + vty_out (vty, "%% OSPF: Reference bandwidth is changed.%s", VTY_NEWLINE); + vty_out (vty, " Please ensure reference bandwidth is consistent across all routers%s", VTY_NEWLINE); + + for (node = listhead (ospf_top->iflist); node; nextnode (node)) + ospf_if_recalculate_output_cost (getdata (node)); + + return CMD_SUCCESS; +} + +DEFUN (no_auto_cost_reference_bandwidth, + no_auto_cost_reference_bandwidth_cmd, + "no auto-cost reference-bandwidth", + NO_STR + "Calculate OSPF interface cost according to bandwidth\n" + "Use reference bandwidth method to assign OSPF cost\n") +{ + listnode node; + + if (ospf_top->ref_bandwidth == OSPF_DEFAULT_REF_BANDWIDTH) + return CMD_SUCCESS; + + ospf_top->ref_bandwidth = OSPF_DEFAULT_REF_BANDWIDTH; + vty_out (vty, "%% OSPF: Reference bandwidth is changed.%s", VTY_NEWLINE); + vty_out (vty, " Please ensure reference bandwidth is consistent across all routers%s", VTY_NEWLINE); + + + for (node = listhead (ospf_top->iflist); node; nextnode (node)) + ospf_if_recalculate_output_cost (getdata (node)); + + return CMD_SUCCESS; +} + + +DEFUN (clear_ip_ospf_neighbor, + clear_ip_ospf_neighbor_cmd, + "clear ip ospf neighbor A.B.C.D", + "Reset functions\n" + "IP\n" + "Clear OSPF\n" + "Neighbor list\n" + "Neighbor ID\n") +{ + listnode node; + struct ospf_neighbor *nbr; + struct in_addr router_id; + int ret; + + ret = inet_aton (argv[0], &router_id); + if (!ret) + { + vty_out (vty, "Please specify Neighbor ID by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (node = listhead (ospf_top->oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + + nbr = ospf_nbr_lookup_by_routerid (oi->nbrs, &router_id); + + if (nbr) + { + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); + vty_out (vty, "clear neighbor %s%s", argv[0], VTY_NEWLINE); + break; + } + } + + return CMD_SUCCESS; +} + +char *ospf_abr_type_descr_str[] = +{ + "Unknown", + "Standard (RFC2328)", + "Alternative IBM", + "Alternative Cisco", + "Alternative Shortcut" +}; + +char *ospf_shortcut_mode_descr_str[] = +{ + "Default", + "Enabled", + "Disabled" +}; + + + +void +show_ip_ospf_area (struct vty *vty, struct ospf_area *area) +{ + /* Show Area ID. */ + vty_out (vty, " Area ID: %s", inet_ntoa (area->area_id)); + + /* Show Area type/mode. */ + if (OSPF_IS_AREA_BACKBONE (area)) + vty_out (vty, " (Backbone)%s", VTY_NEWLINE); + else + { + if (area->external_routing == OSPF_AREA_STUB) + vty_out (vty, " (Stub%s%s)", + area->no_summary ? ", no summary" : "", + area->shortcut_configured ? "; " : ""); + +#ifdef HAVE_NSSA + + else + if (area->external_routing == OSPF_AREA_NSSA) + vty_out (vty, " (NSSA%s%s)", + area->no_summary ? ", no summary" : "", + area->shortcut_configured ? "; " : ""); +#endif /* HAVE_NSSA */ + + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, " Shortcutting mode: %s", + ospf_shortcut_mode_descr_str[area->shortcut_configured]); + vty_out (vty, ", S-bit consensus: %s%s", + area->shortcut_capability ? "ok" : "no", VTY_NEWLINE); + } + + /* Show number of interfaces. */ + vty_out (vty, " Number of interfaces in this area: Total: %d, " + "Active: %d%s", listcount (area->oiflist), + area->act_ints, VTY_NEWLINE); + +#ifdef HAVE_NSSA + if (area->external_routing == OSPF_AREA_NSSA) + { + vty_out (vty, " It is an NSSA configuration. %s Elected NSSA/ABR performs type-7/type-5 LSA translation. %s", VTY_NEWLINE, VTY_NEWLINE); + if (! OSPF_IS_ABR) + vty_out (vty, " It is not ABR, therefore not Translator. %s", + VTY_NEWLINE); + else + { + if (area->NSSATranslator) + vty_out (vty, " We are an ABR and the NSSA Elected Translator. %s", VTY_NEWLINE); + else + vty_out (vty, " We are an ABR, but not the NSSA Elected Translator. %s", VTY_NEWLINE); + } + } +#endif /* HAVE_NSSA */ + + /* Show number of fully adjacent neighbors. */ + vty_out (vty, " Number of fully adjacent neighbors in this area:" + " %d%s", area->full_nbrs, VTY_NEWLINE); + + /* Show authentication type. */ + vty_out (vty, " Area has "); + if (area->auth_type == OSPF_AUTH_NULL) + vty_out (vty, "no authentication%s", VTY_NEWLINE); + else if (area->auth_type == OSPF_AUTH_SIMPLE) + vty_out (vty, "simple password authentication%s", VTY_NEWLINE); + else if (area->auth_type == OSPF_AUTH_CRYPTOGRAPHIC) + vty_out (vty, "message digest authentication%s", VTY_NEWLINE); + + if (!OSPF_IS_AREA_BACKBONE (area)) + vty_out (vty, " Number of full virtual adjacencies going through" + " this area: %d%s", area->full_vls, VTY_NEWLINE); + + /* Show SPF calculation times. */ + vty_out (vty, " SPF algorithm executed %d times%s", + area->spf_calculation, VTY_NEWLINE); + + /* Show number of LSA. */ + vty_out (vty, " Number of LSA %ld%s", area->lsdb->total, VTY_NEWLINE); + + vty_out (vty, "%s", VTY_NEWLINE); +} + +DEFUN (show_ip_ospf, + show_ip_ospf_cmd, + "show ip ospf", + SHOW_STR + IP_STR + "OSPF information\n") +{ + listnode node; + struct ospf_area * area; + + /* Check OSPF is enable. */ + if (ospf_top == NULL) + { + vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + /* Show Router ID. */ + vty_out (vty, " OSPF Routing Process, Router ID: %s%s", + inet_ntoa (ospf_top->router_id), + VTY_NEWLINE); + + /* Show capability. */ + vty_out (vty, " Supports only single TOS (TOS0) routes%s", VTY_NEWLINE); + vty_out (vty, " This implementation conforms to RFC2328%s", VTY_NEWLINE); + vty_out (vty, " RFC1583Compatibility flag is %s%s", + CHECK_FLAG (ospf_top->config, OSPF_RFC1583_COMPATIBLE) ? + "enabled" : "disabled", VTY_NEWLINE); +#ifdef HAVE_OPAQUE_LSA + vty_out (vty, " OpaqueCapability flag is %s%s%s", + CHECK_FLAG (ospf_top->config, OSPF_OPAQUE_CAPABLE) ? + "enabled" : "disabled", + IS_OPAQUE_LSA_ORIGINATION_BLOCKED (ospf_top->opaque) ? + " (origination blocked)" : "", + VTY_NEWLINE); +#endif /* HAVE_OPAQUE_LSA */ + + /* Show SPF timers. */ + vty_out (vty, " SPF schedule delay %d secs, Hold time between two SPFs %d secs%s", + ospf_top->spf_delay, ospf_top->spf_holdtime, VTY_NEWLINE); + + /* Show refresh parameters. */ + vty_out (vty, " Refresh timer %d secs%s", + ospf_top->lsa_refresh_interval, VTY_NEWLINE); + + /* Show ABR/ASBR flags. */ + if (CHECK_FLAG (ospf_top->flags, OSPF_FLAG_ABR)) + vty_out (vty, " This router is an ABR, ABR type is: %s%s", + ospf_abr_type_descr_str[ospf_top->abr_type], VTY_NEWLINE); + + if (CHECK_FLAG (ospf_top->flags, OSPF_FLAG_ASBR)) + vty_out (vty, " This router is an ASBR " + "(injecting external routing information)%s", VTY_NEWLINE); + + /* Show Number of AS-external-LSAs. */ + vty_out (vty, " Number of external LSA %ld%s", + ospf_lsdb_count_all (ospf_top->lsdb), VTY_NEWLINE); + + /* Show number of areas attached. */ + vty_out (vty, " Number of areas attached to this router: %d%s%s", + listcount (ospf_top->areas), VTY_NEWLINE, VTY_NEWLINE); + + /* Show each area status. */ + for (node = listhead (ospf_top->areas); node; nextnode (node)) + if ((area = getdata (node)) != NULL) + show_ip_ospf_area (vty, area); + + return CMD_SUCCESS; +} + + +void +show_ip_ospf_interface_sub (struct vty *vty, struct interface *ifp) +{ + struct ospf_neighbor *nbr; + int oi_count; + struct route_node *rn; + char buf[9]; + + oi_count = ospf_oi_count (ifp); + + /* Is interface up? */ + if (if_is_up (ifp)) + vty_out (vty, "%s is up, line protocol is up%s", ifp->name, VTY_NEWLINE); + else + { + vty_out (vty, "%s is down, line protocol is down%s", ifp->name, + VTY_NEWLINE); + + + if (oi_count == 0) + vty_out (vty, " OSPF not enabled on this interface%s", VTY_NEWLINE); + else + vty_out (vty, " OSPF is enabled, but not running on this interface%s", + VTY_NEWLINE); + return; + } + + /* Is interface OSPF enabled? */ + if (oi_count == 0) + { + vty_out (vty, " OSPF not enabled on this interface%s", VTY_NEWLINE); + return; + } + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + struct ospf_interface *oi = rn->info; + + if (oi == NULL) + continue; + + /* Show OSPF interface information. */ + vty_out (vty, " Internet Address %s/%d,", + inet_ntoa (oi->address->u.prefix4), oi->address->prefixlen); + + vty_out (vty, " Area %s%s", ospf_area_desc_string (oi->area), + VTY_NEWLINE); + + vty_out (vty, " Router ID %s, Network Type %s, Cost: %d%s", + inet_ntoa (ospf_top->router_id), ospf_network_type_str[oi->type], + oi->output_cost, VTY_NEWLINE); + + vty_out (vty, " Transmit Delay is %d sec, State %s, Priority %d%s", + OSPF_IF_PARAM (oi,transmit_delay), LOOKUP (ospf_ism_state_msg, oi->state), + PRIORITY (oi), VTY_NEWLINE); + + /* Show DR information. */ + if (DR (oi).s_addr == 0) + vty_out (vty, " No designated router on this network%s", VTY_NEWLINE); + else + { + nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &DR (oi)); + if (nbr == NULL) + vty_out (vty, " No designated router on this network%s", VTY_NEWLINE); + else + { + vty_out (vty, " Designated Router (ID) %s,", + inet_ntoa (nbr->router_id)); + vty_out (vty, " Interface Address %s%s", + inet_ntoa (nbr->address.u.prefix4), VTY_NEWLINE); + } + } + + /* Show BDR information. */ + if (BDR (oi).s_addr == 0) + vty_out (vty, " No backup designated router on this network%s", + VTY_NEWLINE); + else + { + nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &BDR (oi)); + if (nbr == NULL) + vty_out (vty, " No backup designated router on this network%s", + VTY_NEWLINE); + else + { + vty_out (vty, " Backup Designated Router (ID) %s,", + inet_ntoa (nbr->router_id)); + vty_out (vty, " Interface Address %s%s", + inet_ntoa (nbr->address.u.prefix4), VTY_NEWLINE); + } + } + vty_out (vty, " Timer intervals configured,"); + vty_out (vty, " Hello %d, Dead %d, Wait %d, Retransmit %d%s", + OSPF_IF_PARAM (oi, v_hello), OSPF_IF_PARAM (oi, v_wait), + OSPF_IF_PARAM (oi, v_wait), + OSPF_IF_PARAM (oi, retransmit_interval), + VTY_NEWLINE); + + if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_ACTIVE) + vty_out (vty, " Hello due in %s%s", + ospf_timer_dump (oi->t_hello, buf, 9), VTY_NEWLINE); + else /* OSPF_IF_PASSIVE is set */ + vty_out (vty, " No Hellos (Passive interface)%s", VTY_NEWLINE); + + vty_out (vty, " Neighbor Count is %d, Adjacent neighbor count is %d%s", + ospf_nbr_count (oi->nbrs, 0), ospf_nbr_count (oi->nbrs, NSM_Full), + VTY_NEWLINE); + } +} + +DEFUN (show_ip_ospf_interface, + show_ip_ospf_interface_cmd, + "show ip ospf interface [INTERFACE]", + SHOW_STR + IP_STR + "OSPF information\n" + "Interface information\n" + "Interface name\n") +{ + struct interface *ifp; + listnode node; + + /* Show All Interfaces. */ + if (argc == 0) + for (node = listhead (iflist); node; nextnode (node)) + show_ip_ospf_interface_sub (vty, node->data); + /* Interface name is specified. */ + else + { + if ((ifp = if_lookup_by_name (argv[0])) == NULL) + vty_out (vty, "No such interface name%s", VTY_NEWLINE); + else + show_ip_ospf_interface_sub (vty, ifp); + } + + return CMD_SUCCESS; +} + +void +show_ip_ospf_neighbor_sub (struct vty *vty, struct ospf_interface *oi) +{ + struct route_node *rn; + struct ospf_neighbor *nbr; + char msgbuf[16]; + char timebuf[9]; + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info)) + /* Do not show myself. */ + if (nbr != oi->nbr_self) + /* Down state is not shown. */ + if (nbr->state != NSM_Down) + { + ospf_nbr_state_message (nbr, msgbuf, 16); + + if (nbr->state == NSM_Attempt && nbr->router_id.s_addr == 0) + vty_out (vty, "%-15s %3d %-15s %8s ", + "-", nbr->priority, + msgbuf, ospf_timer_dump (nbr->t_inactivity, timebuf, 9)); + else + vty_out (vty, "%-15s %3d %-15s %8s ", + inet_ntoa (nbr->router_id), nbr->priority, + msgbuf, ospf_timer_dump (nbr->t_inactivity, timebuf, 9)); + vty_out (vty, "%-15s ", inet_ntoa (nbr->src)); + vty_out (vty, "%-15s %5ld %5ld %5d%s", + IF_NAME (oi), ospf_ls_retransmit_count (nbr), + ospf_ls_request_count (nbr), ospf_db_summary_count (nbr), + VTY_NEWLINE); + } +} + +DEFUN (show_ip_ospf_neighbor, + show_ip_ospf_neighbor_cmd, + "show ip ospf neighbor", + SHOW_STR + IP_STR + "OSPF information\n" + "Neighbor list\n") +{ + listnode node; + + if (!ospf_top) + { + vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + /* Show All neighbors. */ + vty_out (vty, "%sNeighbor ID Pri State Dead " + "Time Address Interface RXmtL " + "RqstL DBsmL%s", VTY_NEWLINE, VTY_NEWLINE); + + for (node = listhead (ospf_top->oiflist); node; nextnode (node)) + show_ip_ospf_neighbor_sub (vty, getdata (node)); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_ospf_neighbor_all, + show_ip_ospf_neighbor_all_cmd, + "show ip ospf neighbor all", + SHOW_STR + IP_STR + "OSPF information\n" + "Neighbor list\n" + "include down status neighbor\n") +{ + listnode node; + + if (!ospf_top) + { + vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + /* Show All neighbors. */ + vty_out (vty, "%sNeighbor ID Pri State Dead " + "Time Address Interface RXmtL " + "RqstL DBsmL%s", VTY_NEWLINE, VTY_NEWLINE); + + for (node = listhead (ospf_top->oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + listnode nbr_node; + + show_ip_ospf_neighbor_sub (vty, oi); + + /* print Down neighbor status */ + for (nbr_node = listhead (oi->nbr_nbma); nbr_node; nextnode (nbr_node)) + { + struct ospf_nbr_nbma *nbr_nbma; + + nbr_nbma = getdata (nbr_node); + + if (nbr_nbma->nbr == NULL + || nbr_nbma->nbr->state == NSM_Down) + { + vty_out (vty, "%-15s %3d %-15s %8s ", + "-", nbr_nbma->priority, "Down", "-"); + vty_out (vty, "%-15s %-15s %5d %5d %5d%s", + inet_ntoa (nbr_nbma->addr), IF_NAME (oi), + 0, 0, 0, VTY_NEWLINE); + } + } + } + + return CMD_SUCCESS; +} + +DEFUN (show_ip_ospf_neighbor_int, + show_ip_ospf_neighbor_int_cmd, + "show ip ospf neighbor A.B.C.D", + SHOW_STR + IP_STR + "OSPF information\n" + "Neighbor list\n" + "Interface name\n") +{ + struct ospf_interface *oi; + struct in_addr addr; + int ret; + + if (!ospf_top) + { + vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + ret = inet_aton (argv[0], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if ((oi = ospf_if_is_configured (&addr)) == NULL) + vty_out (vty, "No such interface address%s", VTY_NEWLINE); + else + { + vty_out (vty, "%sNeighbor ID Pri State Dead " + "Time Address Interface RXmtL " + "RqstL DBsmL%s", VTY_NEWLINE, VTY_NEWLINE); + show_ip_ospf_neighbor_sub (vty, oi); + } + + return CMD_SUCCESS; +} + +void +show_ip_ospf_nbr_nbma_detail_sub (struct vty *vty, struct ospf_interface *oi, + struct ospf_nbr_nbma *nbr_nbma) +{ + char timebuf[9]; + + /* Show neighbor ID. */ + vty_out (vty, " Neighbor %s,", "-"); + + /* Show interface address. */ + vty_out (vty, " interface address %s%s", + inet_ntoa (nbr_nbma->addr), VTY_NEWLINE); + /* Show Area ID. */ + vty_out (vty, " In the area %s via interface %s%s", + ospf_area_desc_string (oi->area), IF_NAME (oi), VTY_NEWLINE); + /* Show neighbor priority and state. */ + vty_out (vty, " Neighbor priority is %d, State is %s,", + nbr_nbma->priority, "Down"); + /* Show state changes. */ + vty_out (vty, " %d state changes%s", nbr_nbma->state_change, VTY_NEWLINE); + + /* Show PollInterval */ + vty_out (vty, " Poll interval %d%s", nbr_nbma->v_poll, VTY_NEWLINE); + + /* Show poll-interval timer. */ + vty_out (vty, " Poll timer due in %s%s", + ospf_timer_dump (nbr_nbma->t_poll, timebuf, 9), VTY_NEWLINE); + + /* Show poll-interval timer thread. */ + vty_out (vty, " Thread Poll Timer %s%s", + nbr_nbma->t_poll != NULL ? "on" : "off", VTY_NEWLINE); +} + +void +show_ip_ospf_neighbor_detail_sub (struct vty *vty, struct ospf_interface *oi, + struct ospf_neighbor *nbr) +{ + char timebuf[9]; + + /* Show neighbor ID. */ + if (nbr->state == NSM_Attempt && nbr->router_id.s_addr == 0) + vty_out (vty, " Neighbor %s,", "-"); + else + vty_out (vty, " Neighbor %s,", inet_ntoa (nbr->router_id)); + + /* Show interface address. */ + vty_out (vty, " interface address %s%s", + inet_ntoa (nbr->address.u.prefix4), VTY_NEWLINE); + /* Show Area ID. */ + vty_out (vty, " In the area %s via interface %s%s", + ospf_area_desc_string (oi->area), oi->ifp->name, VTY_NEWLINE); + /* Show neighbor priority and state. */ + vty_out (vty, " Neighbor priority is %d, State is %s,", + nbr->priority, LOOKUP (ospf_nsm_state_msg, nbr->state)); + /* Show state changes. */ + vty_out (vty, " %d state changes%s", nbr->state_change, VTY_NEWLINE); + + /* Show Designated Rotuer ID. */ + vty_out (vty, " DR is %s,", inet_ntoa (nbr->d_router)); + /* Show Backup Designated Rotuer ID. */ + vty_out (vty, " BDR is %s%s", inet_ntoa (nbr->bd_router), VTY_NEWLINE); + /* Show options. */ + vty_out (vty, " Options %d %s%s", nbr->options, + ospf_options_dump (nbr->options), VTY_NEWLINE); + /* Show Router Dead interval timer. */ + vty_out (vty, " Dead timer due in %s%s", + ospf_timer_dump (nbr->t_inactivity, timebuf, 9), VTY_NEWLINE); + /* Show Database Summary list. */ + vty_out (vty, " Database Summary List %d%s", + ospf_db_summary_count (nbr), VTY_NEWLINE); + /* Show Link State Request list. */ + vty_out (vty, " Link State Request List %ld%s", + ospf_ls_request_count (nbr), VTY_NEWLINE); + /* Show Link State Retransmission list. */ + vty_out (vty, " Link State Retransmission List %ld%s", + ospf_ls_retransmit_count (nbr), VTY_NEWLINE); + /* Show inactivity timer thread. */ + vty_out (vty, " Thread Inactivity Timer %s%s", + nbr->t_inactivity != NULL ? "on" : "off", VTY_NEWLINE); + /* Show Database Description retransmission thread. */ + vty_out (vty, " Thread Database Description Retransmision %s%s", + nbr->t_db_desc != NULL ? "on" : "off", VTY_NEWLINE); + /* Show Link State Request Retransmission thread. */ + vty_out (vty, " Thread Link State Request Retransmission %s%s", + nbr->t_ls_req != NULL ? "on" : "off", VTY_NEWLINE); + /* Show Link State Update Retransmission thread. */ + vty_out (vty, " Thread Link State Update Retransmission %s%s%s", + nbr->t_ls_upd != NULL ? "on" : "off", VTY_NEWLINE, VTY_NEWLINE); +} + +DEFUN (show_ip_ospf_neighbor_id, + show_ip_ospf_neighbor_id_cmd, + "show ip ospf neighbor A.B.C.D", + SHOW_STR + IP_STR + "OSPF information\n" + "Neighbor list\n" + "Neighbor ID\n") +{ + listnode node; + struct ospf_neighbor *nbr; + struct in_addr router_id; + int ret; + + ret = inet_aton (argv[0], &router_id); + if (!ret) + { + vty_out (vty, "Please specify Neighbor ID by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (node = listhead (ospf_top->oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + + if ((nbr = ospf_nbr_lookup_by_routerid (oi->nbrs, &router_id))) + { + show_ip_ospf_neighbor_detail_sub (vty, oi, nbr); + return CMD_SUCCESS; + } + } + + /* Nothing to show. */ + return CMD_SUCCESS; +} + +DEFUN (show_ip_ospf_neighbor_detail, + show_ip_ospf_neighbor_detail_cmd, + "show ip ospf neighbor detail", + SHOW_STR + IP_STR + "OSPF information\n" + "Neighbor list\n" + "detail of all neighbors\n") +{ + listnode node; + + if (!ospf_top) + return CMD_SUCCESS; + + for (node = listhead (ospf_top->oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + struct route_node *rn; + struct ospf_neighbor *nbr; + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info)) + if (nbr != oi->nbr_self) + if (nbr->state != NSM_Down) + show_ip_ospf_neighbor_detail_sub (vty, oi, nbr); + } + + return CMD_SUCCESS; +} + +DEFUN (show_ip_ospf_neighbor_detail_all, + show_ip_ospf_neighbor_detail_all_cmd, + "show ip ospf neighbor detail all", + SHOW_STR + IP_STR + "OSPF information\n" + "Neighbor list\n" + "detail of all neighbors\n" + "include down status neighbor\n") +{ + listnode node; + + if (!ospf_top) + return CMD_SUCCESS; + + for (node = listhead (ospf_top->oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + struct route_node *rn; + struct ospf_neighbor *nbr; + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info)) + if (nbr != oi->nbr_self) + if (oi->type == OSPF_IFTYPE_NBMA && nbr->state != NSM_Down) + show_ip_ospf_neighbor_detail_sub (vty, oi, rn->info); + + if (oi->type == OSPF_IFTYPE_NBMA) + { + listnode nd; + + for (nd = listhead (oi->nbr_nbma); nd; nextnode (nd)) + { + struct ospf_nbr_nbma *nbr_nbma = getdata (nd); + if (nbr_nbma->nbr == NULL + || nbr_nbma->nbr->state == NSM_Down) + show_ip_ospf_nbr_nbma_detail_sub (vty, oi, nbr_nbma); + } + } + } + + return CMD_SUCCESS; +} + +DEFUN (show_ip_ospf_neighbor_int_detail, + show_ip_ospf_neighbor_int_detail_cmd, + "show ip ospf neighbor A.B.C.D detail", + SHOW_STR + IP_STR + "OSPF information\n" + "Neighbor list\n" + "Interface address\n" + "detail of all neighbors") +{ + struct ospf_interface *oi; + struct in_addr addr; + int ret; + + ret = inet_aton (argv[0], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if ((oi = ospf_if_is_configured (&addr)) == NULL) + vty_out (vty, "No such interface address%s", VTY_NEWLINE); + else + { + struct route_node *rn; + struct ospf_neighbor *nbr; + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info)) + if (nbr != oi->nbr_self) + if (nbr->state != NSM_Down) + show_ip_ospf_neighbor_detail_sub (vty, oi, nbr); + } + + return CMD_SUCCESS; +} + + +/* Show functions */ +int +show_lsa_summary (struct ospf_lsa *lsa, void *v, int self) +{ + struct vty *vty = (struct vty *) v; + struct router_lsa *rl; + struct summary_lsa *sl; + struct as_external_lsa *asel; + struct prefix_ipv4 p; + + if (lsa != NULL) + /* If self option is set, check LSA self flag. */ + if (self == 0 || IS_LSA_SELF (lsa)) + { + /* LSA common part show. */ + vty_out (vty, "%-15s ", inet_ntoa (lsa->data->id)); + vty_out (vty, "%-15s %4d 0x%08lx 0x%04x", + inet_ntoa (lsa->data->adv_router), LS_AGE (lsa), + (u_long)ntohl (lsa->data->ls_seqnum), ntohs (lsa->data->checksum)); + /* LSA specific part show. */ + switch (lsa->data->type) + { + case OSPF_ROUTER_LSA: + rl = (struct router_lsa *) lsa->data; + vty_out (vty, " %-d", ntohs (rl->links)); + break; + case OSPF_SUMMARY_LSA: + sl = (struct summary_lsa *) lsa->data; + + p.family = AF_INET; + p.prefix = sl->header.id; + p.prefixlen = ip_masklen (sl->mask); + apply_mask_ipv4 (&p); + + vty_out (vty, " %s/%d", inet_ntoa (p.prefix), p.prefixlen); + break; + case OSPF_AS_EXTERNAL_LSA: + asel = (struct as_external_lsa *) lsa->data; + + p.family = AF_INET; + p.prefix = asel->header.id; + p.prefixlen = ip_masklen (asel->mask); + apply_mask_ipv4 (&p); + + vty_out (vty, " %s %s/%d [0x%lx]", + IS_EXTERNAL_METRIC (asel->e[0].tos) ? "E2" : "E1", + inet_ntoa (p.prefix), p.prefixlen, + (u_long)ntohl (asel->e[0].route_tag)); + break; + case OSPF_NETWORK_LSA: + case OSPF_ASBR_SUMMARY_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + default: + break; + } + vty_out (vty, VTY_NEWLINE); + } + + return 0; +} + +char *show_database_desc[] = +{ + "unknown", + "Router Link States", + "Net Link States", + "Summary Link States", + "ASBR-Summary Link States", + "AS External Link States", +#if defined (HAVE_NSSA) || defined (HAVE_OPAQUE_LSA) + "Group Membership LSA", + "NSSA-external Link States", +#endif /* HAVE_NSSA */ +#ifdef HAVE_OPAQUE_LSA + "Type-8 LSA", + "Link-Local Opaque-LSA", + "Area-Local Opaque-LSA", + "AS-external Opaque-LSA", +#endif /* HAVE_OPAQUE_LSA */ +}; + +#define SHOW_OSPF_COMMON_HEADER \ + "Link ID ADV Router Age Seq# CkSum" + +char *show_database_header[] = +{ + "", + "Link ID ADV Router Age Seq# CkSum Link count", + "Link ID ADV Router Age Seq# CkSum", + "Link ID ADV Router Age Seq# CkSum Route", + "Link ID ADV Router Age Seq# CkSum", + "Link ID ADV Router Age Seq# CkSum Route", +#ifdef HAVE_NSSA + " --- header for Group Member ----", + "Link ID ADV Router Age Seq# CkSum Route", +#endif /* HAVE_NSSA */ +#ifdef HAVE_OPAQUE_LSA +#ifndef HAVE_NSSA + " --- type-6 ---", + " --- type-7 ---", +#endif /* HAVE_NSSA */ + " --- type-8 ---", + "Opaque-Type/Id ADV Router Age Seq# CkSum", + "Opaque-Type/Id ADV Router Age Seq# CkSum", + "Opaque-Type/Id ADV Router Age Seq# CkSum", +#endif /* HAVE_OPAQUE_LSA */ +}; + +void +show_ip_ospf_database_header (struct vty *vty, struct ospf_lsa *lsa) +{ + struct router_lsa *rlsa = (struct router_lsa*) lsa->data; + + vty_out (vty, " LS age: %d%s", LS_AGE (lsa), VTY_NEWLINE); + vty_out (vty, " Options: %d%s", lsa->data->options, VTY_NEWLINE); + + if (lsa->data->type == OSPF_ROUTER_LSA) + { + vty_out (vty, " Flags: 0x%x" , rlsa->flags); + + if (rlsa->flags) + vty_out (vty, " :%s%s%s%s", + IS_ROUTER_LSA_BORDER (rlsa) ? " ABR" : "", + IS_ROUTER_LSA_EXTERNAL (rlsa) ? " ASBR" : "", + IS_ROUTER_LSA_VIRTUAL (rlsa) ? " VL-endpoint" : "", + IS_ROUTER_LSA_SHORTCUT (rlsa) ? " Shortcut" : ""); + + vty_out (vty, "%s", VTY_NEWLINE); + } + vty_out (vty, " LS Type: %s%s", + LOOKUP (ospf_lsa_type_msg, lsa->data->type), VTY_NEWLINE); + vty_out (vty, " Link State ID: %s %s%s", inet_ntoa (lsa->data->id), + LOOKUP (ospf_link_state_id_type_msg, lsa->data->type), VTY_NEWLINE); + vty_out (vty, " Advertising Router: %s%s", + inet_ntoa (lsa->data->adv_router), VTY_NEWLINE); + vty_out (vty, " LS Seq Number: %08lx%s", (u_long)ntohl (lsa->data->ls_seqnum), + VTY_NEWLINE); + vty_out (vty, " Checksum: 0x%04x%s", ntohs (lsa->data->checksum), + VTY_NEWLINE); + vty_out (vty, " Length: %d%s", ntohs (lsa->data->length), VTY_NEWLINE); +} + +char *link_type_desc[] = +{ + "(null)", + "another Router (point-to-point)", + "a Transit Network", + "Stub Network", + "a Virtual Link", +}; + +char *link_id_desc[] = +{ + "(null)", + "Neighboring Router ID", + "Designated Router address", + "Network/subnet number", + "Neighboring Router ID", +}; + +char *link_data_desc[] = +{ + "(null)", + "Router Interface address", + "Router Interface address", + "Network Mask", + "Router Interface address", +}; + +/* Show router-LSA each Link information. */ +void +show_ip_ospf_database_router_links (struct vty *vty, + struct router_lsa *rl) +{ + int len, i, type; + + len = ntohs (rl->header.length) - 4; + for (i = 0; i < ntohs (rl->links) && len > 0; len -= 12, i++) + { + type = rl->link[i].type; + + vty_out (vty, " Link connected to: %s%s", + link_type_desc[type], VTY_NEWLINE); + vty_out (vty, " (Link ID) %s: %s%s", link_id_desc[type], + inet_ntoa (rl->link[i].link_id), VTY_NEWLINE); + vty_out (vty, " (Link Data) %s: %s%s", link_data_desc[type], + inet_ntoa (rl->link[i].link_data), VTY_NEWLINE); + vty_out (vty, " Number of TOS metrics: 0%s", VTY_NEWLINE); + vty_out (vty, " TOS 0 Metric: %d%s", + ntohs (rl->link[i].metric), VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + } +} + +/* Show router-LSA detail information. */ +int +show_router_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) +{ + if (lsa != NULL) + { + struct router_lsa *rl = (struct router_lsa *) lsa->data; + + show_ip_ospf_database_header (vty, lsa); + + vty_out (vty, " Number of Links: %d%s%s", ntohs (rl->links), + VTY_NEWLINE, VTY_NEWLINE); + + show_ip_ospf_database_router_links (vty, rl); + } + + return 0; +} + +/* Show network-LSA detail information. */ +int +show_network_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) +{ + int length, i; + + if (lsa != NULL) + { + struct network_lsa *nl = (struct network_lsa *) lsa->data; + + show_ip_ospf_database_header (vty, lsa); + + vty_out (vty, " Network Mask: /%d%s", + ip_masklen (nl->mask), VTY_NEWLINE); + + length = ntohs (lsa->data->length) - OSPF_LSA_HEADER_SIZE - 4; + + for (i = 0; length > 0; i++, length -= 4) + vty_out (vty, " Attached Router: %s%s", + inet_ntoa (nl->routers[i]), VTY_NEWLINE); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + return 0; +} + +/* Show summary-LSA detail information. */ +int +show_summary_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) +{ + if (lsa != NULL) + { + struct summary_lsa *sl = (struct summary_lsa *) lsa->data; + + show_ip_ospf_database_header (vty, lsa); + + vty_out (vty, " Network Mask: /%d%s", ip_masklen (sl->mask), + VTY_NEWLINE); + vty_out (vty, " TOS: 0 Metric: %d%s", GET_METRIC (sl->metric), + VTY_NEWLINE); + } + + return 0; +} + +/* Show summary-ASBR-LSA detail information. */ +int +show_summary_asbr_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) +{ + if (lsa != NULL) + { + struct summary_lsa *sl = (struct summary_lsa *) lsa->data; + + show_ip_ospf_database_header (vty, lsa); + + vty_out (vty, " Network Mask: /%d%s", + ip_masklen (sl->mask), VTY_NEWLINE); + vty_out (vty, " TOS: 0 Metric: %d%s", GET_METRIC (sl->metric), + VTY_NEWLINE); + } + + return 0; +} + +/* Show AS-external-LSA detail information. */ +int +show_as_external_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) +{ + if (lsa != NULL) + { + struct as_external_lsa *al = (struct as_external_lsa *) lsa->data; + + show_ip_ospf_database_header (vty, lsa); + + vty_out (vty, " Network Mask: /%d%s", + ip_masklen (al->mask), VTY_NEWLINE); + vty_out (vty, " Metric Type: %s%s", + IS_EXTERNAL_METRIC (al->e[0].tos) ? + "2 (Larger than any link state path)" : "1", VTY_NEWLINE); + vty_out (vty, " TOS: 0%s", VTY_NEWLINE); + vty_out (vty, " Metric: %d%s", + GET_METRIC (al->e[0].metric), VTY_NEWLINE); + vty_out (vty, " Forward Address: %s%s", + inet_ntoa (al->e[0].fwd_addr), VTY_NEWLINE); + + vty_out (vty, " External Route Tag: %lu%s%s", + (u_long)ntohl (al->e[0].route_tag), VTY_NEWLINE, VTY_NEWLINE); + } + + return 0; +} + +#ifdef HAVE_NSSA +int +show_as_external_lsa_stdvty (struct ospf_lsa *lsa) +{ + struct as_external_lsa *al = (struct as_external_lsa *) lsa->data; + + /* show_ip_ospf_database_header (vty, lsa); */ + + zlog_info( " Network Mask: /%d%s", + ip_masklen (al->mask), "\n"); + zlog_info( " Metric Type: %s%s", + IS_EXTERNAL_METRIC (al->e[0].tos) ? + "2 (Larger than any link state path)" : "1", "\n"); + zlog_info( " TOS: 0%s", "\n"); + zlog_info( " Metric: %d%s", + GET_METRIC (al->e[0].metric), "\n"); + zlog_info( " Forward Address: %s%s", + inet_ntoa (al->e[0].fwd_addr), "\n"); + + zlog_info( " External Route Tag: %u%s%s", + ntohl (al->e[0].route_tag), "\n", "\n"); + + return 0; +} + +/* Show AS-NSSA-LSA detail information. */ +int +show_as_nssa_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) +{ + if (lsa != NULL) + { + struct as_external_lsa *al = (struct as_external_lsa *) lsa->data; + + show_ip_ospf_database_header (vty, lsa); + + vty_out (vty, " Network Mask: /%d%s", + ip_masklen (al->mask), VTY_NEWLINE); + vty_out (vty, " Metric Type: %s%s", + IS_EXTERNAL_METRIC (al->e[0].tos) ? + "2 (Larger than any link state path)" : "1", VTY_NEWLINE); + vty_out (vty, " TOS: 0%s", VTY_NEWLINE); + vty_out (vty, " Metric: %d%s", + GET_METRIC (al->e[0].metric), VTY_NEWLINE); + vty_out (vty, " NSSA: Forward Address: %s%s", + inet_ntoa (al->e[0].fwd_addr), VTY_NEWLINE); + + vty_out (vty, " External Route Tag: %u%s%s", + ntohl (al->e[0].route_tag), VTY_NEWLINE, VTY_NEWLINE); + } + + return 0; +} + +#endif /* HAVE_NSSA */ + +int +show_func_dummy (struct vty *vty, struct ospf_lsa *lsa) +{ + return 0; +} + +#ifdef HAVE_OPAQUE_LSA +int +show_opaque_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) +{ + if (lsa != NULL) + { + show_ip_ospf_database_header (vty, lsa); + show_opaque_info_detail (vty, lsa); + + vty_out (vty, "%s", VTY_NEWLINE); + } + return 0; +} +#endif /* HAVE_OPAQUE_LSA */ + +int (*show_function[])(struct vty *, struct ospf_lsa *) = +{ + NULL, + show_router_lsa_detail, + show_network_lsa_detail, + show_summary_lsa_detail, + show_summary_asbr_lsa_detail, + show_as_external_lsa_detail, +#ifdef HAVE_NSSA + show_func_dummy, + show_as_nssa_lsa_detail, /* almost same as external */ +#endif /* HAVE_NSSA */ +#ifdef HAVE_OPAQUE_LSA +#ifndef HAVE_NSSA + show_func_dummy, + show_func_dummy, +#endif /* HAVE_NSSA */ + NULL, /* type-8 */ + show_opaque_lsa_detail, + show_opaque_lsa_detail, + show_opaque_lsa_detail, +#endif /* HAVE_OPAQUE_LSA */ +}; + +void +show_lsa_prefix_set (struct vty *vty, struct prefix_ls *lp, struct in_addr *id, + struct in_addr *adv_router) +{ + memset (lp, 0, sizeof (struct prefix_ls)); + lp->family = 0; + if (id == NULL) + lp->prefixlen = 0; + else if (adv_router == NULL) + { + lp->prefixlen = 32; + lp->id = *id; + } + else + { + lp->prefixlen = 64; + lp->id = *id; + lp->adv_router = *adv_router; + } +} + +void +show_lsa_detail_proc (struct vty *vty, struct route_table *rt, + struct in_addr *id, struct in_addr *adv_router) +{ + struct prefix_ls lp; + struct route_node *rn, *start; + struct ospf_lsa *lsa; + + show_lsa_prefix_set (vty, &lp, id, adv_router); + start = route_node_get (rt, (struct prefix *) &lp); + if (start) + { + route_lock_node (start); + for (rn = start; rn; rn = route_next_until (rn, start)) + if ((lsa = rn->info)) + { +#ifdef HAVE_NSSA + /* Stay away from any Local Translated Type-7 LSAs */ + if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) + continue; +#endif /* HAVE_NSSA */ + + if (show_function[lsa->data->type] != NULL) + show_function[lsa->data->type] (vty, lsa); + } + route_unlock_node (start); + } +} + +/* Show detail LSA information + -- if id is NULL then show all LSAs. */ +void +show_lsa_detail (struct vty *vty, int type, + struct in_addr *id, struct in_addr *adv_router) +{ + listnode node; + + switch (type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + vty_out (vty, " %s %s%s", + show_database_desc[type], + VTY_NEWLINE, VTY_NEWLINE); + show_lsa_detail_proc (vty, AS_LSDB (ospf_top, type), id, adv_router); + break; + default: + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + struct ospf_area *area = node->data; + vty_out (vty, "%s %s (Area %s)%s%s", + VTY_NEWLINE, show_database_desc[type], + ospf_area_desc_string (area), VTY_NEWLINE, VTY_NEWLINE); + show_lsa_detail_proc (vty, AREA_LSDB (area, type), id, adv_router); + } + break; + } +} + +void +show_lsa_detail_adv_router_proc (struct vty *vty, struct route_table *rt, + struct in_addr *adv_router) +{ + struct route_node *rn; + struct ospf_lsa *lsa; + + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((lsa = rn->info)) + if (IPV4_ADDR_SAME (adv_router, &lsa->data->adv_router)) + { +#ifdef HAVE_NSSA + if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) + continue; +#endif /* HAVE_NSSA */ + if (show_function[lsa->data->type] != NULL) + show_function[lsa->data->type] (vty, lsa); + } +} + +/* Show detail LSA information. */ +void +show_lsa_detail_adv_router (struct vty *vty, int type, + struct in_addr *adv_router) +{ + listnode node; + + switch (type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + vty_out (vty, " %s %s%s", + show_database_desc[type], + VTY_NEWLINE, VTY_NEWLINE); + show_lsa_detail_adv_router_proc (vty, AS_LSDB (ospf_top, type), + adv_router); + break; + default: + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + struct ospf_area *area = node->data; + vty_out (vty, "%s %s (Area %s)%s%s", + VTY_NEWLINE, show_database_desc[type], + ospf_area_desc_string (area), VTY_NEWLINE, VTY_NEWLINE); + show_lsa_detail_adv_router_proc (vty, AREA_LSDB (area, type), + adv_router); + } + break; + } +} + +void +show_ip_ospf_database_summary (struct vty *vty, int self) +{ + listnode node; + int type; + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + struct ospf_area *area = node->data; + for (type = OSPF_MIN_LSA; type < OSPF_MAX_LSA; type++) + { + switch (type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + continue; + default: + break; + } + if (ospf_lsdb_count_self (area->lsdb, type) > 0 || + (!self && ospf_lsdb_count (area->lsdb, type) > 0)) + { + vty_out (vty, " %s (Area %s)%s%s", + show_database_desc[type], + ospf_area_desc_string (area), + VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, "%s%s", show_database_header[type], VTY_NEWLINE); + + foreach_lsa (AREA_LSDB (area, type), vty, self, show_lsa_summary); + + vty_out (vty, "%s", VTY_NEWLINE); + } + } + } + + for (type = OSPF_MIN_LSA; type < OSPF_MAX_LSA; type++) + { + switch (type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + break;; + default: + continue; + } + if (ospf_lsdb_count_self (ospf_top->lsdb, type) || + (!self && ospf_lsdb_count (ospf_top->lsdb, type))) + { + vty_out (vty, " %s%s%s", + show_database_desc[type], + VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, "%s%s", show_database_header[type], + VTY_NEWLINE); + foreach_lsa (AS_LSDB (ospf_top, type), vty, self, show_lsa_summary); + vty_out (vty, "%s", VTY_NEWLINE); + } + } + + vty_out (vty, "%s", VTY_NEWLINE); +} + +void +show_ip_ospf_database_maxage (struct vty *vty) +{ + listnode node; + struct ospf_lsa *lsa; + + vty_out (vty, "%s MaxAge Link States:%s%s", + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + + for (node = listhead (ospf_top->maxage_lsa); node; nextnode (node)) + if ((lsa = node->data) != NULL) + { + vty_out (vty, "Link type: %d%s", lsa->data->type, VTY_NEWLINE); + vty_out (vty, "Link State ID: %s%s", + inet_ntoa (lsa->data->id), VTY_NEWLINE); + vty_out (vty, "Advertising Router: %s%s", + inet_ntoa (lsa->data->adv_router), VTY_NEWLINE); + vty_out (vty, "LSA lock count: %d%s", lsa->lock, VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + } +} + +#ifdef HAVE_NSSA +#define OSPF_LSA_TYPE_NSSA_DESC "NSSA external link state\n" +#define OSPF_LSA_TYPE_NSSA_CMD_STR "|nssa-external" +#else /* HAVE_NSSA */ +#define OSPF_LSA_TYPE_NSSA_DESC "" +#define OSPF_LSA_TYPE_NSSA_CMD_STR "" +#endif /* HAVE_NSSA */ + +#ifdef HAVE_OPAQUE_LSA +#define OSPF_LSA_TYPE_OPAQUE_LINK_DESC "Link local Opaque-LSA\n" +#define OSPF_LSA_TYPE_OPAQUE_AREA_DESC "Link area Opaque-LSA\n" +#define OSPF_LSA_TYPE_OPAQUE_AS_DESC "Link AS Opaque-LSA\n" +#define OSPF_LSA_TYPE_OPAQUE_CMD_STR "|opaque-link|opaque-area|opaque-as" +#else /* HAVE_OPAQUE_LSA */ +#define OSPF_LSA_TYPE_OPAQUE_LINK_DESC "" +#define OSPF_LSA_TYPE_OPAQUE_AREA_DESC "" +#define OSPF_LSA_TYPE_OPAQUE_AS_DESC "" +#define OSPF_LSA_TYPE_OPAQUE_CMD_STR "" +#endif /* HAVE_OPAQUE_LSA */ + +#define OSPF_LSA_TYPES_CMD_STR \ + "asbr-summary|external|network|router|summary" \ + OSPF_LSA_TYPE_NSSA_CMD_STR \ + OSPF_LSA_TYPE_OPAQUE_CMD_STR + +#define OSPF_LSA_TYPES_DESC \ + "ASBR summary link states\n" \ + "External link states\n" \ + "Network link states\n" \ + "Router link states\n" \ + "Network summary link states\n" \ + OSPF_LSA_TYPE_NSSA_DESC \ + OSPF_LSA_TYPE_OPAQUE_LINK_DESC \ + OSPF_LSA_TYPE_OPAQUE_AREA_DESC \ + OSPF_LSA_TYPE_OPAQUE_AS_DESC + +DEFUN (show_ip_ospf_database, + show_ip_ospf_database_cmd, + "show ip ospf database", + SHOW_STR + IP_STR + "OSPF information\n" + "Database summary\n") +{ + int type, ret; + struct in_addr id, adv_router; + + if (ospf_top == NULL) + return CMD_SUCCESS; + + vty_out (vty, "%s OSPF Router with ID (%s)%s%s", VTY_NEWLINE, + inet_ntoa (ospf_top->router_id), VTY_NEWLINE, VTY_NEWLINE); + + /* Show all LSA. */ + if (argc == 0) + { + show_ip_ospf_database_summary (vty, 0); + return CMD_SUCCESS; + } + + /* Set database type to show. */ + if (strncmp (argv[0], "r", 1) == 0) + type = OSPF_ROUTER_LSA; + else if (strncmp (argv[0], "ne", 2) == 0) + type = OSPF_NETWORK_LSA; +#ifdef HAVE_NSSA + else if (strncmp (argv[0], "ns", 2) == 0) + type = OSPF_AS_NSSA_LSA; +#endif /* HAVE_NSSA */ + else if (strncmp (argv[0], "su", 2) == 0) + type = OSPF_SUMMARY_LSA; + else if (strncmp (argv[0], "a", 1) == 0) + type = OSPF_ASBR_SUMMARY_LSA; + else if (strncmp (argv[0], "e", 1) == 0) + type = OSPF_AS_EXTERNAL_LSA; + else if (strncmp (argv[0], "se", 2) == 0) + { + show_ip_ospf_database_summary (vty, 1); + return CMD_SUCCESS; + } + else if (strncmp (argv[0], "m", 1) == 0) + { + show_ip_ospf_database_maxage (vty); + return CMD_SUCCESS; + } +#ifdef HAVE_OPAQUE_LSA + else if (strncmp (argv[0], "opaque-l", 8) == 0) + type = OSPF_OPAQUE_LINK_LSA; + else if (strncmp (argv[0], "opaque-ar", 9) == 0) + type = OSPF_OPAQUE_AREA_LSA; + else if (strncmp (argv[0], "opaque-as", 9) == 0) + type = OSPF_OPAQUE_AS_LSA; +#endif /* HAVE_OPAQUE_LSA */ + else + return CMD_WARNING; + + /* `show ip ospf database LSA'. */ + if (argc == 1) + show_lsa_detail (vty, type, NULL, NULL); + else if (argc >= 2) + { + ret = inet_aton (argv[1], &id); + if (!ret) + return CMD_WARNING; + + /* `show ip ospf database LSA ID'. */ + if (argc == 2) + show_lsa_detail (vty, type, &id, NULL); + /* `show ip ospf database LSA ID adv-router ADV_ROUTER'. */ + else if (argc == 3) + { + if (strncmp (argv[2], "s", 1) == 0) + adv_router = ospf_top->router_id; + else + { + ret = inet_aton (argv[2], &adv_router); + if (!ret) + return CMD_WARNING; + } + show_lsa_detail (vty, type, &id, &adv_router); + } + } + + return CMD_SUCCESS; +} + +ALIAS (show_ip_ospf_database, + show_ip_ospf_database_type_cmd, + "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR "|max-age|self-originate)", + SHOW_STR + IP_STR + "OSPF information\n" + "Database summary\n" + OSPF_LSA_TYPES_DESC + "LSAs in MaxAge list\n" + "Self-originated link states\n") + +ALIAS (show_ip_ospf_database, + show_ip_ospf_database_type_id_cmd, + "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") A.B.C.D", + SHOW_STR + IP_STR + "OSPF information\n" + "Database summary\n" + OSPF_LSA_TYPES_DESC + "Link State ID (as an IP address)\n") + +ALIAS (show_ip_ospf_database, + show_ip_ospf_database_type_id_adv_router_cmd, + "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") A.B.C.D adv-router A.B.C.D", + SHOW_STR + IP_STR + "OSPF information\n" + "Database summary\n" + OSPF_LSA_TYPES_DESC + "Link State ID (as an IP address)\n" + "Advertising Router link states\n" + "Advertising Router (as an IP address)\n") + +ALIAS (show_ip_ospf_database, + show_ip_ospf_database_type_id_self_cmd, + "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") A.B.C.D (self-originate|)", + SHOW_STR + IP_STR + "OSPF information\n" + "Database summary\n" + OSPF_LSA_TYPES_DESC + "Link State ID (as an IP address)\n" + "Self-originated link states\n" + "\n") + +DEFUN (show_ip_ospf_database_type_adv_router, + show_ip_ospf_database_type_adv_router_cmd, + "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") adv-router A.B.C.D", + SHOW_STR + IP_STR + "OSPF information\n" + "Database summary\n" + OSPF_LSA_TYPES_DESC + "Advertising Router link states\n" + "Advertising Router (as an IP address)\n") +{ + int type, ret; + struct in_addr adv_router; + + if (ospf_top == NULL) + return CMD_SUCCESS; + + vty_out (vty, "%s OSPF Router with ID (%s)%s%s", VTY_NEWLINE, + inet_ntoa (ospf_top->router_id), VTY_NEWLINE, VTY_NEWLINE); + + if (argc != 2) + return CMD_WARNING; + + /* Set database type to show. */ + if (strncmp (argv[0], "r", 1) == 0) + type = OSPF_ROUTER_LSA; + else if (strncmp (argv[0], "ne", 2) == 0) + type = OSPF_NETWORK_LSA; +#ifdef HAVE_NSSA + else if (strncmp (argv[0], "ns", 2) == 0) + type = OSPF_AS_NSSA_LSA; +#endif /* HAVE_NSSA */ + else if (strncmp (argv[0], "s", 1) == 0) + type = OSPF_SUMMARY_LSA; + else if (strncmp (argv[0], "a", 1) == 0) + type = OSPF_ASBR_SUMMARY_LSA; + else if (strncmp (argv[0], "e", 1) == 0) + type = OSPF_AS_EXTERNAL_LSA; +#ifdef HAVE_OPAQUE_LSA + else if (strncmp (argv[0], "opaque-l", 8) == 0) + type = OSPF_OPAQUE_LINK_LSA; + else if (strncmp (argv[0], "opaque-ar", 9) == 0) + type = OSPF_OPAQUE_AREA_LSA; + else if (strncmp (argv[0], "opaque-as", 9) == 0) + type = OSPF_OPAQUE_AS_LSA; +#endif /* HAVE_OPAQUE_LSA */ + else + return CMD_WARNING; + + /* `show ip ospf database LSA adv-router ADV_ROUTER'. */ + if (strncmp (argv[1], "s", 1) == 0) + adv_router = ospf_top->router_id; + else + { + ret = inet_aton (argv[1], &adv_router); + if (!ret) + return CMD_WARNING; + } + + show_lsa_detail_adv_router (vty, type, &adv_router); + + return CMD_SUCCESS; +} + +ALIAS (show_ip_ospf_database_type_adv_router, + show_ip_ospf_database_type_self_cmd, + "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") (self-originate|)", + SHOW_STR + IP_STR + "OSPF information\n" + "Database summary\n" + OSPF_LSA_TYPES_DESC + "Self-originated link states\n") + + +DEFUN (ip_ospf_authentication_args, + ip_ospf_authentication_args_addr_cmd, + "ip ospf authentication (null|message-digest) A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Enable authentication on this interface\n" + "Use null authentication\n" + "Use message-digest authentication\n" + "Address of interface") +{ + struct interface *ifp; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + /* Handle null authentication */ + if ( argv[0][0] == 'n' ) + { + SET_IF_PARAM (params, auth_type); + params->auth_type = OSPF_AUTH_NULL; + return CMD_SUCCESS; + } + + /* Handle message-digest authentication */ + if ( argv[0][0] == 'm' ) + { + SET_IF_PARAM (params, auth_type); + params->auth_type = OSPF_AUTH_CRYPTOGRAPHIC; + return CMD_SUCCESS; + } + + vty_out (vty, "You shouldn't get here!%s", VTY_NEWLINE); + return CMD_WARNING; +} + +ALIAS (ip_ospf_authentication_args, + ip_ospf_authentication_args_cmd, + "ip ospf authentication (null|message-digest)", + "IP Information\n" + "OSPF interface commands\n" + "Enable authentication on this interface\n" + "Use null authentication\n" + "Use message-digest authentication\n") + +DEFUN (ip_ospf_authentication, + ip_ospf_authentication_addr_cmd, + "ip ospf authentication A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Enable authentication on this interface\n" + "Address of interface") +{ + struct interface *ifp; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 1) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + SET_IF_PARAM (params, auth_type); + params->auth_type = OSPF_AUTH_SIMPLE; + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_authentication, + ip_ospf_authentication_cmd, + "ip ospf authentication", + "IP Information\n" + "OSPF interface commands\n" + "Enable authentication on this interface\n") + +DEFUN (no_ip_ospf_authentication, + no_ip_ospf_authentication_addr_cmd, + "no ip ospf authentication A.B.C.D", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Enable authentication on this interface\n" + "Address of interface") +{ + struct interface *ifp; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 1) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + params->auth_type = OSPF_AUTH_NOTSET; + UNSET_IF_PARAM (params, auth_type); + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_authentication, + no_ip_ospf_authentication_cmd, + "no ip ospf authentication", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Enable authentication on this interface\n") + +DEFUN (ip_ospf_authentication_key, + ip_ospf_authentication_key_addr_cmd, + "ip ospf authentication-key AUTH_KEY A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Authentication password (key)\n" + "The OSPF password (key)\n" + "Address of interface") +{ + struct interface *ifp; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + + memset (params->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE + 1); + strncpy (params->auth_simple, argv[0], OSPF_AUTH_SIMPLE_SIZE); + SET_IF_PARAM (params, auth_simple); + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_authentication_key, + ip_ospf_authentication_key_cmd, + "ip ospf authentication-key AUTH_KEY", + "IP Information\n" + "OSPF interface commands\n" + "Authentication password (key)\n" + "The OSPF password (key)") + +ALIAS (ip_ospf_authentication_key, + ospf_authentication_key_cmd, + "ospf authentication-key AUTH_KEY", + "OSPF interface commands\n" + "Authentication password (key)\n" + "The OSPF password (key)") + +DEFUN (no_ip_ospf_authentication_key, + no_ip_ospf_authentication_key_addr_cmd, + "no ip ospf authentication-key A.B.C.D", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Authentication password (key)\n" + "Address of interface") +{ + struct interface *ifp; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + memset (params->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE); + UNSET_IF_PARAM (params, auth_simple); + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_authentication_key, + no_ip_ospf_authentication_key_cmd, + "no ip ospf authentication-key", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Authentication password (key)\n") + +ALIAS (no_ip_ospf_authentication_key, + no_ospf_authentication_key_cmd, + "no ospf authentication-key", + NO_STR + "OSPF interface commands\n" + "Authentication password (key)\n") + +DEFUN (ip_ospf_message_digest_key, + ip_ospf_message_digest_key_addr_cmd, + "ip ospf message-digest-key <1-255> md5 KEY A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Message digest authentication password (key)\n" + "Key ID\n" + "Use MD5 algorithm\n" + "The OSPF password (key)" + "Address of interface") +{ + struct interface *ifp; + struct crypt_key *ck; + u_char key_id; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 3) + { + ret = inet_aton(argv[2], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + key_id = strtol (argv[0], NULL, 10); + if (ospf_crypt_key_lookup (params->auth_crypt, key_id) != NULL) + { + vty_out (vty, "OSPF: Key %d already exists%s", key_id, VTY_NEWLINE); + return CMD_WARNING; + } + + ck = ospf_crypt_key_new (); + ck->key_id = (u_char) key_id; + memset (ck->auth_key, 0, OSPF_AUTH_MD5_SIZE+1); + strncpy (ck->auth_key, argv[1], OSPF_AUTH_MD5_SIZE); + + ospf_crypt_key_add (params->auth_crypt, ck); + SET_IF_PARAM (params, auth_crypt); + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_message_digest_key, + ip_ospf_message_digest_key_cmd, + "ip ospf message-digest-key <1-255> md5 KEY", + "IP Information\n" + "OSPF interface commands\n" + "Message digest authentication password (key)\n" + "Key ID\n" + "Use MD5 algorithm\n" + "The OSPF password (key)") + +ALIAS (ip_ospf_message_digest_key, + ospf_message_digest_key_cmd, + "ospf message-digest-key <1-255> md5 KEY", + "OSPF interface commands\n" + "Message digest authentication password (key)\n" + "Key ID\n" + "Use MD5 algorithm\n" + "The OSPF password (key)") + +DEFUN (no_ip_ospf_message_digest_key, + no_ip_ospf_message_digest_key_addr_cmd, + "no ip ospf message-digest-key <1-255> A.B.C.D", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Message digest authentication password (key)\n" + "Key ID\n" + "Address of interface") +{ + struct interface *ifp; + struct crypt_key *ck; + int key_id; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + key_id = strtol (argv[0], NULL, 10); + ck = ospf_crypt_key_lookup (params->auth_crypt, key_id); + if (ck == NULL) + { + vty_out (vty, "OSPF: Key %d does not exist%s", key_id, VTY_NEWLINE); + return CMD_WARNING; + } + + ospf_crypt_key_delete (params->auth_crypt, key_id); + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_message_digest_key, + no_ip_ospf_message_digest_key_cmd, + "no ip ospf message-digest-key <1-255>", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Message digest authentication password (key)\n" + "Key ID\n") + +ALIAS (no_ip_ospf_message_digest_key, + no_ospf_message_digest_key_cmd, + "no ospf message-digest-key <1-255>", + NO_STR + "OSPF interface commands\n" + "Message digest authentication password (key)\n" + "Key ID\n") + +DEFUN (ip_ospf_cost, + ip_ospf_cost_addr_cmd, + "ip ospf cost <1-65535> A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Interface cost\n" + "Cost\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + u_int32_t cost; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + params = IF_DEF_PARAMS (ifp); + + cost = strtol (argv[0], NULL, 10); + + /* cost range is <1-65535>. */ + if (cost < 1 || cost > 65535) + { + vty_out (vty, "Interface output cost is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + SET_IF_PARAM (params, output_cost_cmd); + params->output_cost_cmd = cost; + + ospf_if_recalculate_output_cost (ifp); + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_cost, + ip_ospf_cost_cmd, + "ip ospf cost <1-65535>", + "IP Information\n" + "OSPF interface commands\n" + "Interface cost\n" + "Cost") + +ALIAS (ip_ospf_cost, + ospf_cost_cmd, + "ospf cost <1-65535>", + "OSPF interface commands\n" + "Interface cost\n" + "Cost") + +DEFUN (no_ip_ospf_cost, + no_ip_ospf_cost_addr_cmd, + "no ip ospf cost A.B.C.D", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Interface cost\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 1) + { + ret = inet_aton(argv[0], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + UNSET_IF_PARAM (params, output_cost_cmd); + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + ospf_if_recalculate_output_cost (ifp); + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_cost, + no_ip_ospf_cost_cmd, + "no ip ospf cost", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Interface cost\n") + +ALIAS (no_ip_ospf_cost, + no_ospf_cost_cmd, + "no ospf cost", + NO_STR + "OSPF interface commands\n" + "Interface cost\n") + +void +ospf_nbr_timer_update (struct ospf_interface *oi) +{ + struct route_node *rn; + struct ospf_neighbor *nbr; + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info)) + { + nbr->v_inactivity = OSPF_IF_PARAM (oi, v_wait); + nbr->v_db_desc = OSPF_IF_PARAM (oi, retransmit_interval); + nbr->v_ls_req = OSPF_IF_PARAM (oi, retransmit_interval); + nbr->v_ls_upd = OSPF_IF_PARAM (oi, retransmit_interval); + } +} + +DEFUN (ip_ospf_dead_interval, + ip_ospf_dead_interval_addr_cmd, + "ip ospf dead-interval <1-65535> A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n" + "Seconds\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + u_int32_t seconds; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + struct ospf_interface *oi; + struct route_node *rn; + + params = IF_DEF_PARAMS (ifp); + + seconds = strtol (argv[0], NULL, 10); + + /* dead_interval range is <1-65535>. */ + if (seconds < 1 || seconds > 65535) + { + vty_out (vty, "Router Dead Interval is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + SET_IF_PARAM (params, v_wait); + params->v_wait = seconds; + + /* Update timer values in neighbor structure. */ + if (argc == 2) + { + oi = ospf_if_lookup_by_local_addr (ifp, addr); + if (oi) + ospf_nbr_timer_update (oi); + } + else + { + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + if ((oi = rn->info)) + ospf_nbr_timer_update (oi); + } + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_dead_interval, + ip_ospf_dead_interval_cmd, + "ip ospf dead-interval <1-65535>", + "IP Information\n" + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n" + "Seconds\n") + +ALIAS (ip_ospf_dead_interval, + ospf_dead_interval_cmd, + "ospf dead-interval <1-65535>", + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n" + "Seconds\n") + +DEFUN (no_ip_ospf_dead_interval, + no_ip_ospf_dead_interval_addr_cmd, + "no ip ospf dead-interval A.B.C.D", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + struct ospf_interface *oi; + struct route_node *rn; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 1) + { + ret = inet_aton(argv[0], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + UNSET_IF_PARAM (params, v_wait); + params->v_wait = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT; + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + /* Update timer values in neighbor structure. */ + if (argc == 1) + { + oi = ospf_if_lookup_by_local_addr (ifp, addr); + if (oi) + ospf_nbr_timer_update (oi); + } + else + { + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + if ((oi = rn->info)) + ospf_nbr_timer_update (oi); + } + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_dead_interval, + no_ip_ospf_dead_interval_cmd, + "no ip ospf dead-interval", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n") + +ALIAS (no_ip_ospf_dead_interval, + no_ospf_dead_interval_cmd, + "no ospf dead-interval", + NO_STR + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n") + +DEFUN (ip_ospf_hello_interval, + ip_ospf_hello_interval_addr_cmd, + "ip ospf hello-interval <1-65535> A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Time between HELLO packets\n" + "Seconds\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + u_int32_t seconds; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + params = IF_DEF_PARAMS (ifp); + + seconds = strtol (argv[0], NULL, 10); + + /* HelloInterval range is <1-65535>. */ + if (seconds < 1 || seconds > 65535) + { + vty_out (vty, "Hello Interval is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + SET_IF_PARAM (params, v_hello); + params->v_hello = seconds; + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_hello_interval, + ip_ospf_hello_interval_cmd, + "ip ospf hello-interval <1-65535>", + "IP Information\n" + "OSPF interface commands\n" + "Time between HELLO packets\n" + "Seconds\n") + +ALIAS (ip_ospf_hello_interval, + ospf_hello_interval_cmd, + "ospf hello-interval <1-65535>", + "OSPF interface commands\n" + "Time between HELLO packets\n" + "Seconds\n") + +DEFUN (no_ip_ospf_hello_interval, + no_ip_ospf_hello_interval_addr_cmd, + "no ip ospf hello-interval A.B.C.D", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Time between HELLO packets\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 1) + { + ret = inet_aton(argv[0], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + UNSET_IF_PARAM (params, v_hello); + params->v_hello = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT; + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_hello_interval, + no_ip_ospf_hello_interval_cmd, + "no ip ospf hello-interval", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Time between HELLO packets\n") + +ALIAS (no_ip_ospf_hello_interval, + no_ospf_hello_interval_cmd, + "no ospf hello-interval", + NO_STR + "OSPF interface commands\n" + "Time between HELLO packets\n") + +DEFUN (ip_ospf_network, + ip_ospf_network_cmd, + "ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)", + "IP Information\n" + "OSPF interface commands\n" + "Network type\n" + "Specify OSPF broadcast multi-access network\n" + "Specify OSPF NBMA network\n" + "Specify OSPF point-to-multipoint network\n" + "Specify OSPF point-to-point network\n") +{ + struct interface *ifp = vty->index; + int old_type = IF_DEF_PARAMS (ifp)->type; + struct route_node *rn; + + if (strncmp (argv[0], "b", 1) == 0) + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST; + else if (strncmp (argv[0], "n", 1) == 0) + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_NBMA; + else if (strncmp (argv[0], "point-to-m", 10) == 0) + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_POINTOMULTIPOINT; + else if (strncmp (argv[0], "point-to-p", 10) == 0) + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_POINTOPOINT; + + if (IF_DEF_PARAMS (ifp)->type == old_type) + return CMD_SUCCESS; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), type); + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + struct ospf_interface *oi = rn->info; + + if (!oi) + continue; + + oi->type = IF_DEF_PARAMS (ifp)->type; + + if (oi->state > ISM_Down) + { + OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); + OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceUp); + } + } + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_network, + ospf_network_cmd, + "ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)", + "OSPF interface commands\n" + "Network type\n" + "Specify OSPF broadcast multi-access network\n" + "Specify OSPF NBMA network\n" + "Specify OSPF point-to-multipoint network\n" + "Specify OSPF point-to-point network\n") + +DEFUN (no_ip_ospf_network, + no_ip_ospf_network_cmd, + "no ip ospf network", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Network type\n") +{ + struct interface *ifp = vty->index; + int old_type = IF_DEF_PARAMS (ifp)->type; + struct route_node *rn; + + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST; + + if (IF_DEF_PARAMS (ifp)->type == old_type) + return CMD_SUCCESS; + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + struct ospf_interface *oi = rn->info; + + if (!oi) + continue; + + oi->type = IF_DEF_PARAMS (ifp)->type; + + if (oi->state > ISM_Down) + { + OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); + OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceUp); + } + } + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_network, + no_ospf_network_cmd, + "no ospf network", + NO_STR + "OSPF interface commands\n" + "Network type\n") + +DEFUN (ip_ospf_priority, + ip_ospf_priority_addr_cmd, + "ip ospf priority <0-255> A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Router priority\n" + "Priority\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + u_int32_t priority; + struct route_node *rn; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + params = IF_DEF_PARAMS (ifp); + + priority = strtol (argv[0], NULL, 10); + + /* Router Priority range is <0-255>. */ + if (priority < 0 || priority > 255) + { + vty_out (vty, "Router Priority is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + SET_IF_PARAM (params, priority); + params->priority = priority; + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + struct ospf_interface *oi = rn->info; + + if (!oi) + continue; + + + if (PRIORITY (oi) != OSPF_IF_PARAM (oi, priority)) + { + PRIORITY (oi) = OSPF_IF_PARAM (oi, priority); + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange); + } + } + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_priority, + ip_ospf_priority_cmd, + "ip ospf priority <0-255>", + "IP Information\n" + "OSPF interface commands\n" + "Router priority\n" + "Priority\n") + +ALIAS (ip_ospf_priority, + ospf_priority_cmd, + "ospf priority <0-255>", + "OSPF interface commands\n" + "Router priority\n" + "Priority\n") + +DEFUN (no_ip_ospf_priority, + no_ip_ospf_priority_addr_cmd, + "no ip ospf priority A.B.C.D", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Router priority\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + struct route_node *rn; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 1) + { + ret = inet_aton(argv[0], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + UNSET_IF_PARAM (params, priority); + params->priority = OSPF_ROUTER_PRIORITY_DEFAULT; + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + struct ospf_interface *oi = rn->info; + + if (!oi) + continue; + + + if (PRIORITY (oi) != OSPF_IF_PARAM (oi, priority)) + { + PRIORITY (oi) = OSPF_IF_PARAM (oi, priority); + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange); + } + } + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_priority, + no_ip_ospf_priority_cmd, + "no ip ospf priority", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Router priority\n") + +ALIAS (no_ip_ospf_priority, + no_ospf_priority_cmd, + "no ospf priority", + NO_STR + "OSPF interface commands\n" + "Router priority\n") + +DEFUN (ip_ospf_retransmit_interval, + ip_ospf_retransmit_interval_addr_cmd, + "ip ospf retransmit-interval <3-65535> A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n" + "Seconds\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + u_int32_t seconds; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + params = IF_DEF_PARAMS (ifp); + seconds = strtol (argv[0], NULL, 10); + + /* Retransmit Interval range is <3-65535>. */ + if (seconds < 3 || seconds > 65535) + { + vty_out (vty, "Retransmit Interval is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + SET_IF_PARAM (params, retransmit_interval); + params->retransmit_interval = seconds; + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_retransmit_interval, + ip_ospf_retransmit_interval_cmd, + "ip ospf retransmit-interval <3-65535>", + "IP Information\n" + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n" + "Seconds\n") + +ALIAS (ip_ospf_retransmit_interval, + ospf_retransmit_interval_cmd, + "ospf retransmit-interval <3-65535>", + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n" + "Seconds\n") + +DEFUN (no_ip_ospf_retransmit_interval, + no_ip_ospf_retransmit_interval_addr_cmd, + "no ip ospf retransmit-interval A.B.C.D", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 1) + { + ret = inet_aton(argv[0], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + UNSET_IF_PARAM (params, retransmit_interval); + params->retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_retransmit_interval, + no_ip_ospf_retransmit_interval_cmd, + "no ip ospf retransmit-interval", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n") + +ALIAS (no_ip_ospf_retransmit_interval, + no_ospf_retransmit_interval_cmd, + "no ospf retransmit-interval", + NO_STR + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n") + +DEFUN (ip_ospf_transmit_delay, + ip_ospf_transmit_delay_addr_cmd, + "ip ospf transmit-delay <1-65535> A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Link state transmit delay\n" + "Seconds\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + u_int32_t seconds; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + params = IF_DEF_PARAMS (ifp); + seconds = strtol (argv[0], NULL, 10); + + /* Transmit Delay range is <1-65535>. */ + if (seconds < 1 || seconds > 65535) + { + vty_out (vty, "Transmit Delay is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + SET_IF_PARAM (params, transmit_delay); + params->transmit_delay = seconds; + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_transmit_delay, + ip_ospf_transmit_delay_cmd, + "ip ospf transmit-delay <1-65535>", + "IP Information\n" + "OSPF interface commands\n" + "Link state transmit delay\n" + "Seconds\n") + +ALIAS (ip_ospf_transmit_delay, + ospf_transmit_delay_cmd, + "ospf transmit-delay <1-65535>", + "OSPF interface commands\n" + "Link state transmit delay\n" + "Seconds\n") + +DEFUN (no_ip_ospf_transmit_delay, + no_ip_ospf_transmit_delay_addr_cmd, + "no ip ospf transmit-delay A.B.C.D", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Link state transmit delay\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 1) + { + ret = inet_aton(argv[0], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + UNSET_IF_PARAM (params, transmit_delay); + params->transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT; + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_transmit_delay, + no_ip_ospf_transmit_delay_cmd, + "no ip ospf transmit-delay", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Link state transmit delay\n") + +ALIAS (no_ip_ospf_transmit_delay, + no_ospf_transmit_delay_cmd, + "no ospf transmit-delay", + NO_STR + "OSPF interface commands\n" + "Link state transmit delay\n") + + +DEFUN (ospf_redistribute_source_metric_type, + ospf_redistribute_source_metric_type_routemap_cmd, + "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> metric-type (1|2) route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "Metric for redistributed routes\n" + "OSPF default metric\n" + "OSPF exterior metric type for redistributed routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int source; + int type = -1; + int metric = -1; + + /* Get distribute source. */ + if (!str2distribute_source (argv[0], &source)) + return CMD_WARNING; + + /* Get metric value. */ + if (argc >= 2) + if (!str2metric (argv[1], &metric)) + return CMD_WARNING; + + /* Get metric type. */ + if (argc >= 3) + if (!str2metric_type (argv[2], &type)) + return CMD_WARNING; + + if (argc == 4) + ospf_routemap_set (source, argv[3]); + else + ospf_routemap_unset (source); + + return ospf_redistribute_set (source, type, metric); +} + +ALIAS (ospf_redistribute_source_metric_type, + ospf_redistribute_source_metric_type_cmd, + "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> metric-type (1|2)", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "Metric for redistributed routes\n" + "OSPF default metric\n" + "OSPF exterior metric type for redistributed routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n") + +ALIAS (ospf_redistribute_source_metric_type, + ospf_redistribute_source_metric_cmd, + "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214>", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "Metric for redistributed routes\n" + "OSPF default metric\n") + +DEFUN (ospf_redistribute_source_type_metric, + ospf_redistribute_source_type_metric_routemap_cmd, + "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214> route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "OSPF exterior metric type for redistributed routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Metric for redistributed routes\n" + "OSPF default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int source; + int type = -1; + int metric = -1; + + /* Get distribute source. */ + if (!str2distribute_source (argv[0], &source)) + return CMD_WARNING; + + /* Get metric value. */ + if (argc >= 2) + if (!str2metric_type (argv[1], &type)) + return CMD_WARNING; + + /* Get metric type. */ + if (argc >= 3) + if (!str2metric (argv[2], &metric)) + return CMD_WARNING; + + if (argc == 4) + ospf_routemap_set (source, argv[3]); + else + ospf_routemap_unset (source); + + return ospf_redistribute_set (source, type, metric); +} + +ALIAS (ospf_redistribute_source_type_metric, + ospf_redistribute_source_type_metric_cmd, + "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214>", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "OSPF exterior metric type for redistributed routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Metric for redistributed routes\n" + "OSPF default metric\n") + +ALIAS (ospf_redistribute_source_type_metric, + ospf_redistribute_source_type_cmd, + "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2)", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "OSPF exterior metric type for redistributed routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n") + +ALIAS (ospf_redistribute_source_type_metric, + ospf_redistribute_source_cmd, + "redistribute (kernel|connected|static|rip|bgp)", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n") + +DEFUN (ospf_redistribute_source_metric_routemap, + ospf_redistribute_source_metric_routemap_cmd, + "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "Metric for redistributed routes\n" + "OSPF default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int source; + int metric = -1; + + /* Get distribute source. */ + if (!str2distribute_source (argv[0], &source)) + return CMD_WARNING; + + /* Get metric value. */ + if (argc >= 2) + if (!str2metric (argv[1], &metric)) + return CMD_WARNING; + + if (argc == 3) + ospf_routemap_set (source, argv[2]); + else + ospf_routemap_unset (source); + + return ospf_redistribute_set (source, -1, metric); +} + +DEFUN (ospf_redistribute_source_type_routemap, + ospf_redistribute_source_type_routemap_cmd, + "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "OSPF exterior metric type for redistributed routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int source; + int type = -1; + + /* Get distribute source. */ + if (!str2distribute_source (argv[0], &source)) + return CMD_WARNING; + + /* Get metric value. */ + if (argc >= 2) + if (!str2metric_type (argv[1], &type)) + return CMD_WARNING; + + if (argc == 3) + ospf_routemap_set (source, argv[2]); + else + ospf_routemap_unset (source); + + return ospf_redistribute_set (source, type, -1); +} + +DEFUN (ospf_redistribute_source_routemap, + ospf_redistribute_source_routemap_cmd, + "redistribute (kernel|connected|static|rip|bgp) route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int source; + + /* Get distribute source. */ + if (!str2distribute_source (argv[0], &source)) + return CMD_WARNING; + + if (argc == 2) + ospf_routemap_set (source, argv[1]); + else + ospf_routemap_unset (source); + + return ospf_redistribute_set (source, -1, -1); +} + +DEFUN (no_ospf_redistribute_source, + no_ospf_redistribute_source_cmd, + "no redistribute (kernel|connected|static|rip|bgp)", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n") +{ + int source; + + if (!str2distribute_source (argv[0], &source)) + return CMD_WARNING; + + ospf_routemap_unset (source); + return ospf_redistribute_unset (source); +} + +DEFUN (ospf_distribute_list_out, + ospf_distribute_list_out_cmd, + "distribute-list WORD out (kernel|connected|static|rip|bgp)", + "Filter networks in routing updates\n" + "Access-list name\n" + OUT_STR + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n") +{ + int source; + + /* Get distribute source. */ + if (!str2distribute_source (argv[1], &source)) + return CMD_WARNING; + + return ospf_distribute_list_out_set (source, argv[0]); +} + +DEFUN (no_ospf_distribute_list_out, + no_ospf_distribute_list_out_cmd, + "no distribute-list WORD out (kernel|connected|static|rip|bgp)", + NO_STR + "Filter networks in routing updates\n" + "Access-list name\n" + OUT_STR + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n") +{ + int source; + + if (!str2distribute_source (argv[1], &source)) + return CMD_WARNING; + + return ospf_distribute_list_out_unset (source, argv[0]); +} + +/* Default information originate. */ +DEFUN (ospf_default_information_originate_metric_type_routemap, + ospf_default_information_originate_metric_type_routemap_cmd, + "default-information originate metric <0-16777214> metric-type (1|2) route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int type = -1; + int metric = -1; + + /* Get metric value. */ + if (argc >= 1) + if (!str2metric (argv[0], &metric)) + return CMD_WARNING; + + /* Get metric type. */ + if (argc >= 2) + if (!str2metric_type (argv[1], &type)) + return CMD_WARNING; + + if (argc == 3) + ospf_routemap_set (DEFAULT_ROUTE, argv[2]); + else + ospf_routemap_unset (DEFAULT_ROUTE); + + return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ZEBRA, type, metric); +} + +ALIAS (ospf_default_information_originate_metric_type_routemap, + ospf_default_information_originate_metric_type_cmd, + "default-information originate metric <0-16777214> metric-type (1|2)", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n") + +ALIAS (ospf_default_information_originate_metric_type_routemap, + ospf_default_information_originate_metric_cmd, + "default-information originate metric <0-16777214>", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF default metric\n" + "OSPF metric\n") + +ALIAS (ospf_default_information_originate_metric_type_routemap, + ospf_default_information_originate_cmd, + "default-information originate", + "Control distribution of default information\n" + "Distribute a default route\n") + +/* Default information originate. */ +DEFUN (ospf_default_information_originate_metric_routemap, + ospf_default_information_originate_metric_routemap_cmd, + "default-information originate metric <0-16777214> route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int metric = -1; + + /* Get metric value. */ + if (argc >= 1) + if (!str2metric (argv[0], &metric)) + return CMD_WARNING; + + if (argc == 2) + ospf_routemap_set (DEFAULT_ROUTE, argv[1]); + else + ospf_routemap_unset (DEFAULT_ROUTE); + + return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ZEBRA, -1, metric); +} + +/* Default information originate. */ +DEFUN (ospf_default_information_originate_routemap, + ospf_default_information_originate_routemap_cmd, + "default-information originate route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + if (argc == 1) + ospf_routemap_set (DEFAULT_ROUTE, argv[0]); + else + ospf_routemap_unset (DEFAULT_ROUTE); + + return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ZEBRA, -1, -1); +} + +DEFUN (ospf_default_information_originate_type_metric_routemap, + ospf_default_information_originate_type_metric_routemap_cmd, + "default-information originate metric-type (1|2) metric <0-16777214> route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "OSPF default metric\n" + "OSPF metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int type = -1; + int metric = -1; + + /* Get metric type. */ + if (argc >= 1) + if (!str2metric_type (argv[0], &type)) + return CMD_WARNING; + + /* Get metric value. */ + if (argc >= 2) + if (!str2metric (argv[1], &metric)) + return CMD_WARNING; + + if (argc == 3) + ospf_routemap_set (DEFAULT_ROUTE, argv[2]); + else + ospf_routemap_unset (DEFAULT_ROUTE); + + return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ZEBRA, type, metric); +} + +ALIAS (ospf_default_information_originate_type_metric_routemap, + ospf_default_information_originate_type_metric_cmd, + "default-information originate metric-type (1|2) metric <0-16777214>", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "OSPF default metric\n" + "OSPF metric\n") + +ALIAS (ospf_default_information_originate_type_metric_routemap, + ospf_default_information_originate_type_cmd, + "default-information originate metric-type (1|2)", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n") + +DEFUN (ospf_default_information_originate_type_routemap, + ospf_default_information_originate_type_routemap_cmd, + "default-information originate metric-type (1|2) route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int type = -1; + + /* Get metric type. */ + if (argc >= 1) + if (!str2metric_type (argv[0], &type)) + return CMD_WARNING; + + if (argc == 2) + ospf_routemap_set (DEFAULT_ROUTE, argv[1]); + else + ospf_routemap_unset (DEFAULT_ROUTE); + + return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ZEBRA, type, -1); +} + +DEFUN (ospf_default_information_originate_always_metric_type_routemap, + ospf_default_information_originate_always_metric_type_routemap_cmd, + "default-information originate always metric <0-16777214> metric-type (1|2) route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int type = -1; + int metric = -1; + + /* Get metric value. */ + if (argc >= 1) + if (!str2metric (argv[0], &metric)) + return CMD_WARNING; + + /* Get metric type. */ + if (argc >= 2) + if (!str2metric_type (argv[1], &type)) + return CMD_WARNING; + + if (argc == 3) + ospf_routemap_set (DEFAULT_ROUTE, argv[2]); + else + ospf_routemap_unset (DEFAULT_ROUTE); + + return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ALWAYS, + type, metric); +} + +ALIAS (ospf_default_information_originate_always_metric_type_routemap, + ospf_default_information_originate_always_metric_type_cmd, + "default-information originate always metric <0-16777214> metric-type (1|2)", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n") + +ALIAS (ospf_default_information_originate_always_metric_type_routemap, + ospf_default_information_originate_always_metric_cmd, + "default-information originate always metric <0-16777214>", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "OSPF metric type for default routes\n") + +ALIAS (ospf_default_information_originate_always_metric_type_routemap, + ospf_default_information_originate_always_cmd, + "default-information originate always", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n") + +DEFUN (ospf_default_information_originate_always_metric_routemap, + ospf_default_information_originate_always_metric_routemap_cmd, + "default-information originate always metric <0-16777214> route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int metric = -1; + + /* Get metric value. */ + if (argc >= 1) + if (!str2metric (argv[0], &metric)) + return CMD_WARNING; + + if (argc == 2) + ospf_routemap_set (DEFAULT_ROUTE, argv[1]); + else + ospf_routemap_unset (DEFAULT_ROUTE); + + return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ALWAYS, -1, metric); +} + +DEFUN (ospf_default_information_originate_always_routemap, + ospf_default_information_originate_always_routemap_cmd, + "default-information originate always route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + if (argc == 1) + ospf_routemap_set (DEFAULT_ROUTE, argv[0]); + else + ospf_routemap_unset (DEFAULT_ROUTE); + + return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ALWAYS, -1, -1); +} + +DEFUN (ospf_default_information_originate_always_type_metric_routemap, + ospf_default_information_originate_always_type_metric_routemap_cmd, + "default-information originate always metric-type (1|2) metric <0-16777214> route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "OSPF default metric\n" + "OSPF metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int type = -1; + int metric = -1; + + /* Get metric type. */ + if (argc >= 1) + if (!str2metric_type (argv[0], &type)) + return CMD_WARNING; + + /* Get metric value. */ + if (argc >= 2) + if (!str2metric (argv[1], &metric)) + return CMD_WARNING; + + if (argc == 3) + ospf_routemap_set (DEFAULT_ROUTE, argv[2]); + else + ospf_routemap_unset (DEFAULT_ROUTE); + + return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ALWAYS, + type, metric); +} + +ALIAS (ospf_default_information_originate_always_type_metric_routemap, + ospf_default_information_originate_always_type_metric_cmd, + "default-information originate always metric-type (1|2) metric <0-16777214>", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "OSPF default metric\n" + "OSPF metric\n") + +ALIAS (ospf_default_information_originate_always_type_metric_routemap, + ospf_default_information_originate_always_type_cmd, + "default-information originate always metric-type (1|2)", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n") + +DEFUN (ospf_default_information_originate_always_type_routemap, + ospf_default_information_originate_always_type_routemap_cmd, + "default-information originate always metric-type (1|2) route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int type = -1; + + /* Get metric type. */ + if (argc >= 1) + if (!str2metric_type (argv[0], &type)) + return CMD_WARNING; + + if (argc == 2) + ospf_routemap_set (DEFAULT_ROUTE, argv[1]); + else + ospf_routemap_unset (DEFAULT_ROUTE); + + return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ALWAYS, + type, -1); +} + +DEFUN (no_ospf_default_information_originate, + no_ospf_default_information_originate_cmd, + "no default-information originate", + NO_STR + "Control distribution of default information\n" + "Distribute a default route\n") +{ + struct prefix_ipv4 p; + struct in_addr nexthop; + + p.family = AF_INET; + p.prefix.s_addr = 0; + p.prefixlen = 0; + + ospf_external_lsa_flush (DEFAULT_ROUTE, &p, 0, nexthop); + + if (EXTERNAL_INFO (DEFAULT_ROUTE)) { + ospf_external_info_delete (DEFAULT_ROUTE, p); + route_table_finish (EXTERNAL_INFO (DEFAULT_ROUTE)); + EXTERNAL_INFO (DEFAULT_ROUTE) = NULL; + } + + ospf_routemap_unset (DEFAULT_ROUTE); + return ospf_redistribute_default_unset (); +} + +DEFUN (ospf_default_metric, + ospf_default_metric_cmd, + "default-metric <0-16777214>", + "Set metric of redistributed routes\n" + "Default metric\n") +{ + int metric = -1; + + if (!str2metric (argv[0], &metric)) + return CMD_WARNING; + + ospf_top->default_metric = metric; + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_default_metric, + no_ospf_default_metric_cmd, + "no default-metric", + NO_STR + "Set metric of redistributed routes\n") +{ + ospf_top->default_metric = -1; + return CMD_SUCCESS; +} + +ALIAS (no_ospf_default_metric, + no_ospf_default_metric_val_cmd, + "no default-metric <0-16777214>", + NO_STR + "Set metric of redistributed routes\n" + "Default metric\n") + +DEFUN (ospf_distance, + ospf_distance_cmd, + "distance <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n") +{ + ospf_top->distance_all = atoi (argv[0]); + return CMD_SUCCESS; +} + +DEFUN (no_ospf_distance, + no_ospf_distance_cmd, + "no distance <1-255>", + NO_STR + "Define an administrative distance\n" + "OSPF Administrative distance\n") +{ + ospf_top->distance_all = 0; + return CMD_SUCCESS; +} + +DEFUN (no_ospf_distance_ospf, + no_ospf_distance_ospf_cmd, + "no distance ospf", + NO_STR + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "OSPF Distance\n") +{ + ospf_top->distance_intra = 0; + ospf_top->distance_inter = 0; + ospf_top->distance_external = 0; + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_intra, + ospf_distance_ospf_intra_cmd, + "distance ospf intra-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") +{ + ospf_top->distance_intra = atoi (argv[0]); + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_intra_inter, + ospf_distance_ospf_intra_inter_cmd, + "distance ospf intra-area <1-255> inter-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") +{ + ospf_top->distance_intra = atoi (argv[0]); + ospf_top->distance_inter = atoi (argv[1]); + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_intra_external, + ospf_distance_ospf_intra_external_cmd, + "distance ospf intra-area <1-255> external <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "External routes\n" + "Distance for external routes\n") +{ + ospf_top->distance_intra = atoi (argv[0]); + ospf_top->distance_external = atoi (argv[1]); + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_intra_inter_external, + ospf_distance_ospf_intra_inter_external_cmd, + "distance ospf intra-area <1-255> inter-area <1-255> external <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "External routes\n" + "Distance for external routes\n") +{ + ospf_top->distance_intra = atoi (argv[0]); + ospf_top->distance_inter = atoi (argv[1]); + ospf_top->distance_external = atoi (argv[2]); + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_intra_external_inter, + ospf_distance_ospf_intra_external_inter_cmd, + "distance ospf intra-area <1-255> external <1-255> inter-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "External routes\n" + "Distance for external routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") +{ + ospf_top->distance_intra = atoi (argv[0]); + ospf_top->distance_external = atoi (argv[1]); + ospf_top->distance_inter = atoi (argv[2]); + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_inter, + ospf_distance_ospf_inter_cmd, + "distance ospf inter-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") +{ + ospf_top->distance_inter = atoi (argv[0]); + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_inter_intra, + ospf_distance_ospf_inter_intra_cmd, + "distance ospf inter-area <1-255> intra-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") +{ + ospf_top->distance_inter = atoi (argv[0]); + ospf_top->distance_intra = atoi (argv[1]); + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_inter_external, + ospf_distance_ospf_inter_external_cmd, + "distance ospf inter-area <1-255> external <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "External routes\n" + "Distance for external routes\n") +{ + ospf_top->distance_inter = atoi (argv[0]); + ospf_top->distance_external = atoi (argv[1]); + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_inter_intra_external, + ospf_distance_ospf_inter_intra_external_cmd, + "distance ospf inter-area <1-255> intra-area <1-255> external <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "External routes\n" + "Distance for external routes\n") +{ + ospf_top->distance_inter = atoi (argv[0]); + ospf_top->distance_intra = atoi (argv[1]); + ospf_top->distance_external = atoi (argv[2]); + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_inter_external_intra, + ospf_distance_ospf_inter_external_intra_cmd, + "distance ospf inter-area <1-255> external <1-255> intra-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "External routes\n" + "Distance for external routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") +{ + ospf_top->distance_inter = atoi (argv[0]); + ospf_top->distance_external = atoi (argv[1]); + ospf_top->distance_intra = atoi (argv[2]); + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_external, + ospf_distance_ospf_external_cmd, + "distance ospf external <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "External routes\n" + "Distance for external routes\n") +{ + ospf_top->distance_external = atoi (argv[0]); + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_external_intra, + ospf_distance_ospf_external_intra_cmd, + "distance ospf external <1-255> intra-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "External routes\n" + "Distance for external routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") +{ + ospf_top->distance_external = atoi (argv[0]); + ospf_top->distance_intra = atoi (argv[1]); + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_external_inter, + ospf_distance_ospf_external_inter_cmd, + "distance ospf external <1-255> inter-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "External routes\n" + "Distance for external routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") +{ + ospf_top->distance_external = atoi (argv[0]); + ospf_top->distance_inter = atoi (argv[1]); + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_external_intra_inter, + ospf_distance_ospf_external_intra_inter_cmd, + "distance ospf external <1-255> intra-area <1-255> inter-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "External routes\n" + "Distance for external routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") +{ + ospf_top->distance_external = atoi (argv[0]); + ospf_top->distance_intra = atoi (argv[1]); + ospf_top->distance_inter = atoi (argv[2]); + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_external_inter_intra, + ospf_distance_ospf_external_inter_intra_cmd, + "distance ospf external <1-255> inter-area <1-255> intra-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "External routes\n" + "Distance for external routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") +{ + ospf_top->distance_external = atoi (argv[0]); + ospf_top->distance_inter = atoi (argv[1]); + ospf_top->distance_intra = atoi (argv[2]); + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_source, + ospf_distance_source_cmd, + "distance <1-255> A.B.C.D/M", + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n") +{ + ospf_distance_set (vty, argv[0], argv[1], NULL); + return CMD_SUCCESS; +} + +DEFUN (no_ospf_distance_source, + no_ospf_distance_source_cmd, + "no distance <1-255> A.B.C.D/M", + NO_STR + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n") +{ + ospf_distance_unset (vty, argv[0], argv[1], NULL); + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_source_access_list, + ospf_distance_source_access_list_cmd, + "distance <1-255> A.B.C.D/M WORD", + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") +{ + ospf_distance_set (vty, argv[0], argv[1], argv[2]); + return CMD_SUCCESS; +} + +DEFUN (no_ospf_distance_source_access_list, + no_ospf_distance_source_access_list_cmd, + "no distance <1-255> A.B.C.D/M WORD", + NO_STR + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") +{ + ospf_distance_unset (vty, argv[0], argv[1], argv[2]); + return CMD_SUCCESS; +} + +void +show_ip_ospf_route_network (struct vty *vty, struct route_table *rt) +{ + struct route_node *rn; + struct ospf_route *or; + listnode pnode; + struct ospf_path *path; + + vty_out (vty, "============ OSPF network routing table ============%s", + VTY_NEWLINE); + + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((or = rn->info) != NULL) + { + char buf1[19]; + snprintf (buf1, 19, "%s/%d", + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); + + switch (or->path_type) + { + case OSPF_PATH_INTER_AREA: + if (or->type == OSPF_DESTINATION_NETWORK) + vty_out (vty, "N IA %-18s [%d] area: %s%s", buf1, or->cost, + inet_ntoa (or->u.std.area_id), VTY_NEWLINE); + else if (or->type == OSPF_DESTINATION_DISCARD) + vty_out (vty, "D IA %-18s Discard entry%s", buf1, VTY_NEWLINE); + break; + case OSPF_PATH_INTRA_AREA: + vty_out (vty, "N %-18s [%d] area: %s%s", buf1, or->cost, + inet_ntoa (or->u.std.area_id), VTY_NEWLINE); + break; + default: + break; + } + + if (or->type == OSPF_DESTINATION_NETWORK) + for (pnode = listhead (or->path); pnode; nextnode (pnode)) + { + path = getdata (pnode); + if (path->oi != NULL) + { + if (path->nexthop.s_addr == 0) + vty_out (vty, "%24s directly attached to %s%s", + "", path->oi->ifp->name, VTY_NEWLINE); + else + vty_out (vty, "%24s via %s, %s%s", "", + inet_ntoa (path->nexthop), path->oi->ifp->name, + VTY_NEWLINE); + } + } + } + vty_out (vty, "%s", VTY_NEWLINE); +} + +void +show_ip_ospf_route_router (struct vty *vty, struct route_table *rtrs) +{ + struct route_node *rn; + struct ospf_route *or; + listnode pn, nn; + struct ospf_path *path; + + vty_out (vty, "============ OSPF router routing table =============%s", + VTY_NEWLINE); + for (rn = route_top (rtrs); rn; rn = route_next (rn)) + if (rn->info) + { + int flag = 0; + + vty_out (vty, "R %-15s ", inet_ntoa (rn->p.u.prefix4)); + + for (nn = listhead ((list) rn->info); nn; nextnode (nn)) + if ((or = getdata (nn)) != NULL) + { + if (flag++) + vty_out(vty," " ); + + /* Show path. */ + vty_out (vty, "%s [%d] area: %s", + (or->path_type == OSPF_PATH_INTER_AREA ? "IA" : " "), + or->cost, inet_ntoa (or->u.std.area_id)); + /* Show flags. */ + vty_out (vty, "%s%s%s", + (or->u.std.flags & ROUTER_LSA_BORDER ? ", ABR" : ""), + (or->u.std.flags & ROUTER_LSA_EXTERNAL ? ", ASBR" : ""), + VTY_NEWLINE); + + for (pn = listhead (or->path); pn; nextnode (pn)) + { + path = getdata (pn); + if (path->nexthop.s_addr == 0) + vty_out (vty, "%24s directly attached to %s%s", + "", path->oi->ifp->name, VTY_NEWLINE); + else + vty_out (vty, "%24s via %s, %s%s", "", + inet_ntoa (path->nexthop), path->oi->ifp->name, + VTY_NEWLINE); + } + } + } + vty_out (vty, "%s", VTY_NEWLINE); +} + +void +show_ip_ospf_route_external (struct vty *vty, struct route_table *rt) +{ + struct route_node *rn; + struct ospf_route *er; + listnode pnode; + struct ospf_path *path; + + vty_out (vty, "============ OSPF external routing table ===========%s", + VTY_NEWLINE); + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((er = rn->info) != NULL) + { + char buf1[19]; + snprintf (buf1, 19, "%s/%d", + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); + + switch (er->path_type) + { + case OSPF_PATH_TYPE1_EXTERNAL: + vty_out (vty, "N E1 %-18s [%d] tag: %u%s", buf1, + er->cost, er->u.ext.tag, VTY_NEWLINE); + break; + case OSPF_PATH_TYPE2_EXTERNAL: + vty_out (vty, "N E2 %-18s [%d/%d] tag: %u%s", buf1, er->cost, + er->u.ext.type2_cost, er->u.ext.tag, VTY_NEWLINE); + break; + } + + for (pnode = listhead (er->path); pnode; nextnode (pnode)) + { + path = getdata (pnode); + if (path->oi != NULL) + { + if (path->nexthop.s_addr == 0) + vty_out (vty, "%24s directly attached to %s%s", + "", path->oi->ifp->name, VTY_NEWLINE); + else + vty_out (vty, "%24s via %s, %s%s", "", + inet_ntoa (path->nexthop), path->oi->ifp->name, + VTY_NEWLINE); + } + } + } + vty_out (vty, "%s", VTY_NEWLINE); +} + +#ifdef HAVE_NSSA +DEFUN (show_ip_ospf_border_routers, + show_ip_ospf_border_routers_cmd, + "show ip ospf border-routers", + SHOW_STR + IP_STR + "show all the ABR's and ASBR's\n" + "for this area\n") +{ + if (ospf_top == NULL) + { + vty_out (vty, "OSPF is not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + if (ospf_top->new_table == NULL) + { + vty_out (vty, "No OSPF routing information exist%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + /* Show Network routes. + show_ip_ospf_route_network (vty, ospf_top->new_table); */ + + /* Show Router routes. */ + show_ip_ospf_route_router (vty, ospf_top->new_rtrs); + + return CMD_SUCCESS; +} +#endif /* HAVE_NSSA */ + +DEFUN (show_ip_ospf_route, + show_ip_ospf_route_cmd, + "show ip ospf route", + SHOW_STR + IP_STR + "OSPF information\n" + "OSPF routing table\n") +{ + if (ospf_top == NULL) + { + vty_out (vty, "OSPF is not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + if (ospf_top->new_table == NULL) + { + vty_out (vty, "No OSPF routing information exist%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + /* Show Network routes. */ + show_ip_ospf_route_network (vty, ospf_top->new_table); + + /* Show Router routes. */ + show_ip_ospf_route_router (vty, ospf_top->new_rtrs); + + /* Show AS External routes. */ + show_ip_ospf_route_external (vty, ospf_top->old_external_route); + + return CMD_SUCCESS; +} + + +char *ospf_abr_type_str[] = +{ + "unknown", + "standard", + "ibm", + "cisco", + "shortcut" +}; + +char *ospf_shortcut_mode_str[] = +{ + "default", + "enable", + "disable" +}; + + +void +area_id2str (char *buf, int length, struct ospf_area *area) +{ + memset (buf, 0, length); + + if (area->format == OSPF_AREA_ID_FORMAT_ADDRESS) + strncpy (buf, inet_ntoa (area->area_id), length); + else + sprintf (buf, "%lu", (unsigned long) ntohl (area->area_id.s_addr)); +} + + +char *ospf_int_type_str[] = +{ + "unknown", /* should never be used. */ + "point-to-point", + "broadcast", + "non-broadcast", + "point-to-multipoint", + "virtual-link", /* should never be used. */ + "loopback" +}; + +/* Configuration write function for ospfd. */ +int +config_write_interface (struct vty *vty) +{ + listnode n1, n2; + struct interface *ifp; + struct crypt_key *ck; + int write = 0; + struct route_node *rn = NULL; + struct ospf_if_params *params; + + for (n1 = listhead (iflist); n1; nextnode (n1)) + { + ifp = getdata (n1); + + if (memcmp (ifp->name, "VLINK", 5) == 0) + continue; + + vty_out (vty, "!%s", VTY_NEWLINE); + vty_out (vty, "interface %s%s", ifp->name, + VTY_NEWLINE); + if (ifp->desc) + vty_out (vty, " description %s%s", ifp->desc, + VTY_NEWLINE); + + write++; + + params = IF_DEF_PARAMS (ifp); + + do { + /* Interface Network print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, type) && + params->type != OSPF_IFTYPE_BROADCAST && + params->type != OSPF_IFTYPE_LOOPBACK) + { + vty_out (vty, " ip ospf network %s", + ospf_int_type_str[params->type]); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* OSPF interface authentication print */ + if (OSPF_IF_PARAM_CONFIGURED (params, auth_type) && + params->auth_type != OSPF_AUTH_NOTSET) + { + char *auth_str; + + /* Translation tables are not that much help here due to syntax + of the simple option */ + switch (params->auth_type) + { + + case OSPF_AUTH_NULL: + auth_str = " null"; + break; + + case OSPF_AUTH_SIMPLE: + auth_str = ""; + break; + + case OSPF_AUTH_CRYPTOGRAPHIC: + auth_str = " message-digest"; + break; + + default: + auth_str = ""; + break; + } + + vty_out (vty, " ip ospf authentication%s", auth_str); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Simple Authentication Password print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, auth_simple) && + params->auth_simple[0] != '\0') + { + vty_out (vty, " ip ospf authentication-key %s", + params->auth_simple); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Cryptographic Authentication Key print. */ + for (n2 = listhead (params->auth_crypt); n2; nextnode (n2)) + { + ck = getdata (n2); + vty_out (vty, " ip ospf message-digest-key %d md5 %s", + ck->key_id, ck->auth_key); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Interface Output Cost print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, output_cost_cmd)) + { + vty_out (vty, " ip ospf cost %u", params->output_cost_cmd); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Hello Interval print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, v_hello) && + params->v_hello != OSPF_HELLO_INTERVAL_DEFAULT) + { + vty_out (vty, " ip ospf hello-interval %u", params->v_hello); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + + /* Router Dead Interval print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, v_wait) && + params->v_wait != OSPF_ROUTER_DEAD_INTERVAL_DEFAULT) + { + vty_out (vty, " ip ospf dead-interval %u", params->v_wait); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Router Priority print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, priority) && + params->priority != OSPF_ROUTER_PRIORITY_DEFAULT) + { + vty_out (vty, " ip ospf priority %u", params->priority); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Retransmit Interval print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, retransmit_interval) && + params->retransmit_interval != OSPF_RETRANSMIT_INTERVAL_DEFAULT) + { + vty_out (vty, " ip ospf retransmit-interval %u", + params->retransmit_interval); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Transmit Delay print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, transmit_delay) && + params->transmit_delay != OSPF_TRANSMIT_DELAY_DEFAULT) + { + vty_out (vty, " ip ospf transmit-delay %u", params->transmit_delay); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + while (1) + { + if (rn == NULL) + rn = route_top (IF_OIFS_PARAMS (ifp)); + else + rn = route_next (rn); + + if (rn == NULL) + break; + params = rn->info; + if (params != NULL) + break; + } + } while (rn); + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_config_write_if (vty, ifp); +#endif /* HAVE_OPAQUE_LSA */ + } + + return write; +} + +int +config_write_network_area (struct vty *vty) +{ + struct route_node *rn; + u_char buf[INET_ADDRSTRLEN]; + + /* `network area' print. */ + for (rn = route_top (ospf_top->networks); rn; rn = route_next (rn)) + if (rn->info) + { + struct ospf_network *n = rn->info; + + memset (buf, 0, INET_ADDRSTRLEN); + + /* Create Area ID string by specified Area ID format. */ + if (n->format == OSPF_AREA_ID_FORMAT_ADDRESS) + strncpy (buf, inet_ntoa (n->area_id), INET_ADDRSTRLEN); + else + sprintf (buf, "%lu", + (unsigned long int) ntohl (n->area_id.s_addr)); + + /* Network print. */ + vty_out (vty, " network %s/%d area %s%s", + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, + buf, VTY_NEWLINE); + } + + return 0; +} + +int +config_write_ospf_area (struct vty *vty) +{ + listnode node; + u_char buf[INET_ADDRSTRLEN]; + + /* Area configuration print. */ + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + struct ospf_area *area = getdata (node); + struct route_node *rn1; + + area_id2str (buf, INET_ADDRSTRLEN, area); + + if (area->auth_type != OSPF_AUTH_NULL) + { + if (area->auth_type == OSPF_AUTH_SIMPLE) + vty_out (vty, " area %s authentication%s", buf, VTY_NEWLINE); + else + vty_out (vty, " area %s authentication message-digest%s", + buf, VTY_NEWLINE); + } + + if (area->shortcut_configured != OSPF_SHORTCUT_DEFAULT) + vty_out (vty, " area %s shortcut %s%s", buf, + ospf_shortcut_mode_str[area->shortcut_configured], + VTY_NEWLINE); + + if ((area->external_routing == OSPF_AREA_STUB) +#ifdef HAVE_NSSA + || (area->external_routing == OSPF_AREA_NSSA) +#endif /* HAVE_NSSA */ + ) + { +#ifdef HAVE_NSSA + if (area->external_routing == OSPF_AREA_NSSA) + vty_out (vty, " area %s nssa", buf); + else +#endif /* HAVE_NSSA */ + vty_out (vty, " area %s stub", buf); + + if (area->no_summary) + vty_out (vty, " no-summary"); + + vty_out (vty, "%s", VTY_NEWLINE); + + if (area->default_cost != 1) + vty_out (vty, " area %s default-cost %d%s", buf, + area->default_cost, VTY_NEWLINE); + } + + for (rn1 = route_top (area->ranges); rn1; rn1 = route_next (rn1)) + if (rn1->info) + { + struct ospf_area_range *range = rn1->info; + + vty_out (vty, " area %s range %s/%d", buf, + inet_ntoa (rn1->p.u.prefix4), rn1->p.prefixlen); + + if (range->cost_config != -1) + vty_out (vty, " cost %d", range->cost_config); + + if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE)) + vty_out (vty, " not-advertise"); + + if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) + vty_out (vty, " substitute %s/%d", + inet_ntoa (range->subst_addr), range->subst_masklen); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + if (EXPORT_NAME (area)) + vty_out (vty, " area %s export-list %s%s", buf, + EXPORT_NAME (area), VTY_NEWLINE); + + if (IMPORT_NAME (area)) + vty_out (vty, " area %s import-list %s%s", buf, + IMPORT_NAME (area), VTY_NEWLINE); + + if (PREFIX_NAME_IN (area)) + vty_out (vty, " area %s filter-list prefix %s in%s", buf, + PREFIX_NAME_IN (area), VTY_NEWLINE); + + if (PREFIX_NAME_OUT (area)) + vty_out (vty, " area %s filter-list prefix %s out%s", buf, + PREFIX_NAME_OUT (area), VTY_NEWLINE); + } + + return 0; +} + +int +config_write_ospf_nbr_nbma (struct vty *vty) +{ + struct ospf_nbr_nbma *nbr_nbma; + struct route_node *rn; + + /* Static Neighbor configuration print. */ + for (rn = route_top (ospf_top->nbr_nbma); rn; rn = route_next (rn)) + if ((nbr_nbma = rn->info)) + { + vty_out (vty, " neighbor %s", inet_ntoa (nbr_nbma->addr)); + + if (nbr_nbma->priority != OSPF_NEIGHBOR_PRIORITY_DEFAULT) + vty_out (vty, " priority %d", nbr_nbma->priority); + + if (nbr_nbma->v_poll != OSPF_POLL_INTERVAL_DEFAULT) + vty_out (vty, " poll-interval %d", nbr_nbma->v_poll); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + return 0; +} + +int +config_write_virtual_link (struct vty *vty) +{ + listnode node; + u_char buf[INET_ADDRSTRLEN]; + + /* Virtual-Link print */ + for (node = listhead (ospf_top->vlinks); node; nextnode (node)) + { + listnode n2; + struct crypt_key *ck; + struct ospf_vl_data *vl_data = getdata (node); + struct ospf_interface *oi; + + if (vl_data != NULL) + { + memset (buf, 0, INET_ADDRSTRLEN); + + if (vl_data->format == OSPF_AREA_ID_FORMAT_ADDRESS) + strncpy (buf, inet_ntoa (vl_data->vl_area_id), INET_ADDRSTRLEN); + else + sprintf (buf, "%lu", + (unsigned long int) ntohl (vl_data->vl_area_id.s_addr)); + oi = vl_data->vl_oi; + + /* timers */ + if (OSPF_IF_PARAM (oi, v_hello) != OSPF_HELLO_INTERVAL_DEFAULT || + OSPF_IF_PARAM (oi, v_wait) != OSPF_ROUTER_DEAD_INTERVAL_DEFAULT || + OSPF_IF_PARAM (oi, retransmit_interval) != OSPF_RETRANSMIT_INTERVAL_DEFAULT || + OSPF_IF_PARAM (oi, transmit_delay) != OSPF_TRANSMIT_DELAY_DEFAULT) + vty_out (vty, " area %s virtual-link %s hello-interval %d retransmit-interval %d transmit-delay %d dead-interval %d%s", + buf, + inet_ntoa (vl_data->vl_peer), + OSPF_IF_PARAM (oi, v_hello), + OSPF_IF_PARAM (oi, retransmit_interval), + OSPF_IF_PARAM (oi, transmit_delay), + OSPF_IF_PARAM (oi, v_wait), + VTY_NEWLINE); + else + vty_out (vty, " area %s virtual-link %s%s", buf, + inet_ntoa (vl_data->vl_peer), VTY_NEWLINE); + /* Auth key */ + if (IF_DEF_PARAMS (vl_data->vl_oi->ifp)->auth_simple[0] != '\0') + vty_out (vty, " area %s virtual-link %s authentication-key %s%s", + buf, + inet_ntoa (vl_data->vl_peer), + IF_DEF_PARAMS (vl_data->vl_oi->ifp)->auth_simple, + VTY_NEWLINE); + /* md5 keys */ + for (n2 = listhead (IF_DEF_PARAMS (vl_data->vl_oi->ifp)->auth_crypt); n2; nextnode (n2)) + { + ck = getdata (n2); + vty_out (vty, " area %s virtual-link %s message-digest-key %d md5 %s%s", + buf, + inet_ntoa (vl_data->vl_peer), + ck->key_id, ck->auth_key, VTY_NEWLINE); + } + + } + } + + return 0; +} + + +char *distribute_str[] = { "system", "kernel", "connected", "static", "rip", + "ripng", "ospf", "ospf6", "bgp"}; +int +config_write_ospf_redistribute (struct vty *vty) +{ + int type; + + /* redistribute print. */ + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) + if (type != zclient->redist_default && zclient->redist[type]) + { + vty_out (vty, " redistribute %s", distribute_str[type]); + if (ospf_top->dmetric[type].value >= 0) + vty_out (vty, " metric %d", ospf_top->dmetric[type].value); + + if (ospf_top->dmetric[type].type == EXTERNAL_METRIC_TYPE_1) + vty_out (vty, " metric-type 1"); + + if (ROUTEMAP_NAME (type)) + vty_out (vty, " route-map %s", ROUTEMAP_NAME (type)); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + return 0; +} + +int +config_write_ospf_default_metric (struct vty *vty) +{ + if (ospf_top->default_metric != -1) + vty_out (vty, " default-metric %d%s", ospf_top->default_metric, + VTY_NEWLINE); + return 0; +} + +int +config_write_ospf_distribute (struct vty *vty) +{ + int type; + + if (ospf_top) + { + /* distribute-list print. */ + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) + if (ospf_top->dlist[type].name) + vty_out (vty, " distribute-list %s out %s%s", + ospf_top->dlist[type].name, + distribute_str[type], VTY_NEWLINE); + + /* default-information print. */ + if (ospf_top->default_originate != DEFAULT_ORIGINATE_NONE) + { + if (ospf_top->default_originate == DEFAULT_ORIGINATE_ZEBRA) + vty_out (vty, " default-information originate"); + else + vty_out (vty, " default-information originate always"); + + if (ospf_top->dmetric[DEFAULT_ROUTE].value >= 0) + vty_out (vty, " metric %d", + ospf_top->dmetric[DEFAULT_ROUTE].value); + if (ospf_top->dmetric[DEFAULT_ROUTE].type == EXTERNAL_METRIC_TYPE_1) + vty_out (vty, " metric-type 1"); + + if (ROUTEMAP_NAME (DEFAULT_ROUTE)) + vty_out (vty, " route-map %s", ROUTEMAP_NAME (DEFAULT_ROUTE)); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + } + + return 0; +} + +int +config_write_ospf_distance (struct vty *vty) +{ + struct route_node *rn; + struct ospf_distance *odistance; + + if (ospf_top->distance_all) + vty_out (vty, " distance %d%s", ospf_top->distance_all, VTY_NEWLINE); + + if (ospf_top->distance_intra + || ospf_top->distance_inter + || ospf_top->distance_external) + { + vty_out (vty, " distance ospf"); + + if (ospf_top->distance_intra) + vty_out (vty, " intra-area %d", ospf_top->distance_intra); + if (ospf_top->distance_inter) + vty_out (vty, " inter-area %d", ospf_top->distance_inter); + if (ospf_top->distance_external) + vty_out (vty, " external %d", ospf_top->distance_external); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + for (rn = route_top (ospf_top->distance_table); rn; rn = route_next (rn)) + if ((odistance = rn->info) != NULL) + { + vty_out (vty, " distance %d %s/%d %s%s", odistance->distance, + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, + odistance->access_list ? odistance->access_list : "", + VTY_NEWLINE); + } + return 0; +} + +/* OSPF configuration write function. */ +int +ospf_config_write (struct vty *vty) +{ + listnode node; + int write = 0; + + if (ospf_top != NULL) + { + /* `router ospf' print. */ + vty_out (vty, "router ospf%s", VTY_NEWLINE); + + write++; + + if (!ospf_top->networks) + return write; + + /* Router ID print. */ + if (ospf_top->router_id_static.s_addr != 0) + vty_out (vty, " ospf router-id %s%s", + inet_ntoa (ospf_top->router_id_static), VTY_NEWLINE); + + /* ABR type print. */ + if (ospf_top->abr_type != OSPF_ABR_STAND) + vty_out (vty, " ospf abr-type %s%s", + ospf_abr_type_str[ospf_top->abr_type], VTY_NEWLINE); + + /* RFC1583 compatibility flag print -- Compatible with CISCO 12.1. */ + if (CHECK_FLAG (ospf_top->config, OSPF_RFC1583_COMPATIBLE)) + vty_out (vty, " compatible rfc1583%s", VTY_NEWLINE); + + /* auto-cost reference-bandwidth configuration. */ + if (ospf_top->ref_bandwidth != OSPF_DEFAULT_REF_BANDWIDTH) + vty_out (vty, " auto-cost reference-bandwidth %d%s", + ospf_top->ref_bandwidth / 1000, VTY_NEWLINE); + + /* SPF timers print. */ + if (ospf_top->spf_delay != OSPF_SPF_DELAY_DEFAULT || + ospf_top->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT) + vty_out (vty, " timers spf %d %d%s", + ospf_top->spf_delay, ospf_top->spf_holdtime, VTY_NEWLINE); + + /* SPF refresh parameters print. */ + if (ospf_top->lsa_refresh_interval != OSPF_LSA_REFRESH_INTERVAL_DEFAULT) + vty_out (vty, " refresh timer %d%s", + ospf_top->lsa_refresh_interval, VTY_NEWLINE); + + /* Redistribute information print. */ + config_write_ospf_redistribute (vty); + + /* passive-interface print. */ + for (node = listhead (ospf_top->iflist); node; nextnode (node)) + { + struct interface *ifp = getdata (node); + + if (!ifp) + continue; + if (IF_DEF_PARAMS (ifp)->passive_interface == OSPF_IF_PASSIVE) + vty_out (vty, " passive-interface %s%s", + ifp->name, VTY_NEWLINE); + } + + for (node = listhead (ospf_top->oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + + if (OSPF_IF_PARAM_CONFIGURED (oi->params, passive_interface) && + oi->params->passive_interface == OSPF_IF_PASSIVE) + vty_out (vty, " passive-interface %s%s", + inet_ntoa (oi->address->u.prefix4), VTY_NEWLINE); + } + + + /* Network area print. */ + config_write_network_area (vty); + + /* Area config print. */ + config_write_ospf_area (vty); + + /* static neighbor print. */ + config_write_ospf_nbr_nbma (vty); + + /* Virtual-Link print. */ + config_write_virtual_link (vty); + + /* Default metric configuration. */ + config_write_ospf_default_metric (vty); + + /* Distribute-list and default-information print. */ + config_write_ospf_distribute (vty); + + /* Distance configuration. */ + config_write_ospf_distance (vty); + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_config_write_router (vty, ospf_top); +#endif /* HAVE_OPAQUE_LSA */ + } + + return write; +} + +void +ospf_vty_show_init () +{ + /* "show ip ospf" commands. */ + install_element (VIEW_NODE, &show_ip_ospf_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_cmd); + + /* "show ip ospf database" commands. */ + install_element (VIEW_NODE, &show_ip_ospf_database_type_cmd); + install_element (VIEW_NODE, &show_ip_ospf_database_type_id_cmd); + install_element (VIEW_NODE, &show_ip_ospf_database_type_id_adv_router_cmd); + install_element (VIEW_NODE, &show_ip_ospf_database_type_adv_router_cmd); + install_element (VIEW_NODE, &show_ip_ospf_database_type_id_self_cmd); + install_element (VIEW_NODE, &show_ip_ospf_database_type_self_cmd); + install_element (VIEW_NODE, &show_ip_ospf_database_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_database_type_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_adv_router_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_database_type_adv_router_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_self_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_database_type_self_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_database_cmd); + + /* "show ip ospf interface" commands. */ + install_element (VIEW_NODE, &show_ip_ospf_interface_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_interface_cmd); + + /* "show ip ospf neighbor" commands. */ + install_element (VIEW_NODE, &show_ip_ospf_neighbor_int_detail_cmd); + install_element (VIEW_NODE, &show_ip_ospf_neighbor_int_cmd); + install_element (VIEW_NODE, &show_ip_ospf_neighbor_id_cmd); + install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_all_cmd); + install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_cmd); + install_element (VIEW_NODE, &show_ip_ospf_neighbor_cmd); + install_element (VIEW_NODE, &show_ip_ospf_neighbor_all_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_int_detail_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_int_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_id_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_all_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_all_cmd); + + /* "show ip ospf route" commands. */ + install_element (VIEW_NODE, &show_ip_ospf_route_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_route_cmd); +#ifdef HAVE_NSSA + install_element (VIEW_NODE, &show_ip_ospf_border_routers_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_border_routers_cmd); +#endif /* HAVE_NSSA */ +} + + +/* ospfd's interface node. */ +struct cmd_node interface_node = +{ + INTERFACE_NODE, + "%s(config-if)# ", + 1 +}; + +/* Initialization of OSPF interface. */ +void +ospf_vty_if_init () +{ + /* Install interface node. */ + install_node (&interface_node, config_write_interface); + + install_element (CONFIG_NODE, &interface_cmd); + install_default (INTERFACE_NODE); + + /* "description" commands. */ + install_element (INTERFACE_NODE, &interface_desc_cmd); + install_element (INTERFACE_NODE, &no_interface_desc_cmd); + + /* "ip ospf authentication" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_authentication_args_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_authentication_args_cmd); + install_element (INTERFACE_NODE, &ip_ospf_authentication_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_authentication_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_authentication_addr_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_authentication_cmd); + install_element (INTERFACE_NODE, &ip_ospf_authentication_key_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_authentication_key_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_authentication_key_addr_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_authentication_key_cmd); + + /* "ip ospf message-digest-key" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_message_digest_key_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_message_digest_key_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_message_digest_key_addr_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_message_digest_key_cmd); + + /* "ip ospf cost" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_cost_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_cost_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_cost_addr_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_cost_cmd); + + /* "ip ospf dead-interval" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_dead_interval_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_dead_interval_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_addr_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_cmd); + + /* "ip ospf hello-interval" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_hello_interval_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_hello_interval_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_addr_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_cmd); + + /* "ip ospf network" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_network_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_network_cmd); + + /* "ip ospf priority" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_priority_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_priority_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_priority_addr_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_priority_cmd); + + /* "ip ospf retransmit-interval" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_addr_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_cmd); + + /* "ip ospf transmit-delay" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_cmd); + + /* These commands are compatibitliy for previous version. */ + install_element (INTERFACE_NODE, &ospf_authentication_key_cmd); + install_element (INTERFACE_NODE, &no_ospf_authentication_key_cmd); + install_element (INTERFACE_NODE, &ospf_message_digest_key_cmd); + install_element (INTERFACE_NODE, &no_ospf_message_digest_key_cmd); + install_element (INTERFACE_NODE, &ospf_cost_cmd); + install_element (INTERFACE_NODE, &no_ospf_cost_cmd); + install_element (INTERFACE_NODE, &ospf_dead_interval_cmd); + install_element (INTERFACE_NODE, &no_ospf_dead_interval_cmd); + install_element (INTERFACE_NODE, &ospf_hello_interval_cmd); + install_element (INTERFACE_NODE, &no_ospf_hello_interval_cmd); + install_element (INTERFACE_NODE, &ospf_network_cmd); + install_element (INTERFACE_NODE, &no_ospf_network_cmd); + install_element (INTERFACE_NODE, &ospf_priority_cmd); + install_element (INTERFACE_NODE, &no_ospf_priority_cmd); + install_element (INTERFACE_NODE, &ospf_retransmit_interval_cmd); + install_element (INTERFACE_NODE, &no_ospf_retransmit_interval_cmd); + install_element (INTERFACE_NODE, &ospf_transmit_delay_cmd); + install_element (INTERFACE_NODE, &no_ospf_transmit_delay_cmd); +} + +/* Zebra node structure. */ +struct cmd_node zebra_node = +{ + ZEBRA_NODE, + "%s(config-router)#", +}; + +void +ospf_vty_zebra_init () +{ + install_element (OSPF_NODE, &ospf_redistribute_source_type_metric_cmd); + install_element (OSPF_NODE, &ospf_redistribute_source_metric_type_cmd); + install_element (OSPF_NODE, &ospf_redistribute_source_type_cmd); + install_element (OSPF_NODE, &ospf_redistribute_source_metric_cmd); + install_element (OSPF_NODE, &ospf_redistribute_source_cmd); + install_element (OSPF_NODE, + &ospf_redistribute_source_metric_type_routemap_cmd); + install_element (OSPF_NODE, + &ospf_redistribute_source_type_metric_routemap_cmd); + install_element (OSPF_NODE, &ospf_redistribute_source_metric_routemap_cmd); + install_element (OSPF_NODE, &ospf_redistribute_source_type_routemap_cmd); + install_element (OSPF_NODE, &ospf_redistribute_source_routemap_cmd); + + install_element (OSPF_NODE, &no_ospf_redistribute_source_cmd); + + install_element (OSPF_NODE, &ospf_distribute_list_out_cmd); + install_element (OSPF_NODE, &no_ospf_distribute_list_out_cmd); + + install_element (OSPF_NODE, + &ospf_default_information_originate_metric_type_cmd); + install_element (OSPF_NODE, &ospf_default_information_originate_metric_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_type_metric_cmd); + install_element (OSPF_NODE, &ospf_default_information_originate_type_cmd); + install_element (OSPF_NODE, &ospf_default_information_originate_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_metric_type_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_metric_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_type_metric_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_type_cmd); + + install_element (OSPF_NODE, + &ospf_default_information_originate_metric_type_routemap_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_metric_routemap_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_routemap_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_type_metric_routemap_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_type_routemap_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_metric_type_routemap_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_metric_routemap_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_routemap_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_type_metric_routemap_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_type_routemap_cmd); + + install_element (OSPF_NODE, &no_ospf_default_information_originate_cmd); + + install_element (OSPF_NODE, &ospf_default_metric_cmd); + install_element (OSPF_NODE, &no_ospf_default_metric_cmd); + install_element (OSPF_NODE, &no_ospf_default_metric_val_cmd); + + install_element (OSPF_NODE, &ospf_distance_cmd); + install_element (OSPF_NODE, &no_ospf_distance_cmd); + install_element (OSPF_NODE, &no_ospf_distance_ospf_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_intra_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_intra_inter_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_intra_external_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_intra_inter_external_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_intra_external_inter_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_inter_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_inter_intra_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_inter_external_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_inter_intra_external_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_inter_external_intra_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_external_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_external_intra_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_external_inter_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_external_intra_inter_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_external_inter_intra_cmd); +#if 0 + install_element (OSPF_NODE, &ospf_distance_source_cmd); + install_element (OSPF_NODE, &no_ospf_distance_source_cmd); + install_element (OSPF_NODE, &ospf_distance_source_access_list_cmd); + install_element (OSPF_NODE, &no_ospf_distance_source_access_list_cmd); +#endif /* 0 */ +} + +struct cmd_node ospf_node = +{ + OSPF_NODE, + "%s(config-router)# ", + 1 +}; + + +/* Install OSPF related vty commands. */ +void +ospf_vty_init () +{ + /* Install ospf top node. */ + install_node (&ospf_node, ospf_config_write); + + /* "router ospf" commands. */ + install_element (CONFIG_NODE, &router_ospf_cmd); + install_element (CONFIG_NODE, &no_router_ospf_cmd); + + install_default (OSPF_NODE); + + /* "ospf router-id" commands. */ + install_element (OSPF_NODE, &ospf_router_id_cmd); + install_element (OSPF_NODE, &no_ospf_router_id_cmd); + install_element (OSPF_NODE, &router_id_cmd); + install_element (OSPF_NODE, &no_router_id_cmd); + + /* "passive-interface" commands. */ + install_element (OSPF_NODE, &passive_interface_addr_cmd); + install_element (OSPF_NODE, &passive_interface_cmd); + install_element (OSPF_NODE, &no_passive_interface_addr_cmd); + install_element (OSPF_NODE, &no_passive_interface_cmd); + + /* "ospf abr-type" commands. */ + install_element (OSPF_NODE, &ospf_abr_type_cmd); + install_element (OSPF_NODE, &no_ospf_abr_type_cmd); + + /* "ospf rfc1583-compatible" commands. */ + install_element (OSPF_NODE, &ospf_rfc1583_flag_cmd); + install_element (OSPF_NODE, &no_ospf_rfc1583_flag_cmd); + install_element (OSPF_NODE, &ospf_compatible_rfc1583_cmd); + install_element (OSPF_NODE, &no_ospf_compatible_rfc1583_cmd); + + /* "network area" commands. */ + install_element (OSPF_NODE, &network_area_cmd); + install_element (OSPF_NODE, &no_network_area_cmd); + + /* "area authentication" commands. */ + install_element (OSPF_NODE, &area_authentication_message_digest_cmd); + install_element (OSPF_NODE, &area_authentication_cmd); + install_element (OSPF_NODE, &no_area_authentication_cmd); + + /* "area range" commands. */ + install_element (OSPF_NODE, &area_range_cmd); + install_element (OSPF_NODE, &area_range_advertise_cmd); + install_element (OSPF_NODE, &area_range_cost_cmd); + install_element (OSPF_NODE, &area_range_advertise_cost_cmd); + install_element (OSPF_NODE, &area_range_not_advertise_cmd); + install_element (OSPF_NODE, &no_area_range_cmd); + install_element (OSPF_NODE, &no_area_range_advertise_cmd); + install_element (OSPF_NODE, &no_area_range_cost_cmd); + install_element (OSPF_NODE, &no_area_range_advertise_cost_cmd); + install_element (OSPF_NODE, &area_range_substitute_cmd); + install_element (OSPF_NODE, &no_area_range_substitute_cmd); + + /* "area virtual-link" commands. */ + install_element (OSPF_NODE, &area_vlink_cmd); + install_element (OSPF_NODE, &no_area_vlink_cmd); + + install_element (OSPF_NODE, &area_vlink_param1_cmd); + install_element (OSPF_NODE, &no_area_vlink_param1_cmd); + + install_element (OSPF_NODE, &area_vlink_param2_cmd); + install_element (OSPF_NODE, &no_area_vlink_param2_cmd); + + install_element (OSPF_NODE, &area_vlink_param3_cmd); + install_element (OSPF_NODE, &no_area_vlink_param3_cmd); + + install_element (OSPF_NODE, &area_vlink_param4_cmd); + install_element (OSPF_NODE, &no_area_vlink_param4_cmd); + + install_element (OSPF_NODE, &area_vlink_authtype_args_cmd); + install_element (OSPF_NODE, &area_vlink_authtype_cmd); + install_element (OSPF_NODE, &no_area_vlink_authtype_cmd); + + install_element (OSPF_NODE, &area_vlink_md5_cmd); + install_element (OSPF_NODE, &no_area_vlink_md5_cmd); + + install_element (OSPF_NODE, &area_vlink_authkey_cmd); + install_element (OSPF_NODE, &no_area_vlink_authkey_cmd); + + install_element (OSPF_NODE, &area_vlink_authtype_args_authkey_cmd); + install_element (OSPF_NODE, &area_vlink_authtype_authkey_cmd); + install_element (OSPF_NODE, &no_area_vlink_authtype_authkey_cmd); + + install_element (OSPF_NODE, &area_vlink_authtype_args_md5_cmd); + install_element (OSPF_NODE, &area_vlink_authtype_md5_cmd); + install_element (OSPF_NODE, &no_area_vlink_authtype_md5_cmd); + + /* "area stub" commands. */ + install_element (OSPF_NODE, &area_stub_no_summary_cmd); + install_element (OSPF_NODE, &area_stub_cmd); + install_element (OSPF_NODE, &no_area_stub_no_summary_cmd); + install_element (OSPF_NODE, &no_area_stub_cmd); + +#ifdef HAVE_NSSA + /* "area nssa" commands. */ + install_element (OSPF_NODE, &area_nssa_cmd); + install_element (OSPF_NODE, &area_nssa_translate_no_summary_cmd); + install_element (OSPF_NODE, &area_nssa_translate_cmd); + install_element (OSPF_NODE, &area_nssa_no_summary_cmd); + install_element (OSPF_NODE, &no_area_nssa_cmd); + install_element (OSPF_NODE, &no_area_nssa_no_summary_cmd); +#endif /* HAVE_NSSA */ + + install_element (OSPF_NODE, &area_default_cost_cmd); + install_element (OSPF_NODE, &no_area_default_cost_cmd); + + install_element (OSPF_NODE, &area_shortcut_cmd); + install_element (OSPF_NODE, &no_area_shortcut_cmd); + + install_element (OSPF_NODE, &area_export_list_cmd); + install_element (OSPF_NODE, &no_area_export_list_cmd); + + install_element (OSPF_NODE, &area_filter_list_cmd); + install_element (OSPF_NODE, &no_area_filter_list_cmd); + + install_element (OSPF_NODE, &area_import_list_cmd); + install_element (OSPF_NODE, &no_area_import_list_cmd); + + install_element (OSPF_NODE, &timers_spf_cmd); + install_element (OSPF_NODE, &no_timers_spf_cmd); + + install_element (OSPF_NODE, &refresh_timer_cmd); + install_element (OSPF_NODE, &no_refresh_timer_val_cmd); + install_element (OSPF_NODE, &no_refresh_timer_cmd); + + install_element (OSPF_NODE, &auto_cost_reference_bandwidth_cmd); + install_element (OSPF_NODE, &no_auto_cost_reference_bandwidth_cmd); + + /* "neighbor" commands. */ + install_element (OSPF_NODE, &neighbor_cmd); + install_element (OSPF_NODE, &neighbor_priority_poll_interval_cmd); + install_element (OSPF_NODE, &neighbor_priority_cmd); + install_element (OSPF_NODE, &neighbor_poll_interval_cmd); + install_element (OSPF_NODE, &neighbor_poll_interval_priority_cmd); + install_element (OSPF_NODE, &no_neighbor_cmd); + install_element (OSPF_NODE, &no_neighbor_priority_cmd); + install_element (OSPF_NODE, &no_neighbor_poll_interval_cmd); + + /* Init interface related vty commands. */ + ospf_vty_if_init (); + + /* Init zebra related vty commands. */ + ospf_vty_zebra_init (); +} + diff --git a/ospfd/ospf_vty.h b/ospfd/ospf_vty.h new file mode 100644 index 00000000..9f30e204 --- /dev/null +++ b/ospfd/ospf_vty.h @@ -0,0 +1,85 @@ +/* OSPF VTY interface. + * Copyright (C) 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* Macros. */ +#define VTY_GET_UINT32(NAME,V,STR) \ +{ \ + char *endptr = NULL; \ + (V) = strtoul ((STR), &endptr, 10); \ + if (*endptr != '\0' || ((V) == ULONG_MAX && errno == ERANGE)) \ + { \ + vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ +} + +#define VTY_GET_IPV4_ADDRESS(NAME,V,STR) \ +{ \ + int retv; \ + retv = inet_aton ((STR), &(V)); \ + if (!retv) \ + { \ + vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ +} + +#define VTY_GET_IPV4_PREFIX(NAME,V,STR) \ +{ \ + int retv; \ + retv = str2prefix_ipv4 ((STR), &(V)); \ + if (retv <= 0) \ + { \ + vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ +} + +#define VTY_GET_OSPF_AREA_ID(V,F,STR) \ +{ \ + int retv; \ + retv = ospf_str2area_id ((STR), &(V), &(F)); \ + if (retv < 0) \ + { \ + vty_out (vty, "%% Invalid OSPF area ID%s", VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ +} + +#define VTY_GET_OSPF_AREA_ID_NO_BB(NAME,V,F,STR) \ +{ \ + int retv; \ + retv = ospf_str2area_id ((STR), &(V), &(F)); \ + if (retv < 0) \ + { \ + vty_out (vty, "%% Invalid OSPF area ID%s", VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ + if (OSPF_IS_AREA_ID_BACKBONE ((V))) \ + { \ + vty_out (vty, "%% You can't configure %s to backbone%s", \ + NAME, VTY_NEWLINE); \ + } \ +} + +/* Prototypes. */ +void ospf_vty_init (); +void ospf_vty_show_init (); diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c new file mode 100644 index 00000000..1ad31f29 --- /dev/null +++ b/ospfd/ospf_zebra.c @@ -0,0 +1,1180 @@ +/* + * Zebra connect library for OSPFd + * Copyright (C) 1997, 98, 99, 2000 Kunihiro Ishiguro, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "thread.h" +#include "command.h" +#include "network.h" +#include "prefix.h" +#include "routemap.h" +#include "table.h" +#include "stream.h" +#include "memory.h" +#include "zclient.h" +#include "filter.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_zebra.h" +#ifdef HAVE_SNMP +#include "ospfd/ospf_snmp.h" +#endif /* HAVE_SNMP */ + +/* Zebra structure to hold current status. */ +struct zclient *zclient = NULL; + +/* For registering threads. */ +extern struct thread_master *master; + +/* Inteface addition message from zebra. */ +int +ospf_interface_add (int command, struct zclient *zclient, zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_add_read (zclient->ibuf); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + zlog_info ("Zebra: interface add %s index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + if (!OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), type)) + { + SET_IF_PARAM (IF_DEF_PARAMS (ifp), type); + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST; + + if (if_is_broadcast (ifp)) + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST; + else if (if_is_pointopoint (ifp)) + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_POINTOPOINT; + else if (if_is_loopback (ifp)) + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_LOOPBACK; + } + + ospf_if_update (); + +#ifdef HAVE_SNMP + ospf_snmp_if_update (ifp); +#endif /* HAVE_SNMP */ + + return 0; +} + +int +ospf_interface_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + struct stream *s; + struct route_node *rn; + + s = zclient->ibuf; + /* zebra_interface_state_read() updates interface structure in iflist */ + ifp = zebra_interface_state_read (s); + + if (ifp == NULL) + return 0; + + if (if_is_up (ifp)) + zlog_warn ("Zebra: got delete of %s, but interface is still up", + ifp->name); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + zlog_info ("Zebra: interface delete %s index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + +#ifdef HAVE_SNMP + ospf_snmp_if_delete (ifp); +#endif /* HAVE_SNMP */ + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + if (rn->info) + ospf_if_free ((struct ospf_interface *) rn->info); + + for (rn = route_top (IF_OIFS_PARAMS (ifp)); rn; rn = route_next (rn)) + if (rn->info) + ospf_del_if_params (rn->info); + + if_delete (ifp); + + return 0; +} + +struct interface * +zebra_interface_if_lookup (struct stream *s) +{ + struct interface *ifp; + u_char ifname_tmp[INTERFACE_NAMSIZ]; + + /* Read interface name. */ + stream_get (ifname_tmp, s, INTERFACE_NAMSIZ); + + /* Lookup this by interface index. */ + ifp = if_lookup_by_name (ifname_tmp); + + /* If such interface does not exist, indicate an error */ + if (!ifp) + return NULL; + + return ifp; +} + +void +zebra_interface_if_set_value (struct stream *s, struct interface *ifp) +{ + /* Read interface's index. */ + ifp->ifindex = stream_getl (s); + + /* Read interface's value. */ + ifp->flags = stream_getl (s); + ifp->metric = stream_getl (s); + ifp->mtu = stream_getl (s); + ifp->bandwidth = stream_getl (s); +} + +int +ospf_interface_state_up (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + struct interface if_tmp; + struct ospf_interface *oi; + struct route_node *rn; + + ifp = zebra_interface_if_lookup (zclient->ibuf); + + if (ifp == NULL) + return 0; + + /* Interface is already up. */ + if (if_is_up (ifp)) + { + /* Temporarily keep ifp values. */ + memcpy (&if_tmp, ifp, sizeof (struct interface)); + + zebra_interface_if_set_value (zclient->ibuf, ifp); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + zlog_info ("Zebra: Interface[%s] state update.", ifp->name); + + if (if_tmp.bandwidth != ifp->bandwidth) + { + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + zlog_info ("Zebra: Interface[%s] bandwidth change %d -> %d.", + ifp->name, if_tmp.bandwidth, ifp->bandwidth); + + ospf_if_recalculate_output_cost (ifp); + } + return 0; + } + + zebra_interface_if_set_value (zclient->ibuf, ifp); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + zlog_info ("Zebra: Interface[%s] state change to up.", ifp->name); + + for (rn = route_top (IF_OIFS (ifp));rn; rn = route_next (rn)) + { + if ( (oi = rn->info) == NULL) + continue; + + ospf_if_up (oi); + } + + return 0; +} + +int +ospf_interface_state_down (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + struct ospf_interface *oi; + struct route_node *node; + + ifp = zebra_interface_state_read (zclient->ibuf); + + if (ifp == NULL) + return 0; + + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + zlog_info ("Zebra: Interface[%s] state change to down.", ifp->name); + + for (node = route_top (IF_OIFS (ifp));node; node = route_next (node)) + { + if ( (oi = node->info) == NULL) + continue; + ospf_if_down (oi); + } + + return 0; +} + +int +ospf_interface_address_add (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *c; + + c = zebra_interface_address_add_read (zclient->ibuf); + + if (c == NULL) + return 0; + +#if 0 + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + { + struct prefix *p; + + p = c->address; + if (p->family == AF_INET) + zlog_info (" connected address %s/%d", + inet_atop (p->u.prefix4), p->prefixlen); + } +#endif + + ospf_if_update (); + +#ifdef HAVE_SNMP + ospf_snmp_if_update (c->ifp); +#endif /* HAVE_SNMP */ + + return 0; +} + +int +ospf_interface_address_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *c; + struct interface *ifp; + struct ospf_interface *oi; + struct route_node *rn; + struct prefix p; + + c = zebra_interface_address_delete_read (zclient->ibuf); + + if (c == NULL) + return 0; + + ifp = c->ifp; + p = *c->address; + p.prefixlen = IPV4_MAX_PREFIXLEN; + + rn = route_node_lookup (IF_OIFS (ifp), &p); + if (! rn) + return 0; + + assert (rn->info); + oi = rn->info; + + /* Call interface hook functions to clean up */ + ospf_if_free (oi); + +#ifdef HAVE_SNMP + ospf_snmp_if_update (c->ifp); +#endif /* HAVE_SNMP */ + + connected_free (c); + + ospf_if_update(); + + return 0; +} + +void +ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or) +{ + u_char message; + u_char distance; + u_char flags; + int psize; + struct stream *s; + struct ospf_path *path; + listnode node; + + if (zclient->redist[ZEBRA_ROUTE_OSPF]) + { + message = 0; + flags = 0; + + /* OSPF pass nexthop and metric */ + SET_FLAG (message, ZAPI_MESSAGE_NEXTHOP); + SET_FLAG (message, ZAPI_MESSAGE_METRIC); + + /* Distance value. */ + distance = ospf_distance_apply (p, or); + if (distance) + SET_FLAG (message, ZAPI_MESSAGE_DISTANCE); + + /* Make packet. */ + s = zclient->obuf; + stream_reset (s); + + /* Length place holder. */ + stream_putw (s, 0); + + /* Put command, type, flags, message. */ + stream_putc (s, ZEBRA_IPV4_ROUTE_ADD); + stream_putc (s, ZEBRA_ROUTE_OSPF); + stream_putc (s, flags); + stream_putc (s, message); + + /* Put prefix information. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *)&p->prefix, psize); + + /* Nexthop count. */ + stream_putc (s, or->path->count); + + /* Nexthop, ifindex, distance and metric information. */ + for (node = listhead (or->path); node; nextnode (node)) + { + path = getdata (node); + + if (path->nexthop.s_addr != INADDR_ANY) + { + stream_putc (s, ZEBRA_NEXTHOP_IPV4); + stream_put_in_addr (s, &path->nexthop); + } + else + { + stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); + if (path->oi) + stream_putl (s, path->oi->ifp->ifindex); + else + stream_putl (s, 0); + } + } + + if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE)) + stream_putc (s, distance); + if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC)) + { + if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL) + stream_putl (s, or->cost + or->u.ext.type2_cost); + else if (or->path_type == OSPF_PATH_TYPE2_EXTERNAL) + stream_putl (s, or->u.ext.type2_cost); + else + stream_putl (s, or->cost); + } + + stream_putw_at (s, 0, stream_get_endp (s)); + + writen (zclient->sock, s->data, stream_get_endp (s)); + +#if 0 + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + { + char *nexthop_str; + + nexthop_str = strdup (inet_ntoa (*nexthop)); + zlog_info ("Zebra: Route add %s/%d nexthop %s metric %d", + inet_ntoa (p->prefix), p->prefixlen, nexthop_str, + metric); + free (nexthop_str); + } +#endif /* 0 */ + } +} + +void +ospf_zebra_delete (struct prefix_ipv4 *p, struct ospf_route *or) +{ + struct zapi_ipv4 api; + + if (zclient->redist[ZEBRA_ROUTE_OSPF]) + { + api.type = ZEBRA_ROUTE_OSPF; + api.flags = 0; + api.message = 0; + zapi_ipv4_delete (zclient, p, &api); + +#if 0 + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + { + char *nexthop_str; + + nexthop_str = strdup (inet_ntoa (*nexthop)); + zlog_info ("Zebra: Route delete %s/%d nexthop %s", + inet_ntoa (p->prefix), p->prefixlen, nexthop_str); + free (nexthop_str); + } +#endif /* 0 */ + } +} + +void +ospf_zebra_add_discard (struct prefix_ipv4 *p) +{ + struct zapi_ipv4 api; + + if (zclient->redist[ZEBRA_ROUTE_OSPF]) + { + api.type = ZEBRA_ROUTE_OSPF; + api.flags = ZEBRA_FLAG_BLACKHOLE; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 0; + api.ifindex_num = 0; + + zapi_ipv4_add (zclient, p, &api); + } +} + +void +ospf_zebra_delete_discard (struct prefix_ipv4 *p) +{ + struct zapi_ipv4 api; + + if (zclient->redist[ZEBRA_ROUTE_OSPF]) + { + api.type = ZEBRA_ROUTE_OSPF; + api.flags = ZEBRA_FLAG_BLACKHOLE; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 0; + api.ifindex_num = 0; + + zapi_ipv4_delete (zclient, p, &api); + } +} + +int +ospf_is_type_redistributed (int type) +{ + return (DEFAULT_ROUTE_TYPE (type)) ? + zclient->default_information : zclient->redist[type]; +} + +int +ospf_redistribute_set (int type, int mtype, int mvalue) +{ + int force = 0; + + if (ospf_is_type_redistributed (type)) + { + if (mtype != ospf_top->dmetric[type].type) + { + ospf_top->dmetric[type].type = mtype; + force = LSA_REFRESH_FORCE; + } + if (mvalue != ospf_top->dmetric[type].value) + { + ospf_top->dmetric[type].value = mvalue; + force = LSA_REFRESH_FORCE; + } + + ospf_external_lsa_refresh_type (type, force); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[%s]: Refresh Type[%d], Metric[%d]", + LOOKUP (ospf_redistributed_proto, type), + metric_type (type), metric_value (type)); + + return CMD_SUCCESS; + } + + ospf_top->dmetric[type].type = mtype; + ospf_top->dmetric[type].value = mvalue; + + zclient_redistribute_set (zclient, type); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[%s]: Start Type[%d], Metric[%d]", + LOOKUP (ospf_redistributed_proto, type), + metric_type (type), metric_value (type)); + + ospf_asbr_status_update (++ospf_top->redistribute); + + return CMD_SUCCESS; +} + +int +ospf_redistribute_unset (int type) +{ + if (type == zclient->redist_default) + return CMD_SUCCESS; + + if (! ospf_is_type_redistributed (type)) + return CMD_SUCCESS; + + zclient_redistribute_unset (zclient, type); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[%s]: Stop", + LOOKUP (ospf_redistributed_proto, type)); + + ospf_top->dmetric[type].type = -1; + ospf_top->dmetric[type].value = -1; + + /* Remove the routes from OSPF table. */ + ospf_redistribute_withdraw (type); + + ospf_asbr_status_update (--ospf_top->redistribute); + + return CMD_SUCCESS; +} + +int +ospf_redistribute_default_set (int originate, int mtype, int mvalue) +{ + int force = 0; + if (ospf_is_type_redistributed (DEFAULT_ROUTE)) + { + if (mtype != ospf_top->dmetric[DEFAULT_ROUTE].type) + { + ospf_top->dmetric[DEFAULT_ROUTE].type = mtype; + force = 1; + } + if (mvalue != ospf_top->dmetric[DEFAULT_ROUTE].value) + { + force = 1; + ospf_top->dmetric[DEFAULT_ROUTE].value = mvalue; + } + + ospf_external_lsa_refresh_default (); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[%s]: Refresh Type[%d], Metric[%d]", + LOOKUP (ospf_redistributed_proto, DEFAULT_ROUTE), + metric_type (DEFAULT_ROUTE), + metric_value (DEFAULT_ROUTE)); + return CMD_SUCCESS; + } + + ospf_top->default_originate = originate; + ospf_top->dmetric[DEFAULT_ROUTE].type = mtype; + ospf_top->dmetric[DEFAULT_ROUTE].value = mvalue; + + zclient_redistribute_default_set (zclient); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[DEFAULT]: Start Type[%d], Metric[%d]", + metric_type (DEFAULT_ROUTE), metric_value (DEFAULT_ROUTE)); + + + if (ospf_top->router_id.s_addr == 0) + ospf_top->external_origin |= (1 << DEFAULT_ROUTE); + else + thread_add_timer (master, ospf_default_originate_timer, + &ospf_top->default_originate, 1); + + ospf_asbr_status_update (++ospf_top->redistribute); + + return CMD_SUCCESS; +} + +int +ospf_redistribute_default_unset () +{ + if (!ospf_is_type_redistributed (DEFAULT_ROUTE)) + return CMD_SUCCESS; + + ospf_top->default_originate = DEFAULT_ORIGINATE_NONE; + ospf_top->dmetric[DEFAULT_ROUTE].type = -1; + ospf_top->dmetric[DEFAULT_ROUTE].value = -1; + + zclient_redistribute_default_unset (zclient); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[DEFAULT]: Stop"); + + ospf_asbr_status_update (--ospf_top->redistribute); + + return CMD_SUCCESS; +} + +int +ospf_external_lsa_originate_check (struct external_info *ei) +{ + /* If prefix is multicast, then do not originate LSA. */ + if (IN_MULTICAST (htonl (ei->p.prefix.s_addr))) + { + zlog_info ("LSA[Type5:%s]: Not originate AS-external-LSA, " + "Prefix belongs multicast", inet_ntoa (ei->p.prefix)); + return 0; + } + + /* Take care of default-originate. */ + if (is_prefix_default (&ei->p)) + if (ospf_top->default_originate == DEFAULT_ORIGINATE_NONE) + { + zlog_info ("LSA[Type5:0.0.0.0]: Not originate AS-exntenal-LSA " + "for default"); + return 0; + } + + return 1; +} + +/* If connected prefix is OSPF enable interface, then do not announce. */ +int +ospf_distribute_check_connected (struct external_info *ei) +{ + struct route_node *rn; + + for (rn = route_top (ospf_top->networks); rn; rn = route_next (rn)) + if (rn->info != NULL) + if (prefix_match (&rn->p, (struct prefix *)&ei->p)) + return 0; + + return 1; +} + +/* return 1 if external LSA must be originated, 0 otherwise */ +int +ospf_redistribute_check (struct external_info *ei, int *changed) +{ + struct route_map_set_values save_values; + struct prefix_ipv4 *p = &ei->p; + u_char type = is_prefix_default (&ei->p) ? DEFAULT_ROUTE : ei->type; + + if (changed) + *changed = 0; + + if (!ospf_external_lsa_originate_check (ei)) + return 0; + + /* Take care connected route. */ + if (type == ZEBRA_ROUTE_CONNECT && !ospf_distribute_check_connected (ei)) + return 0; + + if (!DEFAULT_ROUTE_TYPE (type) && DISTRIBUTE_NAME (type)) + /* distirbute-list exists, but access-list may not? */ + if (DISTRIBUTE_LIST (type)) + if (access_list_apply (DISTRIBUTE_LIST (type), p) == FILTER_DENY) + { + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[%s]: %s/%d filtered by ditribute-list.", + LOOKUP (ospf_redistributed_proto, type), + inet_ntoa (p->prefix), p->prefixlen); + return 0; + } + + save_values = ei->route_map_set; + ospf_reset_route_map_set_values (&ei->route_map_set); + + /* apply route-map if needed */ + if (ROUTEMAP_NAME (type)) + { + int ret; + + ret = route_map_apply (ROUTEMAP (type), (struct prefix *)p, + RMAP_OSPF, ei); + + if (ret == RMAP_DENYMATCH) + { + ei->route_map_set = save_values; + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[%s]: %s/%d filtered by route-map.", + LOOKUP (ospf_redistributed_proto, type), + inet_ntoa (p->prefix), p->prefixlen); + return 0; + } + + /* check if 'route-map set' changed something */ + if (changed) + *changed = !ospf_route_map_set_compare (&ei->route_map_set, + &save_values); + } + + return 1; +} + +/* OSPF route-map set for redistribution */ +void +ospf_routemap_set (int type, char *name) +{ + if (ROUTEMAP_NAME (type)) + free (ROUTEMAP_NAME (type)); + + ROUTEMAP_NAME (type) = strdup (name); + ROUTEMAP (type) = route_map_lookup_by_name (name); +} + +void +ospf_routemap_unset (int type) +{ + if (ROUTEMAP_NAME (type)) + free (ROUTEMAP_NAME (type)); + + ROUTEMAP_NAME (type) = NULL; + ROUTEMAP (type) = NULL; +} + +/* Zebra route add and delete treatment. */ +int +ospf_zebra_read_ipv4 (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct stream *s; + struct zapi_ipv4 api; + unsigned long ifindex; + struct in_addr nexthop; + struct prefix_ipv4 p; + struct external_info *ei; + + s = zclient->ibuf; + ifindex = 0; + nexthop.s_addr = 0; + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.flags = stream_getc (s); + api.message = stream_getc (s); + + /* IPv4 prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = stream_getc (s); + stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + { + api.nexthop_num = stream_getc (s); + nexthop.s_addr = stream_get_ipv4 (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) + { + api.ifindex_num = stream_getc (s); + ifindex = stream_getl (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + + if (command == ZEBRA_IPV4_ROUTE_ADD) + { + ei = ospf_external_info_add (api.type, p, ifindex, nexthop); + + if (ospf_top->router_id.s_addr == 0) + /* Set flags to generate AS-external-LSA originate event + for each redistributed protocols later. */ + ospf_top->external_origin |= (1 << api.type); + else + { + if (ei) + { + if (is_prefix_default (&p)) + ospf_external_lsa_refresh_default (); + else + { + struct ospf_lsa *current; + + current = ospf_external_info_find_lsa (&ei->p); + if (!current) + ospf_external_lsa_originate (ei); + else if (IS_LSA_MAXAGE (current)) + ospf_external_lsa_refresh (current, ei, LSA_REFRESH_FORCE); + else + zlog_warn ("ospf_zebra_read_ipv4() : %s already exists", + inet_ntoa (p.prefix)); + } + } + } + } + else /* if (command == ZEBRA_IPV4_ROUTE_DELETE) */ + { + ospf_external_info_delete (api.type, p); + if ( !is_prefix_default (&p)) + ospf_external_lsa_flush (api.type, &p, ifindex, nexthop); + else + ospf_external_lsa_refresh_default (); + } + + return 0; +} + + +int +ospf_distribute_list_out_set (int type, char *name) +{ + /* Lookup access-list for distribute-list. */ + DISTRIBUTE_LIST (type) = access_list_lookup (AFI_IP, name); + + /* Clear previous distribute-name. */ + if (DISTRIBUTE_NAME (type)) + free (DISTRIBUTE_NAME (type)); + + /* Set distribute-name. */ + DISTRIBUTE_NAME (type) = strdup (name); + + /* If access-list have been set, schedule update timer. */ + if (DISTRIBUTE_LIST (type)) + ospf_distribute_list_update (type); + + return CMD_SUCCESS; +} + +int +ospf_distribute_list_out_unset (int type, char *name) +{ + /* Schedule update timer. */ + if (DISTRIBUTE_LIST (type)) + ospf_distribute_list_update (type); + + /* Unset distribute-list. */ + DISTRIBUTE_LIST (type) = NULL; + + /* Clear distribute-name. */ + if (DISTRIBUTE_NAME (type)) + free (DISTRIBUTE_NAME (type)); + + DISTRIBUTE_NAME (type) = NULL; + + return CMD_SUCCESS; +} + +/* distribute-list update timer. */ +int +ospf_distribute_list_update_timer (struct thread *thread) +{ + struct route_node *rn; + struct external_info *ei; + struct route_table *rt; + struct ospf_lsa *lsa; + u_char type; + + type = (int) THREAD_ARG (thread); + rt = EXTERNAL_INFO (type); + + ospf_top->t_distribute_update = NULL; + + zlog_info ("Zebra[Redistribute]: distribute-list update timer fired!"); + + /* foreach all external info. */ + if (rt) + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((ei = rn->info) != NULL) + { + if (is_prefix_default (&ei->p)) + ospf_external_lsa_refresh_default (); + else if ((lsa = ospf_external_info_find_lsa (&ei->p))) + ospf_external_lsa_refresh (lsa, ei, LSA_REFRESH_IF_CHANGED); + else + ospf_external_lsa_originate (ei); + } + return 0; +} + +#define OSPF_DISTRIBUTE_UPDATE_DELAY 5 + +/* Update distribute-list and set timer to apply access-list. */ +void +ospf_distribute_list_update (int type) +{ + struct route_table *rt; + + zlog_info ("ospf_distribute_list_update(): start"); + + /* External info does not exist. */ + if (!(rt = EXTERNAL_INFO (type))) + return; + + /* If exists previously invoked thread, then cancel it. */ + if (ospf_top->t_distribute_update) + OSPF_TIMER_OFF (ospf_top->t_distribute_update); + + /* Set timer. */ + ospf_top->t_distribute_update = + thread_add_timer (master, ospf_distribute_list_update_timer, + (void *) type, OSPF_DISTRIBUTE_UPDATE_DELAY); + + zlog_info ("ospf_distribute_list_update(): stop"); +} + +/* If access-list is updated, apply some check. */ +void +ospf_filter_update (struct access_list *access) +{ + int type; + int abr_inv = 0; + struct ospf_area *area; + listnode node; + + /* If OSPF instatnce does not exist, return right now. */ + if (!ospf_top) + return; + + + /* Update distribute-list, and apply filter. */ + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) + { + if (ROUTEMAP (type) != NULL) + { + /* if route-map is not NULL it may be using this access list */ + ospf_distribute_list_update (type); + continue; + } + + + if (DISTRIBUTE_NAME (type)) + { + /* Keep old access-list for distribute-list. */ + struct access_list *old = DISTRIBUTE_LIST (type); + + /* Update access-list for distribute-list. */ + DISTRIBUTE_LIST (type) = + access_list_lookup (AFI_IP, DISTRIBUTE_NAME (type)); + + /* No update for this distribute type. */ + if (old == NULL && DISTRIBUTE_LIST (type) == NULL) + continue; + + /* Schedule distribute-list update timer. */ + if (DISTRIBUTE_LIST (type) == NULL || + strcmp (DISTRIBUTE_NAME (type), access->name) == 0) + ospf_distribute_list_update (type); + } + } + + /* Update Area access-list. */ + for (node = listhead (ospf_top->areas); node; nextnode (node)) + if ((area = getdata (node)) != NULL) + { + if (EXPORT_NAME (area)) + { + EXPORT_LIST (area) = NULL; + abr_inv++; + } + + if (IMPORT_NAME (area)) + { + IMPORT_LIST (area) = NULL; + abr_inv++; + } + } + + /* Schedule ABR tasks -- this will be changed -- takada. */ + if (OSPF_IS_ABR && abr_inv) + ospf_schedule_abr_task (); +} + + +struct ospf_distance * +ospf_distance_new () +{ + struct ospf_distance *new; + new = XMALLOC (MTYPE_OSPF_DISTANCE, sizeof (struct ospf_distance)); + memset (new, 0, sizeof (struct ospf_distance)); + return new; +} + +void +ospf_distance_free (struct ospf_distance *odistance) +{ + XFREE (MTYPE_OSPF_DISTANCE, odistance); +} + +int +ospf_distance_set (struct vty *vty, char *distance_str, char *ip_str, + char *access_list_str) +{ + int ret; + struct prefix_ipv4 p; + u_char distance; + struct route_node *rn; + struct ospf_distance *odistance; + + ret = str2prefix_ipv4 (ip_str, &p); + if (ret == 0) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + distance = atoi (distance_str); + + /* Get OSPF distance node. */ + rn = route_node_get (ospf_top->distance_table, (struct prefix *) &p); + if (rn->info) + { + odistance = rn->info; + route_unlock_node (rn); + } + else + { + odistance = ospf_distance_new (); + rn->info = odistance; + } + + /* Set distance value. */ + odistance->distance = distance; + + /* Reset access-list configuration. */ + if (odistance->access_list) + { + free (odistance->access_list); + odistance->access_list = NULL; + } + if (access_list_str) + odistance->access_list = strdup (access_list_str); + + return CMD_SUCCESS; +} + +int +ospf_distance_unset (struct vty *vty, char *distance_str, char *ip_str, + char *access_list_str) +{ + int ret; + struct prefix_ipv4 p; + u_char distance; + struct route_node *rn; + struct ospf_distance *odistance; + + ret = str2prefix_ipv4 (ip_str, &p); + if (ret == 0) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + distance = atoi (distance_str); + + rn = route_node_lookup (ospf_top->distance_table, (struct prefix *)&p); + if (! rn) + { + vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + odistance = rn->info; + + if (odistance->access_list) + free (odistance->access_list); + ospf_distance_free (odistance); + + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + + return CMD_SUCCESS; +} + +void +ospf_distance_reset () +{ + struct route_node *rn; + struct ospf_distance *odistance; + + for (rn = route_top (ospf_top->distance_table); rn; rn = route_next (rn)) + if ((odistance = rn->info) != NULL) + { + if (odistance->access_list) + free (odistance->access_list); + ospf_distance_free (odistance); + rn->info = NULL; + route_unlock_node (rn); + } +} + +u_char +ospf_distance_apply (struct prefix_ipv4 *p, struct ospf_route *or) +{ +#if 0 + struct route_node *rn; + struct ospf_distance *odistance; + struct access_list *alist; + struct prefix_ipv4 q; + + memset (&q, 0, sizeof (struct prefix_ipv4)); + q.family = AF_INET; + /* q.prefix = */ + q.prefixlen = IPV4_MAX_BITLEN; +#endif /* 0 */ + + if (! ospf_top) + return 0; + +#if 0 + rn = route_node_match (ospf_top->distance_table, (struct prefix *) &q); + if (rn) + { + odistance = rn->info; + route_unlock_node (rn); + + if (odistance->access_list) + { + alist = access_list_lookup (AFI_IP, odistance->access_list); + if (alist == NULL) + return 0; + if (access_list_apply (alist, (struct prefix *) p) == FILTER_DENY) + return 0; + + return odistance->distance; + } + else + return odistance->distance; + } +#endif /* 0 */ + + if (ospf_top->distance_intra) + if (or->path_type == OSPF_PATH_INTRA_AREA) + return ospf_top->distance_intra; + + if (ospf_top->distance_inter) + if (or->path_type == OSPF_PATH_INTER_AREA) + return ospf_top->distance_inter; + + if (ospf_top->distance_external) + if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL + || or->path_type == OSPF_PATH_TYPE2_EXTERNAL) + return ospf_top->distance_external; + + if (ospf_top->distance_all) + return ospf_top->distance_all; + + return 0; +} + +void +ospf_zebra_init () +{ + /* Allocate zebra structure. */ + zclient = zclient_new (); + zclient_init (zclient, ZEBRA_ROUTE_OSPF); + zclient->interface_add = ospf_interface_add; + zclient->interface_delete = ospf_interface_delete; + zclient->interface_up = ospf_interface_state_up; + zclient->interface_down = ospf_interface_state_down; + zclient->interface_address_add = ospf_interface_address_add; + zclient->interface_address_delete = ospf_interface_address_delete; + zclient->ipv4_route_add = ospf_zebra_read_ipv4; + zclient->ipv4_route_delete = ospf_zebra_read_ipv4; + + access_list_add_hook (ospf_filter_update); + access_list_delete_hook (ospf_filter_update); +} diff --git a/ospfd/ospf_zebra.h b/ospfd/ospf_zebra.h new file mode 100644 index 00000000..5dbf5739 --- /dev/null +++ b/ospfd/ospf_zebra.h @@ -0,0 +1,78 @@ +/* + * Zebra connect library for OSPFd + * Copyright (C) 1997, 98, 99, 2000 Kunihiro Ishiguro, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_ZEBRA_H +#define _ZEBRA_OSPF_ZEBRA_H + +#define EXTERNAL_METRIC_TYPE_1 0 +#define EXTERNAL_METRIC_TYPE_2 1 + +#define DEFAULT_ROUTE ZEBRA_ROUTE_MAX +#define DEFAULT_ROUTE_TYPE(T) ((T) == DEFAULT_ROUTE) + +/* OSPF distance. */ +struct ospf_distance +{ + /* Distance value for the IP source prefix. */ + u_char distance; + + /* Name of the access-list to be matched. */ + char *access_list; +}; + +/* Prototypes */ +void ospf_zclient_start (); + +void ospf_zebra_add (struct prefix_ipv4 *, struct ospf_route *); +void ospf_zebra_delete (struct prefix_ipv4 *, struct ospf_route *); + +void ospf_zebra_add_discard (struct prefix_ipv4 *); +void ospf_zebra_delete_discard (struct prefix_ipv4 *); + +int ospf_default_originate_timer (struct thread *); + +int ospf_redistribute_check (struct external_info *, int *); +int ospf_distribute_check_connected (struct external_info *); +void ospf_distribute_list_update (int); + +int ospf_is_type_redistributed (int); +int ospf_redistribute_unset (int); + +void ospf_distance_reset (); +u_char ospf_distance_apply (struct prefix_ipv4 *, struct ospf_route *); + +struct vty; + +int ospf_redistribute_set (int, int, int); +int ospf_redistribute_unset (int); +int ospf_redistribute_default_set (int, int, int); +int ospf_redistribute_default_unset (); +int ospf_distribute_list_out_set (int, char *); +int ospf_distribute_list_out_unset (int, char *); +void ospf_routemap_set (int, char *); +void ospf_routemap_unset (int); +int ospf_distance_set (struct vty *, char *, char *, char *); +int ospf_distance_unset (struct vty *, char *, char *, char *); +void ospf_zebra_init (); + +#endif /* _ZEBRA_OSPF_ZEBRA_H */ + diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c new file mode 100644 index 00000000..e7de8eab --- /dev/null +++ b/ospfd/ospfd.c @@ -0,0 +1,1603 @@ +/* OSPF version 2 daemon program. + Copyright (C) 1999, 2000 Toshiaki Takada + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "thread.h" +#include "vty.h" +#include "command.h" +#include "linklist.h" +#include "prefix.h" +#include "table.h" +#include "if.h" +#include "memory.h" +#include "stream.h" +#include "log.h" +#include "sockunion.h" /* for inet_aton () */ +#include "zclient.h" +#include "plist.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_network.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ase.h" + +/* OSPF instance top. */ +struct ospf *ospf_top; + +extern struct zclient *zclient; + + +void ospf_remove_vls_through_area (struct ospf_area *); +void ospf_network_free (struct ospf_network *); +void ospf_area_free (struct ospf_area *); +void ospf_network_run (struct ospf *, struct prefix *, struct ospf_area *); + +/* Get Router ID from ospf interface list. */ +struct in_addr +ospf_router_id_get (list if_list) +{ + listnode node; + struct in_addr router_id; + + memset (&router_id, 0, sizeof (struct in_addr)); + + for (node = listhead (if_list); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + + if (!if_is_up (oi->ifp) || + OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE) + continue; + + /* Ignore virtual link interface. */ + if (oi->type != OSPF_IFTYPE_VIRTUALLINK && + oi->type != OSPF_IFTYPE_LOOPBACK) + if (IPV4_ADDR_CMP (&router_id, &oi->address->u.prefix4) < 0) + router_id = oi->address->u.prefix4; + } + + return router_id; +} + +#define OSPF_EXTERNAL_LSA_ORIGINATE_DELAY 1 + +void +ospf_router_id_update () +{ + listnode node; + struct in_addr router_id, router_id_old; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Router-ID[OLD:%s]: Update",inet_ntoa (ospf_top->router_id)); + + router_id_old = ospf_top->router_id; + + if (ospf_top->router_id_static.s_addr != 0) + router_id = ospf_top->router_id_static; + else + router_id = ospf_router_id_get (ospf_top->oiflist); + + ospf_top->router_id = router_id; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Router-ID[NEW:%s]: Update", inet_ntoa (ospf_top->router_id)); + + if (!IPV4_ADDR_SAME (&router_id_old, &router_id)) + { + for (node = listhead (ospf_top->oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + + /* Update self-neighbor's router_id. */ + oi->nbr_self->router_id = router_id; + } + + /* If AS-external-LSA is queued, then flush those LSAs. */ + if (router_id_old.s_addr == 0 && ospf_top->external_origin) + { + int type; + /* Originate each redistributed external route. */ + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) + if (ospf_top->external_origin & (1 << type)) + thread_add_event (master, ospf_external_lsa_originate_timer, + NULL, type); + /* Originate Deafult. */ + if (ospf_top->external_origin & (1 << ZEBRA_ROUTE_MAX)) + thread_add_event (master, ospf_default_originate_timer, + &ospf_top->default_originate, 0); + + ospf_top->external_origin = 0; + } + + OSPF_TIMER_ON (ospf_top->t_router_lsa_update, + ospf_router_lsa_update_timer, OSPF_LSA_UPDATE_DELAY); + } +} + +int +ospf_router_id_update_timer (struct thread *thread) +{ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Router-ID: Update timer fired!"); + + ospf_top->t_router_id_update = NULL; + ospf_router_id_update (); + + return 0; +} + +/* For OSPF area sort by area id. */ +int +ospf_area_id_cmp (struct ospf_area *a1, struct ospf_area *a2) +{ + if (ntohl (a1->area_id.s_addr) > ntohl (a2->area_id.s_addr)) + return 1; + if (ntohl (a1->area_id.s_addr) < ntohl (a2->area_id.s_addr)) + return -1; + return 0; +} + +/* Allocate new ospf structure. */ +struct ospf * +ospf_new () +{ + int i; + + struct ospf *new = XCALLOC (MTYPE_OSPF_TOP, sizeof (struct ospf)); + + new->router_id.s_addr = htonl (0); + new->router_id_static.s_addr = htonl (0); + + new->abr_type = OSPF_ABR_STAND; + new->iflist = iflist; + new->oiflist = list_new (); + new->vlinks = list_new (); + new->areas = list_new (); + new->areas->cmp = (int (*)(void *, void *)) ospf_area_id_cmp; + new->networks = route_table_init (); + new->nbr_nbma = route_table_init (); + + new->lsdb = ospf_lsdb_new (); + + new->default_originate = DEFAULT_ORIGINATE_NONE; + + new->new_external_route = route_table_init (); + new->old_external_route = route_table_init (); + new->external_lsas = route_table_init (); + + /* Distribute parameter init. */ + for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) + { + new->dmetric[i].type = -1; + new->dmetric[i].value = -1; + } + new->default_metric = -1; + new->ref_bandwidth = OSPF_DEFAULT_REF_BANDWIDTH; + + /* SPF timer value init. */ + new->spf_delay = OSPF_SPF_DELAY_DEFAULT; + new->spf_holdtime = OSPF_SPF_HOLDTIME_DEFAULT; + + /* MaxAge init. */ + new->maxage_lsa = list_new (); + new->t_maxage_walker = + thread_add_timer (master, ospf_lsa_maxage_walker, + NULL, OSPF_LSA_MAXAGE_CHECK_INTERVAL); + + /* Distance table init. */ + new->distance_table = route_table_init (); + + new->lsa_refresh_queue.index = 0; + new->lsa_refresh_interval = OSPF_LSA_REFRESH_INTERVAL_DEFAULT; + new->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker, + new, new->lsa_refresh_interval); + new->lsa_refresher_started = time (NULL); + + new->fd = ospf_sock_init (); + if (new->fd >= 0) + new->t_read = thread_add_read (master, ospf_read, new, new->fd); + new->oi_write_q = list_new (); + + return new; +} + +struct ospf * +ospf_get () +{ + if (ospf_top != NULL) + return ospf_top; + + ospf_top = ospf_new (); + + if (ospf_top->router_id_static.s_addr == 0) + ospf_router_id_update (); + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_type11_lsa_init (ospf_top); +#endif /* HAVE_OPAQUE_LSA */ + + return ospf_top; +} + +void +ospf_finish (struct ospf *ospf) +{ + struct route_node *rn; + struct ospf_nbr_nbma *nbr_nbma; + listnode node; + int i; + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_type11_lsa_term (ospf); +#endif /* HAVE_OPAQUE_LSA */ + + /* Unredister redistribution */ + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + ospf_redistribute_unset (i); + + for (node = listhead (ospf->areas); node;) + { + struct ospf_area *area = getdata (node); + nextnode (node); + + ospf_remove_vls_through_area (area); + } + + for (node = listhead (ospf->vlinks); node; ) + { + struct ospf_vl_data *vl_data = node->data; + nextnode (node); + + ospf_vl_delete (vl_data); + } + + list_delete (ospf->vlinks); + + /* Reset interface. */ + for (node = listhead (ospf->oiflist); node;) + { + struct ospf_interface *oi = getdata (node); + nextnode (node); + + if (oi) + ospf_if_free (oi); + } + + /* Clear static neighbors */ + for (rn = route_top (ospf->nbr_nbma); rn; rn = route_next (rn)) + if ((nbr_nbma = rn->info)) + { + OSPF_POLL_TIMER_OFF (nbr_nbma->t_poll); + + if (nbr_nbma->nbr) + { + nbr_nbma->nbr->nbr_nbma = NULL; + nbr_nbma->nbr = NULL; + } + + if (nbr_nbma->oi) + { + listnode_delete (nbr_nbma->oi->nbr_nbma, nbr_nbma); + nbr_nbma->oi = NULL; + } + + XFREE (MTYPE_OSPF_NEIGHBOR_STATIC, nbr_nbma); + } + + route_table_finish (ospf->nbr_nbma); + + /* Clear networks and Areas. */ + for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) + { + struct ospf_network *network; + + if ((network = rn->info) != NULL) + { + ospf_network_free (network); + rn->info = NULL; + route_unlock_node (rn); + } + } + + for (node = listhead (ospf->areas); node;) + { + struct ospf_area *area = getdata (node); + nextnode (node); + + listnode_delete (ospf->areas, area); + ospf_area_free (area); + } + + /* Cancel all timers. */ + OSPF_TIMER_OFF (ospf->t_external_lsa); + OSPF_TIMER_OFF (ospf->t_router_id_update); + OSPF_TIMER_OFF (ospf->t_router_lsa_update); + OSPF_TIMER_OFF (ospf->t_spf_calc); + OSPF_TIMER_OFF (ospf->t_ase_calc); + OSPF_TIMER_OFF (ospf->t_maxage); + OSPF_TIMER_OFF (ospf->t_maxage_walker); + OSPF_TIMER_OFF (ospf->t_abr_task); + OSPF_TIMER_OFF (ospf->t_distribute_update); + OSPF_TIMER_OFF (ospf->t_lsa_refresher); + OSPF_TIMER_OFF (ospf->t_read); + OSPF_TIMER_OFF (ospf->t_write); + + close (ospf->fd); + +#ifdef HAVE_OPAQUE_LSA + foreach_lsa (OPAQUE_AS_LSDB (ospf), ospf_top->lsdb, 0, + ospf_lsa_discard_callback); +#endif /* HAVE_OPAQUE_LSA */ + foreach_lsa (EXTERNAL_LSDB (ospf), ospf->lsdb, 0, + ospf_lsa_discard_callback); + ospf_lsdb_delete_all (ospf->lsdb); + ospf_lsdb_free (ospf->lsdb); + + for (node = listhead (ospf->maxage_lsa); node; nextnode (node)) + ospf_lsa_unlock (getdata (node)); + + list_delete (ospf->maxage_lsa); + + if (ospf->old_table) + ospf_route_table_free (ospf->old_table); + if (ospf->new_table) + { + ospf_route_delete (ospf->new_table); + ospf_route_table_free (ospf->new_table); + } + if (ospf->old_rtrs) + ospf_rtrs_free (ospf->old_rtrs); + if (ospf->new_rtrs) + ospf_rtrs_free (ospf->new_rtrs); + if (ospf->new_external_route) + { + ospf_route_delete (ospf->new_external_route); + ospf_route_table_free (ospf->new_external_route); + } + if (ospf->old_external_route) + { + ospf_route_delete (ospf->old_external_route); + ospf_route_table_free (ospf->old_external_route); + } + if (ospf->external_lsas) + { + ospf_ase_external_lsas_finish (ospf->external_lsas); + } + + list_delete (ospf->areas); + + for (i = ZEBRA_ROUTE_SYSTEM; i <= ZEBRA_ROUTE_MAX; i++) + if (EXTERNAL_INFO (i) != NULL) + for (rn = route_top (EXTERNAL_INFO (i)); rn; rn = route_next (rn)) + { + if (rn->info == NULL) + continue; + + XFREE (MTYPE_OSPF_EXTERNAL_INFO, rn->info); + rn->info = NULL; + route_unlock_node (rn); + } + + ospf_distance_reset (); + route_table_finish (ospf->distance_table); + + XFREE (MTYPE_OSPF_TOP, ospf); + + ospf_top = NULL; +} + + +/* allocate new OSPF Area object */ +struct ospf_area * +ospf_area_new (struct in_addr area_id) +{ + struct ospf_area *new; + + /* Allocate new config_network. */ + new = XCALLOC (MTYPE_OSPF_AREA, sizeof (struct ospf_area)); + + new->top = ospf_top; + + new->area_id = area_id; + + new->external_routing = OSPF_AREA_DEFAULT; + new->default_cost = 1; + new->auth_type = OSPF_AUTH_NULL; + + /* New LSDB init. */ + new->lsdb = ospf_lsdb_new (); + + /* Self-originated LSAs initialize. */ + new->router_lsa_self = NULL; + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_type10_lsa_init (new); +#endif /* HAVE_OPAQUE_LSA */ + + new->oiflist = list_new (); + new->ranges = route_table_init (); + + if (area_id.s_addr == OSPF_AREA_BACKBONE) + ospf_top->backbone = new; + + return new; +} + +void +ospf_area_free (struct ospf_area *area) +{ + /* Free LSDBs. */ + foreach_lsa (ROUTER_LSDB (area), area->lsdb, 0, ospf_lsa_discard_callback); + foreach_lsa (NETWORK_LSDB (area), area->lsdb, 0, ospf_lsa_discard_callback); + foreach_lsa (SUMMARY_LSDB (area), area->lsdb, 0, ospf_lsa_discard_callback); + foreach_lsa (ASBR_SUMMARY_LSDB (area), area->lsdb, 0, + ospf_lsa_discard_callback); + +#ifdef HAVE_NSSA + foreach_lsa (NSSA_LSDB (area), area->lsdb, 0, ospf_lsa_discard_callback); +#endif /* HAVE_NSSA */ +#ifdef HAVE_OPAQUE_LSA + foreach_lsa (OPAQUE_AREA_LSDB (area), area->lsdb, 0, + ospf_lsa_discard_callback); + foreach_lsa (OPAQUE_LINK_LSDB (area), area->lsdb, 0, + ospf_lsa_discard_callback); +#endif /* HAVE_OPAQUE_LSA */ + + ospf_lsdb_delete_all (area->lsdb); + ospf_lsdb_free (area->lsdb); + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_type10_lsa_term (area); +#endif /* HAVE_OPAQUE_LSA */ + ospf_lsa_unlock (area->router_lsa_self); + + route_table_finish (area->ranges); + list_delete (area->oiflist); + + if (EXPORT_NAME (area)) + free (EXPORT_NAME (area)); + + if (IMPORT_NAME (area)) + free (IMPORT_NAME (area)); + + /* Cancel timer. */ + OSPF_TIMER_OFF (area->t_router_lsa_self); + + if (OSPF_IS_AREA_BACKBONE (area)) + ospf_top->backbone = NULL; + + XFREE (MTYPE_OSPF_AREA, area); +} + +void +ospf_area_check_free (struct in_addr area_id) +{ + struct ospf_area *area; + + area = ospf_area_lookup_by_area_id (area_id); + if (area && + listcount (area->oiflist) == 0 && + area->ranges->top == NULL && + area->shortcut_configured == OSPF_SHORTCUT_DEFAULT && + area->external_routing == OSPF_AREA_DEFAULT && + area->no_summary == 0 && + area->default_cost == 1 && + EXPORT_NAME (area) == NULL && + IMPORT_NAME (area) == NULL && + area->auth_type == OSPF_AUTH_NULL) + { + listnode_delete (ospf_top->areas, area); + ospf_area_free (area); + } +} + +struct ospf_area * +ospf_area_get (struct in_addr area_id, int format) +{ + struct ospf_area *area; + + area = ospf_area_lookup_by_area_id (area_id); + if (!area) + { + area = ospf_area_new (area_id); + area->format = format; + listnode_add_sort (ospf_top->areas, area); + ospf_check_abr_status (); + } + + return area; +} + +struct ospf_area * +ospf_area_lookup_by_area_id (struct in_addr area_id) +{ + struct ospf_area *area; + listnode node; + + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + area = getdata (node); + + if (IPV4_ADDR_SAME (&area->area_id, &area_id)) + return area; + } + + return NULL; +} + +void +ospf_area_add_if (struct ospf_area *area, struct ospf_interface *oi) +{ + listnode_add (area->oiflist, oi); +} + +void +ospf_area_del_if (struct ospf_area *area, struct ospf_interface *oi) +{ + listnode_delete (area->oiflist, oi); +} + + +/* Config network statement related functions. */ +struct ospf_network * +ospf_network_new (struct in_addr area_id, int format) +{ + struct ospf_network *new; + new = XCALLOC (MTYPE_OSPF_NETWORK, sizeof (struct ospf_network)); + + new->area_id = area_id; + new->format = format; + + return new; +} + +void +ospf_network_free (struct ospf_network *network) +{ + ospf_area_check_free (network->area_id); + ospf_schedule_abr_task (); + XFREE (MTYPE_OSPF_NETWORK, network); +} + +int +ospf_network_set (struct ospf *ospf, struct prefix_ipv4 *p, + struct in_addr area_id) +{ + struct ospf_network *network; + struct ospf_area *area; + struct route_node *rn; + struct external_info *ei; + int ret = OSPF_AREA_ID_FORMAT_DECIMAL; + + rn = route_node_get (ospf->networks, (struct prefix *)p); + if (rn->info) + { + /* There is already same network statement. */ + route_unlock_node (rn); + return 0; + } + + rn->info = network = ospf_network_new (area_id, ret); + area = ospf_area_get (area_id, ret); + + /* Run network config now. */ + ospf_network_run (ospf, (struct prefix *)p, area); + + /* Update connected redistribute. */ + if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT)) + if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)) + for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)); + rn; rn = route_next (rn)) + if ((ei = rn->info) != NULL) + if (ospf_external_info_find_lsa (&ei->p)) + if (!ospf_distribute_check_connected (ei)) + ospf_external_lsa_flush (ei->type, &ei->p, + ei->ifindex, ei->nexthop); + + ospf_area_check_free (area_id); + + return 1; +} + +int +ospf_network_unset (struct ospf *ospf, struct prefix_ipv4 *p, + struct in_addr area_id) +{ + struct route_node *rn; + struct ospf_network *network; + struct external_info *ei; + + rn = route_node_lookup (ospf->networks, (struct prefix *)p); + if (rn == NULL) + return 0; + + network = rn->info; + if (!IPV4_ADDR_SAME (&area_id, &network->area_id)) + return 0; + + ospf_network_free (rn->info); + rn->info = NULL; + route_unlock_node (rn); + + ospf_if_update (); + + /* Update connected redistribute. */ + if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT)) + if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)) + for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)); + rn; rn = route_next (rn)) + if ((ei = rn->info) != NULL) + if (!ospf_external_info_find_lsa (&ei->p)) + if (ospf_distribute_check_connected (ei)) + ospf_external_lsa_originate (ei); + + return 1; +} + + +void +ospf_network_run (struct ospf *ospf, struct prefix *p, struct ospf_area *area) +{ + struct interface *ifp; + listnode node; + + /* Schedule Router ID Update. */ + if (ospf->router_id_static.s_addr == 0) + if (ospf->t_router_id_update == NULL) + { + ospf->t_router_id_update = + thread_add_timer (master, ospf_router_id_update_timer, ospf, + OSPF_ROUTER_ID_UPDATE_DELAY); + } + + /* Get target interface. */ + for (node = listhead (ospf->iflist); node; nextnode (node)) + { + listnode cn; + + if ((ifp = getdata (node)) == NULL) + continue; + + if (memcmp (ifp->name, "VLINK", 5) == 0) + continue; + + /* if interface prefix is match specified prefix, + then create socket and join multicast group. */ + for (cn = listhead (ifp->connected); cn; nextnode (cn)) + { + struct connected *co = getdata (cn); + struct prefix *addr; + + if (if_is_pointopoint (ifp)) + addr = co->destination; + else + addr = co->address; + + if (p->family == co->address->family && + ! ospf_if_is_configured (&(addr->u.prefix4))) + if ((if_is_pointopoint (ifp) && + IPV4_ADDR_SAME (&(addr->u.prefix4), &(p->u.prefix4))) || + prefix_match (p, addr)) + { + struct ospf_interface *oi; + + oi = ospf_if_new (ifp, co->address); + oi->connected = co; + + oi->nbr_self->address = *oi->address; + + area->act_ints++; + oi->area = area; + + oi->params = ospf_lookup_if_params (ifp, oi->address->u.prefix4); + oi->output_cost = ospf_if_get_output_cost (oi); + + if (area->external_routing != OSPF_AREA_DEFAULT) + UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); + oi->nbr_self->priority = OSPF_IF_PARAM (oi, priority); + + /* Add pseudo neighbor. */ + ospf_nbr_add_self (oi); + + /* Make sure pseudo neighbor's router_id. */ + oi->nbr_self->router_id = ospf_top->router_id; + oi->nbr_self->src = oi->address->u.prefix4; + + /* Relate ospf interface to ospf instance. */ + oi->ospf = ospf_top; + + /* update network type as interface flag */ + /* If network type is specified previously, + skip network type setting. */ + oi->type = IF_DEF_PARAMS (ifp)->type; + + /* Set area flag. */ + switch (area->external_routing) + { + case OSPF_AREA_DEFAULT: + SET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); + break; + case OSPF_AREA_STUB: + UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); + break; +#ifdef HAVE_NSSA + case OSPF_AREA_NSSA: + UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); + SET_FLAG (oi->nbr_self->options, OSPF_OPTION_NP); + break; +#endif /* HAVE_NSSA */ + } + + ospf_area_add_if (oi->area, oi); + + if (if_is_up (ifp)) + ospf_if_up (oi); + + break; + } + } + } +} + +void +ospf_ls_upd_queue_empty (struct ospf_interface *oi) +{ + struct route_node *rn; + listnode node; + list lst; + struct ospf_lsa *lsa; + + /* empty ls update queue */ + for (rn = route_top (oi->ls_upd_queue); rn; + rn = route_next (rn)) + if ((lst = (list) rn->info)) + { + for (node = listhead (lst); node; nextnode (node)) + if ((lsa = getdata (node))) + ospf_lsa_unlock (lsa); + list_free (lst); + rn->info = NULL; + } + + /* remove update event */ + if (oi->t_ls_upd_event) + { + thread_cancel (oi->t_ls_upd_event); + oi->t_ls_upd_event = NULL; + } +} + +void +ospf_if_update () +{ + struct route_node *rn; + listnode node; + listnode next; + struct ospf_network *network; + struct ospf_area *area; + + if (ospf_top != NULL) + { + /* Update Router ID scheduled. */ + if (ospf_top->router_id_static.s_addr == 0) + if (ospf_top->t_router_id_update == NULL) + { + ospf_top->t_router_id_update = + thread_add_timer (master, ospf_router_id_update_timer, NULL, + OSPF_ROUTER_ID_UPDATE_DELAY); + } + + /* Find interfaces that not configured already. */ + for (node = listhead (ospf_top->oiflist); node; node = next) + { + int found = 0; + struct ospf_interface *oi = getdata (node); + struct connected *co = oi->connected; + + next = nextnode (node); + + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + continue; + + for (rn = route_top (ospf_top->networks); rn; rn = route_next (rn)) + { + if (rn->info == NULL) + continue; + + if ((oi->type == OSPF_IFTYPE_POINTOPOINT + && IPV4_ADDR_SAME (&(co->destination->u.prefix4), + &(rn->p.u.prefix4))) + || prefix_match (&(rn->p), co->address)) + { + found = 1; + route_unlock_node (rn); + break; + } + } + + if (found == 0) + ospf_if_free (oi); + } + + /* Run each interface. */ + for (rn = route_top (ospf_top->networks); rn; rn = route_next (rn)) + if (rn->info != NULL) + { + network = (struct ospf_network *) rn->info; + area = ospf_area_get (network->area_id, network->format); + ospf_network_run (ospf_top, &rn->p, area); + } + } +} + +void +ospf_remove_vls_through_area (struct ospf_area *area) +{ + listnode node, next; + struct ospf_vl_data *vl_data; + + for (node = listhead (ospf_top->vlinks); node; node = next) + { + next = node->next; + if ((vl_data = getdata (node)) != NULL) + if (IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id)) + ospf_vl_delete (vl_data); + } +} + + +struct message ospf_area_type_msg[] = +{ + { OSPF_AREA_DEFAULT, "Default" }, + { OSPF_AREA_STUB, "Stub" }, + { OSPF_AREA_NSSA, "NSSA" }, +}; +int ospf_area_type_msg_max = OSPF_AREA_TYPE_MAX; + +void +ospf_area_type_set (struct ospf_area *area, int type) +{ + listnode node; + struct ospf_interface *oi; + + if (area->external_routing == type) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Area[%s]: Types are the same, ignored.", + inet_ntoa (area->area_id)); + return; + } + + area->external_routing = type; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Area[%s]: Configured as %s", inet_ntoa (area->area_id), + LOOKUP (ospf_area_type_msg, type)); + + switch (area->external_routing) + { + case OSPF_AREA_DEFAULT: + for (node = listhead (area->oiflist); node; nextnode (node)) + if ((oi = getdata (node)) != NULL) + if (oi->nbr_self != NULL) + SET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); + break; + case OSPF_AREA_STUB: + for (node = listhead (area->oiflist); node; nextnode (node)) + if ((oi = getdata (node)) != NULL) + if (oi->nbr_self != NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("setting options on %s accordingly", IF_NAME (oi)); + UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("options set on %s: %x", + IF_NAME (oi), OPTIONS (oi)); + } + break; + case OSPF_AREA_NSSA: +#ifdef HAVE_NSSA + for (node = listhead (area->oiflist); node; nextnode (node)) + if ((oi = getdata (node)) != NULL) + if (oi->nbr_self != NULL) + { + zlog_info ("setting nssa options on %s accordingly", IF_NAME (oi)); + UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); + SET_FLAG (oi->nbr_self->options, OSPF_OPTION_NP); + zlog_info ("options set on %s: %x", IF_NAME (oi), OPTIONS (oi)); + } +#endif /* HAVE_NSSA */ + break; + default: + break; + } + + ospf_router_lsa_timer_add (area); + ospf_schedule_abr_task (); +} + +int +ospf_area_shortcut_set (struct ospf_area *area, int mode) +{ + if (area->shortcut_configured == mode) + return 0; + + area->shortcut_configured = mode; + ospf_router_lsa_timer_add (area); + ospf_schedule_abr_task (); + + ospf_area_check_free (area->area_id); + + return 1; +} + +int +ospf_area_shortcut_unset (struct ospf_area *area) +{ + area->shortcut_configured = OSPF_SHORTCUT_DEFAULT; + ospf_router_lsa_timer_add (area); + ospf_area_check_free (area->area_id); + ospf_schedule_abr_task (); + + return 1; +} + +int +ospf_area_vlink_count (struct ospf *ospf, struct ospf_area *area) +{ + struct ospf_vl_data *vl; + listnode node; + int count = 0; + + for (node = listhead (ospf->vlinks); node; nextnode (node)) + { + vl = getdata (node); + if (IPV4_ADDR_SAME (&vl->vl_area_id, &area->area_id)) + count++; + } + + return count; +} + +int +ospf_area_stub_set (struct ospf *ospf, struct in_addr area_id) +{ + struct ospf_area *area; + int format = OSPF_AREA_ID_FORMAT_DECIMAL; + + area = ospf_area_get (area_id, format); + if (ospf_area_vlink_count (ospf, area)) + return 0; + + if (area->external_routing != OSPF_AREA_STUB) + ospf_area_type_set (area, OSPF_AREA_STUB); + + return 1; +} + +int +ospf_area_stub_unset (struct ospf *ospf, struct in_addr area_id) +{ + struct ospf_area *area; + + area = ospf_area_lookup_by_area_id (area_id); + if (area == NULL) + return 1; + + if (area->external_routing == OSPF_AREA_STUB) + ospf_area_type_set (area, OSPF_AREA_DEFAULT); + + ospf_area_check_free (area_id); + + return 1; +} + +int +ospf_area_no_summary_set (struct ospf *ospf, struct in_addr area_id) +{ + struct ospf_area *area; + int format = OSPF_AREA_ID_FORMAT_DECIMAL; + + area = ospf_area_get (area_id, format); + area->no_summary = 1; + + return 1; +} + +int +ospf_area_no_summary_unset (struct ospf *ospf, struct in_addr area_id) +{ + struct ospf_area *area; + + area = ospf_area_lookup_by_area_id (area_id); + if (area == NULL) + return 0; + + area->no_summary = 0; + ospf_area_check_free (area_id); + + return 1; +} + +int +ospf_area_nssa_set (struct ospf *ospf, struct in_addr area_id) +{ + struct ospf_area *area; + int format = OSPF_AREA_ID_FORMAT_DECIMAL; + + area = ospf_area_get (area_id, format); + if (ospf_area_vlink_count (ospf, area)) + return 0; + + if (area->external_routing != OSPF_AREA_NSSA) + { + ospf_area_type_set (area, OSPF_AREA_NSSA); + ospf->anyNSSA++; + } + + return 1; +} + +int +ospf_area_nssa_unset (struct ospf *ospf, struct in_addr area_id) +{ + struct ospf_area *area; + + area = ospf_area_lookup_by_area_id (area_id); + if (area == NULL) + return 0; + + if (area->external_routing == OSPF_AREA_NSSA) + { + ospf->anyNSSA--; + ospf_area_type_set (area, OSPF_AREA_DEFAULT); + } + + ospf_area_check_free (area_id); + + return 1; +} + +int +ospf_area_nssa_translator_role_set (struct ospf *ospf, struct in_addr area_id, + int role) +{ + struct ospf_area *area; + + area = ospf_area_lookup_by_area_id (area_id); + if (area == NULL) + return 0; + + area->NSSATranslator = role; + + return 1; +} + +int +ospf_area_nssa_translator_role_unset (struct ospf *ospf, + struct in_addr area_id) +{ + struct ospf_area *area; + + area = ospf_area_lookup_by_area_id (area_id); + if (area == NULL) + return 0; + + area->NSSATranslator = OSPF_NSSA_ROLE_CANDIDATE; + + ospf_area_check_free (area_id); + + return 1; +} + +int +ospf_area_export_list_set (struct ospf_area *area, char *list_name) +{ + struct access_list *list; + list = access_list_lookup (AFI_IP, list_name); + + EXPORT_LIST (area) = list; + + if (EXPORT_NAME (area)) + free (EXPORT_NAME (area)); + + EXPORT_NAME (area) = strdup (list_name); + ospf_schedule_abr_task (); + + return 1; +} + +int +ospf_area_export_list_unset (struct ospf_area * area) +{ + + EXPORT_LIST (area) = 0; + + if (EXPORT_NAME (area)) + free (EXPORT_NAME (area)); + + EXPORT_NAME (area) = NULL; + + ospf_area_check_free (area->area_id); + + ospf_schedule_abr_task (); + + return 1; +} + +int +ospf_area_import_list_set (struct ospf_area *area, char *name) +{ + struct access_list *list; + list = access_list_lookup (AFI_IP, name); + + IMPORT_LIST (area) = list; + + if (IMPORT_NAME (area)) + free (IMPORT_NAME (area)); + + IMPORT_NAME (area) = strdup (name); + ospf_schedule_abr_task (); + + return 1; +} + +int +ospf_area_import_list_unset (struct ospf_area * area) +{ + IMPORT_LIST (area) = 0; + + if (IMPORT_NAME (area)) + free (IMPORT_NAME (area)); + + IMPORT_NAME (area) = NULL; + ospf_area_check_free (area->area_id); + + ospf_schedule_abr_task (); + + return 1; +} + +int +ospf_timers_spf_set (struct ospf *ospf, u_int32_t delay, u_int32_t hold) +{ + ospf->spf_delay = delay; + ospf->spf_holdtime = hold; + + return 1; +} + +int +ospf_timers_spf_unset (struct ospf *ospf) +{ + ospf->spf_delay = OSPF_SPF_DELAY_DEFAULT; + ospf->spf_holdtime = OSPF_SPF_HOLDTIME_DEFAULT; + + return 1; +} + +int +ospf_timers_refresh_set (struct ospf *ospf, int interval) +{ + int time_left; + + if (ospf->lsa_refresh_interval == interval) + return 1; + + time_left = ospf->lsa_refresh_interval - + (time (NULL) - ospf->lsa_refresher_started); + + if (time_left > interval) + { + OSPF_TIMER_OFF (ospf->t_lsa_refresher); + ospf->t_lsa_refresher = + thread_add_timer (master, ospf_lsa_refresh_walker, ospf, interval); + } + ospf->lsa_refresh_interval = interval; + + return 1; +} + +int +ospf_timers_refresh_unset (struct ospf *ospf) +{ + int time_left; + + time_left = ospf->lsa_refresh_interval - + (time (NULL) - ospf->lsa_refresher_started); + + if (time_left > OSPF_LSA_REFRESH_INTERVAL_DEFAULT) + { + OSPF_TIMER_OFF (ospf->t_lsa_refresher); + ospf->t_lsa_refresher = + thread_add_timer (master, ospf_lsa_refresh_walker, ospf, + OSPF_LSA_REFRESH_INTERVAL_DEFAULT); + } + + ospf->lsa_refresh_interval = OSPF_LSA_REFRESH_INTERVAL_DEFAULT; + + return 1; +} + + +struct ospf_nbr_nbma * +ospf_nbr_nbma_new () +{ + struct ospf_nbr_nbma *nbr_nbma; + + nbr_nbma = XMALLOC (MTYPE_OSPF_NEIGHBOR_STATIC, + sizeof (struct ospf_nbr_nbma)); + memset (nbr_nbma, 0, sizeof (struct ospf_nbr_nbma)); + + nbr_nbma->priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; + nbr_nbma->v_poll = OSPF_POLL_INTERVAL_DEFAULT; + + return nbr_nbma; +} + +void +ospf_nbr_nbma_free (struct ospf_nbr_nbma *nbr_nbma) +{ + XFREE (MTYPE_OSPF_NEIGHBOR_STATIC, nbr_nbma); +} + +void +ospf_nbr_nbma_delete (struct ospf *ospf, struct ospf_nbr_nbma *nbr_nbma) +{ + struct route_node *rn; + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefix = nbr_nbma->addr; + p.prefixlen = IPV4_MAX_BITLEN; + + rn = route_node_lookup (ospf->nbr_nbma, (struct prefix *)&p); + if (rn) + { + ospf_nbr_nbma_free (rn->info); + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + } +} + +void +ospf_nbr_nbma_down (struct ospf_nbr_nbma *nbr_nbma) +{ + OSPF_TIMER_OFF (nbr_nbma->t_poll); + + if (nbr_nbma->nbr) + { + nbr_nbma->nbr->nbr_nbma = NULL; + OSPF_NSM_EVENT_EXECUTE (nbr_nbma->nbr, NSM_KillNbr); + } + + if (nbr_nbma->oi) + listnode_delete (nbr_nbma->oi->nbr_nbma, nbr_nbma); +} + +void +ospf_nbr_nbma_add (struct ospf_nbr_nbma *nbr_nbma, + struct ospf_interface *oi) +{ + struct ospf_neighbor *nbr; + struct route_node *rn; + struct prefix p; + + if (oi->type != OSPF_IFTYPE_NBMA) + return; + + if (nbr_nbma->nbr != NULL) + return; + + if (IPV4_ADDR_SAME (&oi->nbr_self->address.u.prefix4, &nbr_nbma->addr)) + return; + + nbr_nbma->oi = oi; + listnode_add (oi->nbr_nbma, nbr_nbma); + + /* Get neighbor information from table. */ + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = nbr_nbma->addr; + + rn = route_node_get (oi->nbrs, (struct prefix *)&p); + if (rn->info) + { + nbr = rn->info; + nbr->nbr_nbma = nbr_nbma; + nbr_nbma->nbr = nbr; + + route_unlock_node (rn); + } + else + { + nbr = rn->info = ospf_nbr_new (oi); + nbr->state = NSM_Down; + nbr->src = nbr_nbma->addr; + nbr->nbr_nbma = nbr_nbma; + nbr->priority = nbr_nbma->priority; + nbr->address = p; + + nbr_nbma->nbr = nbr; + + OSPF_NSM_EVENT_EXECUTE (nbr, NSM_Start); + } +} + +void +ospf_nbr_nbma_if_update (struct ospf_interface *oi) +{ + struct ospf_nbr_nbma *nbr_nbma; + struct route_node *rn; + struct prefix_ipv4 p; + + if (oi->type != OSPF_IFTYPE_NBMA) + return; + + for (rn = route_top (ospf_top->nbr_nbma); rn; rn = route_next (rn)) + if ((nbr_nbma = rn->info)) + if (nbr_nbma->oi == NULL && nbr_nbma->nbr == NULL) + { + p.family = AF_INET; + p.prefix = nbr_nbma->addr; + p.prefixlen = IPV4_MAX_BITLEN; + + if (prefix_match (oi->address, (struct prefix *)&p)) + ospf_nbr_nbma_add (nbr_nbma, oi); + } +} + +struct ospf_nbr_nbma * +ospf_nbr_nbma_lookup (struct ospf *ospf, struct in_addr nbr_addr) +{ + struct route_node *rn; + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefix = nbr_addr; + p.prefixlen = IPV4_MAX_BITLEN; + + rn = route_node_lookup (ospf->nbr_nbma, (struct prefix *)&p); + if (rn) + { + route_unlock_node (rn); + return rn->info; + } + return NULL; +} + +struct ospf_nbr_nbma * +ospf_nbr_nbma_lookup_next (struct in_addr *addr, int first) +{ +#if 0 + struct ospf_nbr_nbma *nbr_nbma; + listnode node; +#endif + + if (! ospf_top) + return NULL; + +#if 0 + for (node = listhead (ospf_top->nbr_nbma); node; nextnode (node)) + { + nbr_nbma = getdata (node); + + if (first) + { + *addr = nbr_nbma->addr; + return nbr_nbma; + } + else if (ntohl (nbr_nbma->addr.s_addr) > ntohl (addr->s_addr)) + { + *addr = nbr_nbma->addr; + return nbr_nbma; + } + } +#endif + return NULL; +} + +int +ospf_nbr_nbma_set (struct ospf *ospf, struct in_addr nbr_addr) +{ + struct ospf_nbr_nbma *nbr_nbma; + struct ospf_interface *oi; + struct prefix_ipv4 p; + struct route_node *rn; + listnode node; + + nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr); + if (nbr_nbma) + return 0; + + nbr_nbma = ospf_nbr_nbma_new (); + nbr_nbma->addr = nbr_addr; + + p.family = AF_INET; + p.prefix = nbr_addr; + p.prefixlen = IPV4_MAX_BITLEN; + + rn = route_node_get (ospf->nbr_nbma, (struct prefix *)&p); + rn->info = nbr_nbma; + + for (node = listhead (ospf->oiflist); node; nextnode (node)) + { + oi = getdata (node); + if (oi->type == OSPF_IFTYPE_NBMA) + if (prefix_match (oi->address, (struct prefix *)&p)) + { + ospf_nbr_nbma_add (nbr_nbma, oi); + break; + } + } + + return 1; +} + +int +ospf_nbr_nbma_unset (struct ospf *ospf, struct in_addr nbr_addr) +{ + struct ospf_nbr_nbma *nbr_nbma; + + nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr); + if (nbr_nbma == NULL) + return 0; + + ospf_nbr_nbma_down (nbr_nbma); + ospf_nbr_nbma_delete (ospf, nbr_nbma); + + return 1; +} + +int +ospf_nbr_nbma_priority_set (struct ospf *ospf, struct in_addr nbr_addr, + u_char priority) +{ + struct ospf_nbr_nbma *nbr_nbma; + + nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr); + if (nbr_nbma == NULL) + return 0; + + if (nbr_nbma->priority != priority) + nbr_nbma->priority = priority; + + return 1; +} + +int +ospf_nbr_nbma_priority_unset (struct ospf *ospf, struct in_addr nbr_addr) +{ + struct ospf_nbr_nbma *nbr_nbma; + + nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr); + if (nbr_nbma == NULL) + return 0; + + if (nbr_nbma != OSPF_NEIGHBOR_PRIORITY_DEFAULT) + nbr_nbma->priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; + + return 1; +} + +int +ospf_nbr_nbma_poll_interval_set (struct ospf *ospf, struct in_addr nbr_addr, + int interval) +{ + struct ospf_nbr_nbma *nbr_nbma; + + nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr); + if (nbr_nbma == NULL) + return 0; + + if (nbr_nbma->v_poll != interval) + { + nbr_nbma->v_poll = interval; + if (nbr_nbma->oi && ospf_if_is_up (nbr_nbma->oi)) + { + OSPF_TIMER_OFF (nbr_nbma->t_poll); + OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer, + nbr_nbma->v_poll); + } + } + + return 1; +} + +int +ospf_nbr_nbma_poll_interval_unset (struct ospf *ospf, struct in_addr addr) +{ + struct ospf_nbr_nbma *nbr_nbma; + + nbr_nbma = ospf_nbr_nbma_lookup (ospf, addr); + if (nbr_nbma == NULL) + return 0; + + if (nbr_nbma->v_poll != OSPF_POLL_INTERVAL_DEFAULT) + nbr_nbma->v_poll = OSPF_POLL_INTERVAL_DEFAULT; + + return 1; +} + + +void +ospf_prefix_list_update (struct prefix_list *plist) +{ + struct ospf_area *area; + listnode node; + int abr_inv = 0; + + /* If OSPF instatnce does not exist, return right now. */ + if (!ospf_top) + return; + + /* Update Area prefix-list. */ + for (node = listhead (ospf_top->areas); node; nextnode (node)) + { + area = getdata (node); + + /* Update filter-list in. */ + if (PREFIX_NAME_IN (area)) + if (strcmp (PREFIX_NAME_IN (area), plist->name) == 0) + { + PREFIX_LIST_IN (area) = + prefix_list_lookup (AFI_IP, PREFIX_NAME_IN (area)); + abr_inv++; + } + + /* Update filter-list out. */ + if (PREFIX_NAME_OUT (area)) + if (strcmp (PREFIX_NAME_OUT (area), plist->name) == 0) + { + PREFIX_LIST_IN (area) = + prefix_list_lookup (AFI_IP, PREFIX_NAME_OUT (area)); + abr_inv++; + } + } + + /* Schedule ABR tasks. */ + if (OSPF_IS_ABR && abr_inv) + ospf_schedule_abr_task (); +} + +void +ospf_init () +{ + /* Make empty list of ospf list. */ + ospf_top = NULL; + + prefix_list_add_hook (ospf_prefix_list_update); + prefix_list_delete_hook (ospf_prefix_list_update); +} diff --git a/ospfd/ospfd.conf.sample b/ospfd/ospfd.conf.sample new file mode 100644 index 00000000..0e8ac67b --- /dev/null +++ b/ospfd/ospfd.conf.sample @@ -0,0 +1,13 @@ +! -*- ospf -*- +! +! OSPFd sample configuration file +! +! +hostname ospfd +password zebra +!enable password please-set-at-here +! +!router ospf +! network 192.168.1.0/24 area 0 +! +log stdout diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h new file mode 100644 index 00000000..a83231b2 --- /dev/null +++ b/ospfd/ospfd.h @@ -0,0 +1,559 @@ +/* + * OSPFd main header. + * Copyright (C) 1998, 99, 2000 Kunihiro Ishiguro, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPFD_H +#define _ZEBRA_OSPFD_H + +#include "filter.h" + +#define OSPF_VERSION 2 + +/* Default protocol, port number. */ +#ifndef IPPROTO_OSPFIGP +#define IPPROTO_OSPFIGP 89 +#endif /* IPPROTO_OSPFIGP */ + +/* VTY port number. */ +#define OSPF_VTY_PORT 2604 +#define OSPF_VTYSH_PATH "/tmp/.ospfd" + +/* IP TTL for OSPF protocol. */ +#define OSPF_IP_TTL 1 +#define OSPF_VL_IP_TTL 100 + +/* Default configuration file name for ospfd. */ +#define OSPF_DEFAULT_CONFIG "ospfd.conf" + +/* Architectual Constants */ +#ifdef DEBUG +#define OSPF_LS_REFRESH_TIME 60 +#else +#define OSPF_LS_REFRESH_TIME 1800 +#endif +#define OSPF_MIN_LS_INTERVAL 5 +#define OSPF_MIN_LS_ARRIVAL 1 +#define OSPF_LSA_MAXAGE 3600 +#define OSPF_CHECK_AGE 300 +#define OSPF_LSA_MAXAGE_DIFF 900 +#define OSPF_LS_INFINITY 0xffffff +#define OSPF_DEFAULT_DESTINATION 0x00000000 /* 0.0.0.0 */ +#define OSPF_INITIAL_SEQUENCE_NUMBER 0x80000001 +#define OSPF_MAX_SEQUENCE_NUMBER 0x7fffffff + +#define OSPF_LSA_MAXAGE_CHECK_INTERVAL 30 + +#define OSPF_ALLSPFROUTERS 0xe0000005 /* 224.0.0.5 */ +#define OSPF_ALLDROUTERS 0xe0000006 /* 224.0.0.6 */ + +#ifdef HAVE_NSSA +#define OSPF_LOOPer 0x7f000000 /* 127.0.0.0 */ +#endif /* HAVE_NSSA */ + +#define OSPF_AREA_BACKBONE 0x00000000 /* 0.0.0.0 */ + +/* OSPF Authentication Type. */ +#define OSPF_AUTH_NULL 0 +#define OSPF_AUTH_SIMPLE 1 +#define OSPF_AUTH_CRYPTOGRAPHIC 2 +/* For Interface authentication setting default */ +#define OSPF_AUTH_NOTSET -1 +/* For the consumption and sanity of the command handler */ +/* DO NIOT REMOVE!!! Need to detect whether a value has + been given or not in VLink command handlers */ +#define OSPF_AUTH_CMD_NOTSEEN -2 + +/* OSPF SPF timer values. */ +#define OSPF_SPF_DELAY_DEFAULT 5 +#define OSPF_SPF_HOLDTIME_DEFAULT 10 + +/* OSPF interface default values. */ +#define OSPF_OUTPUT_COST_DEFAULT 10 +#define OSPF_ROUTER_DEAD_INTERVAL_DEFAULT 40 +#define OSPF_HELLO_INTERVAL_DEFAULT 10 +#define OSPF_ROUTER_PRIORITY_DEFAULT 1 +#define OSPF_RETRANSMIT_INTERVAL_DEFAULT 5 +#define OSPF_TRANSMIT_DELAY_DEFAULT 1 +#define OSPF_DEFAULT_BANDWIDTH 10000 /* Kbps */ + +#define OSPF_DEFAULT_REF_BANDWIDTH 100000 /* Kbps */ + +#define OSPF_POLL_INTERVAL_DEFAULT 60 +#define OSPF_NEIGHBOR_PRIORITY_DEFAULT 0 + +/* OSPF options. */ +#define OSPF_OPTION_T 0x01 /* TOS. */ +#define OSPF_OPTION_E 0x02 +#define OSPF_OPTION_MC 0x04 +#define OSPF_OPTION_NP 0x08 +#define OSPF_OPTION_EA 0x10 +#define OSPF_OPTION_DC 0x20 +#define OSPF_OPTION_O 0x40 + +/* OSPF Database Description flags. */ +#define OSPF_DD_FLAG_MS 0x01 +#define OSPF_DD_FLAG_M 0x02 +#define OSPF_DD_FLAG_I 0x04 +#define OSPF_DD_FLAG_ALL 0x07 + +/* Timer value. */ +#define OSPF_ROUTER_ID_UPDATE_DELAY 1 + +#define OSPF_LS_REFRESH_SHIFT (60 * 15) +#define OSPF_LS_REFRESH_JITTER 60 + +/* OSPF instance structure. */ +struct ospf +{ + /* OSPF Router ID. */ + struct in_addr router_id; /* Configured automatically. */ + struct in_addr router_id_static; /* Configured manually. */ + + /* ABR/ASBR internal flags. */ + u_char flags; +#define OSPF_FLAG_ABR 0x0001 +#define OSPF_FLAG_ASBR 0x0002 + + /* ABR type. */ + u_char abr_type; +#define OSPF_ABR_UNKNOWN 0 +#define OSPF_ABR_STAND 1 +#define OSPF_ABR_IBM 2 +#define OSPF_ABR_CISCO 3 +#define OSPF_ABR_SHORTCUT 4 + + /* NSSA ABR */ + u_char anyNSSA; /* Bump for every NSSA attached. */ + + /* Configured variables. */ + u_char config; +#define OSPF_RFC1583_COMPATIBLE (1 << 0) +#define OSPF_OPAQUE_CAPABLE (1 << 2) + +#ifdef HAVE_OPAQUE_LSA + /* Opaque-LSA administrative flags. */ + u_char opaque; +#define OPAQUE_OPERATION_READY_BIT (1 << 0) +#define OPAQUE_BLOCK_TYPE_09_LSA_BIT (1 << 1) +#define OPAQUE_BLOCK_TYPE_10_LSA_BIT (1 << 2) +#define OPAQUE_BLOCK_TYPE_11_LSA_BIT (1 << 3) +#endif /* HAVE_OPAQUE_LSA */ + + int spf_delay; /* SPF delay time. */ + int spf_holdtime; /* SPF hold time. */ + int default_originate; /* Default information originate. */ +#define DEFAULT_ORIGINATE_NONE 0 +#define DEFAULT_ORIGINATE_ZEBRA 1 +#define DEFAULT_ORIGINATE_ALWAYS 2 + u_int32_t ref_bandwidth; /* Reference Bandwidth (Kbps). */ + struct route_table *networks; /* OSPF config networks. */ + list vlinks; /* Configured Virtual-Links. */ + list areas; /* OSPF areas. */ + struct route_table *nbr_nbma; + struct ospf_area *backbone; /* Pointer to the Backbone Area. */ + + list iflist; /* Zebra derived interfaces. */ + list oiflist; /* ospf interfaces */ + + /* LSDB of AS-external-LSAs. */ + struct ospf_lsdb *lsdb; + + /* Redistributed external information. */ + struct route_table *external_info[ZEBRA_ROUTE_MAX + 1]; +#define EXTERNAL_INFO(T) ospf_top->external_info[T] + + /* Flags. */ + int external_origin; /* AS-external-LSA origin flag. */ + int ase_calc; /* ASE calculation flag. */ + +#ifdef HAVE_OPAQUE_LSA + list opaque_lsa_self; /* Type-11 Opaque-LSAs */ +#endif /* HAVE_OPAQUE_LSA */ + + /* Routing tables. */ + struct route_table *old_table; /* Old routing table. */ + struct route_table *new_table; /* Current routing table. */ + + struct route_table *old_rtrs; /* Old ABR/ASBR RT. */ + struct route_table *new_rtrs; /* New ABR/ASBR RT. */ + + struct route_table *new_external_route; /* New External Route. */ + struct route_table *old_external_route; /* Old External Route. */ + + struct route_table *external_lsas; /* Database of external LSAs, + prefix is LSA's adv. network*/ + + /* Time stamps. */ + time_t ts_spf; /* SPF calculation time stamp. */ + + list maxage_lsa; /* List of MaxAge LSA for deletion. */ + int redistribute; /* Num of redistributed protocols. */ + + /* Threads. */ + struct thread *t_router_id_update; /* Router ID update timer. */ + struct thread *t_router_lsa_update; /* router-LSA update timer. */ + struct thread *t_abr_task; /* ABR task timer. */ + struct thread *t_asbr_check; /* ASBR check timer. */ + struct thread *t_distribute_update; /* Distirbute list update timer. */ + struct thread *t_spf_calc; /* SPF calculation timer. */ + struct thread *t_ase_calc; /* ASE calculation timer. */ + struct thread *t_external_lsa; /* AS-external-LSA origin timer. */ +#ifdef HAVE_OPAQUE_LSA + struct thread *t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */ +#endif /* HAVE_OPAQUE_LSA */ + struct thread *t_maxage; /* MaxAge LSA remover timer. */ + struct thread *t_maxage_walker; /* MaxAge LSA checking timer. */ + + struct thread *t_write; + struct thread *t_read; + int fd; + list oi_write_q; + + /* Distribute lists out of other route sources. */ + struct + { + char *name; + struct access_list *list; + } dlist[ZEBRA_ROUTE_MAX]; +#define DISTRIBUTE_NAME(T) ospf_top->dlist[T].name +#define DISTRIBUTE_LIST(T) ospf_top->dlist[T].list + + /* Redistribute metric info. */ + struct + { + int type; /* External metric type (E1 or E2). */ + int value; /* Value for static metric (24-bit). + -1 means metric value is not set. */ + } dmetric [ZEBRA_ROUTE_MAX + 1]; + + /* For redistribute route map. */ + struct + { + char *name; + struct route_map *map; + } route_map [ZEBRA_ROUTE_MAX + 1]; /* +1 is for default-information */ +#define ROUTEMAP_NAME(T) ospf_top->route_map[T].name +#define ROUTEMAP(T) ospf_top->route_map[T].map + + int default_metric; /* Default metric for redistribute. */ + +#define OSPF_LSA_REFRESHER_GRANULARITY 10 +#define OSPF_LSA_REFRESHER_SLOTS ((OSPF_LS_REFRESH_TIME + \ + OSPF_LS_REFRESH_SHIFT)/10 + 1) + struct + { + u_int16_t index; + list qs[OSPF_LSA_REFRESHER_SLOTS]; + } lsa_refresh_queue; + + struct thread *t_lsa_refresher; + time_t lsa_refresher_started; +#define OSPF_LSA_REFRESH_INTERVAL_DEFAULT 10 + u_int16_t lsa_refresh_interval; + + /* Distance parameter. */ + u_char distance_all; + u_char distance_intra; + u_char distance_inter; + u_char distance_external; + + /* Statistics for LSA origination. */ + u_int32_t lsa_originate_count; + + /* Statistics for LSA used for new instantiation. */ + u_int32_t rx_lsa_count; + + struct route_table *distance_table; +}; + +/* OSPF area structure. */ +struct ospf_area +{ + /* OSPF instance. */ + struct ospf *top; + + /* Zebra interface list belonging to the area. */ + list oiflist; + + /* Area ID. */ + struct in_addr area_id; + + /* Area ID format. */ + char format; +#define OSPF_AREA_ID_FORMAT_ADDRESS 1 +#define OSPF_AREA_ID_FORMAT_DECIMAL 2 + + /* Address range. */ + list address_range; + + /* Configured variables. */ + int external_routing; /* ExternalRoutingCapability. */ +#define OSPF_AREA_DEFAULT 0 +#define OSPF_AREA_STUB 1 +#define OSPF_AREA_NSSA 2 +#define OSPF_AREA_TYPE_MAX 3 + int no_summary; /* Don't inject summaries into stub.*/ + int shortcut_configured; /* Area configured as shortcut. */ +#define OSPF_SHORTCUT_DEFAULT 0 +#define OSPF_SHORTCUT_ENABLE 1 +#define OSPF_SHORTCUT_DISABLE 2 + int shortcut_capability; /* Other ABRs agree on S-bit */ + u_int32_t default_cost; /* StubDefaultCost. */ + int auth_type; /* Authentication type. */ + + u_char NSSATranslatorRole; /* NSSA Role during configuration */ +#define OSPF_NSSA_ROLE_NEVER 0 +#define OSPF_NSSA_ROLE_ALWAYS 1 +#define OSPF_NSSA_ROLE_CANDIDATE 2 + u_char NSSATranslator; /* NSSA Role after election process */ + + u_char transit; /* TransitCapability. */ +#define OSPF_TRANSIT_FALSE 0 +#define OSPF_TRANSIT_TRUE 1 + struct route_table *ranges; /* Configured Area Ranges. */ + + /* Area related LSDBs[Type1-4]. */ + struct ospf_lsdb *lsdb; + + /* Self-originated LSAs. */ + struct ospf_lsa *router_lsa_self; +#ifdef HAVE_OPAQUE_LSA + list opaque_lsa_self; /* Type-10 Opaque-LSAs */ +#endif /* HAVE_OPAQUE_LSA */ + + /* Area announce list. */ + struct + { + char *name; + struct access_list *list; + } export; +#define EXPORT_NAME(A) (A)->export.name +#define EXPORT_LIST(A) (A)->export.list + + /* Area acceptance list. */ + struct + { + char *name; + struct access_list *list; + } import; +#define IMPORT_NAME(A) (A)->import.name +#define IMPORT_LIST(A) (A)->import.list + + /* Type 3 LSA Area prefix-list. */ + struct + { + char *name; + struct prefix_list *list; + } plist_in; +#define PREFIX_LIST_IN(A) (A)->plist_in.list +#define PREFIX_NAME_IN(A) (A)->plist_in.name + + struct + { + char *name; + struct prefix_list *list; + } plist_out; +#define PREFIX_LIST_OUT(A) (A)->plist_out.list +#define PREFIX_NAME_OUT(A) (A)->plist_out.name + + /* Shortest Path Tree. */ + struct vertex *spf; + + /* Threads. */ + struct thread *t_router_lsa_self;/* Self-originated router-LSA timer. */ +#ifdef HAVE_OPAQUE_LSA + struct thread *t_opaque_lsa_self; /* Type-10 Opaque-LSAs origin. */ +#endif /* HAVE_OPAQUE_LSA */ + + /* Statistics field. */ + u_int32_t spf_calculation; /* SPF Calculation Count. */ + + /* Router count. */ + u_int32_t abr_count; /* ABR router in this area. */ + u_int32_t asbr_count; /* ASBR router in this area. */ + + /* Counters. */ + u_int32_t act_ints; /* Active interfaces. */ + u_int32_t full_nbrs; /* Fully adjacent neighbors. */ + u_int32_t full_vls; /* Fully adjacent virtual neighbors. */ +}; + +/* OSPF config network structure. */ +struct ospf_network +{ + /* Area ID. */ + struct in_addr area_id; + int format; +}; + +/* OSPF NBMA neighbor structure. */ +struct ospf_nbr_nbma +{ + /* Neighbor IP address. */ + struct in_addr addr; + + /* OSPF interface. */ + struct ospf_interface *oi; + + /* OSPF neighbor structure. */ + struct ospf_neighbor *nbr; + + /* Neighbor priority. */ + u_char priority; + + /* Poll timer value. */ + u_int32_t v_poll; + + /* Poll timer thread. */ + struct thread *t_poll; + + /* State change. */ + u_int32_t state_change; +}; + +/* Macro. */ +#define OSPF_AREA_SAME(X,Y) \ + (memcmp ((X->area_id), (Y->area_id), IPV4_MAX_BYTELEN) == 0) + +#define OSPF_IS_ABR (ospf_top->flags & OSPF_FLAG_ABR) +#define OSPF_IS_ASBR (ospf_top->flags & OSPF_FLAG_ASBR) + +#define OSPF_IS_AREA_ID_BACKBONE(I) ((I).s_addr == OSPF_AREA_BACKBONE) +#define OSPF_IS_AREA_BACKBONE(A) OSPF_IS_AREA_ID_BACKBONE ((A)->area_id) + +#ifdef roundup +# define ROUNDUP(val, gran) roundup(val, gran) +#else /* roundup */ +# define ROUNDUP(val, gran) (((val) - 1 | (gran) - 1) + 1) +#endif /* roundup */ + +#define LSA_OPTIONS_GET(area) \ + (((area)->external_routing == OSPF_AREA_DEFAULT) ? OSPF_OPTION_E : 0) +#ifdef HAVE_NSSA +#define LSA_NSSA_GET(area) \ + (((area)->external_routing == OSPF_AREA_NSSA) ? \ + (area)->NSSATranslator : 0) +#endif /* HAVE_NSSA */ + +#define OSPF_TIMER_ON(T,F,V) \ + do { \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), NULL, (V)); \ + } while (0) + +#define OSPF_AREA_TIMER_ON(T,F,V) \ + do { \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), area, (V)); \ + } while (0) + +#define OSPF_POLL_TIMER_ON(T,F,V) \ + do { \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), nbr_nbma, (V)); \ + } while (0) + +#define OSPF_POLL_TIMER_OFF(X) OSPF_TIMER_OFF((X)) + +#define OSPF_TIMER_OFF(X) \ + do { \ + if (X) \ + { \ + thread_cancel (X); \ + (X) = NULL; \ + } \ + } while (0) + +#define OSPF_SCHEDULE_MAXAGE(T, F) \ + do { \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), 0, 2); \ + } while (0) + +/* Messages */ +extern struct message ospf_ism_state_msg[]; +extern struct message ospf_nsm_state_msg[]; +extern struct message ospf_lsa_type_msg[]; +extern struct message ospf_link_state_id_type_msg[]; +extern struct message ospf_redistributed_proto[]; +extern struct message ospf_network_type_msg[]; +extern int ospf_ism_state_msg_max; +extern int ospf_nsm_state_msg_max; +extern int ospf_lsa_type_msg_max; +extern int ospf_link_state_id_type_msg_max; +extern int ospf_redistributed_proto_max; +extern int ospf_network_type_msg_max; +extern struct zclient *zclient; +extern struct thread_master *master; +extern struct ospf *ospf_top; +extern int ospf_zlog; + +/* Prototypes. */ +struct ospf *ospf_get (); +void ospf_finish (struct ospf *); +int ospf_router_id_update_timer (struct thread *); +void ospf_router_id_update (); +int ospf_network_set (struct ospf *, struct prefix_ipv4 *, struct in_addr); +int ospf_network_unset (struct ospf *, struct prefix_ipv4 *, struct in_addr); +int ospf_area_stub_set (struct ospf *, struct in_addr); +int ospf_area_stub_unset (struct ospf *, struct in_addr); +int ospf_area_no_summary_set (struct ospf *, struct in_addr); +int ospf_area_no_summary_unset (struct ospf *, struct in_addr); +int ospf_area_nssa_set (struct ospf *, struct in_addr); +int ospf_area_nssa_unset (struct ospf *, struct in_addr); +int ospf_area_nssa_translator_role_set (struct ospf *, struct in_addr, int); +int ospf_area_export_list_set (struct ospf_area *, char *); +int ospf_area_export_list_unset (struct ospf_area *); +int ospf_area_import_list_set (struct ospf_area *, char *); +int ospf_area_import_list_unset (struct ospf_area *); +int ospf_area_shortcut_set (struct ospf_area *, int); +int ospf_area_shortcut_unset (struct ospf_area *); +int ospf_timers_spf_set (struct ospf *, u_int32_t, u_int32_t); +int ospf_timers_spf_unset (struct ospf *); +int ospf_timers_refresh_set (struct ospf *, int); +int ospf_timers_refresh_unset (struct ospf *); +int ospf_nbr_nbma_set (struct ospf *, struct in_addr); +int ospf_nbr_nbma_unset (struct ospf *, struct in_addr); +int ospf_nbr_nbma_priority_set (struct ospf *, struct in_addr, u_char); +int ospf_nbr_nbma_priority_unset (struct ospf *, struct in_addr); +int ospf_nbr_nbma_poll_interval_set (struct ospf *, struct in_addr, int); +int ospf_nbr_nbma_poll_interval_unset (struct ospf *, struct in_addr); +void ospf_prefix_list_update (struct prefix_list *); +void ospf_init (); +void ospf_if_update (); +void ospf_ls_upd_queue_empty (struct ospf_interface *); +void ospf_terminate (); +void ospf_nbr_nbma_if_update (struct ospf_interface *); +struct ospf_nbr_nbma *ospf_nbr_nbma_lookup (struct ospf *, struct in_addr); +struct ospf_nbr_nbma *ospf_nbr_nbma_lookup_next (struct in_addr *, int); +int ospf_oi_count (struct interface *); + +struct ospf_area *ospf_area_new (struct in_addr); +struct ospf_area *ospf_area_get (struct in_addr, int); +void ospf_area_check_free (struct in_addr); +struct ospf_area *ospf_area_lookup_by_area_id (struct in_addr); +void ospf_area_add_if (struct ospf_area *, struct ospf_interface *); +void ospf_area_del_if (struct ospf_area *, struct ospf_interface *); + +void ospf_route_map_init (); +void ospf_snmp_init (); + +#endif /* _ZEBRA_OSPFD_H */ -- cgit v1.2.1